Issues (68)

src/Dialects/MySQL.php (3 issues)

1
<?php
2
/**
3
 * Class MySQL
4
 *
5
 * @filesource   MySQL.php
6
 * @created      11.01.2018
7
 * @package      chillerlan\Database\Dialects
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2018 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\Database\Dialects;
14
15
class MySQL extends DialectAbstract{
16
17
	protected array $quotes = ['`', '`'];
18
	protected string $charset = 'utf8mb4_bin';
19
20
	/** @inheritdoc */
21
	public function insert(string $table, array $fields, string $onConflict = null, string $conflictTarget = null):array{
22
		$onConflict = strtoupper($onConflict);
0 ignored issues
show
It seems like $onConflict can also be of type null; however, parameter $string of strtoupper() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

22
		$onConflict = strtoupper(/** @scrutinizer ignore-type */ $onConflict);
Loading history...
23
24
		switch($onConflict){
25
			case 'IGNORE':
26
				$sql = ['INSERT IGNORE'];
27
				break;
28
			case 'REPLACE':
29
				$sql = ['REPLACE'];
30
				break;
31
			default:
32
				$sql = ['INSERT'];
33
		}
34
35
		$sql[] = 'INTO';
36
		$sql[] = $this->quote($table);
37
		$sql[] = '('.$this->quotes[0].implode($this->quotes[1].', '.$this->quotes[0], $fields).$this->quotes[1].')';
38
		$sql[] = 'VALUES';
39
		$sql[] = '('.implode(',', array_fill(0, count($fields), '?')).')';
40
41
		return $sql;
42
	}
43
44
	/** @inheritdoc */
45
	public function createDatabase(string $dbname, bool $ifNotExists = null, string $collate = null):array {
46
		$collate = $collate ?? $this->charset;
47
48
		$sql[] = 'CREATE DATABASE';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$sql was never initialized. Although not strictly required by PHP, it is generally a good practice to add $sql = array(); before regardless.
Loading history...
49
50
		if($ifNotExists){
51
			$sql[] = 'IF NOT EXISTS';
52
		}
53
54
		$sql[] = $this->quote($dbname);
55
56
		if(!empty($collate)){
57
			[$charset] = explode('_', $collate);
58
59
			$sql[] = 'CHARACTER SET';
60
			$sql[] = $charset;
61
62
			if($collate !== $charset){
63
				$sql[] = 'COLLATE';
64
				$sql[] = $collate;
65
			}
66
67
		}
68
69
		return $sql;
70
	}
71
72
	/** @inheritdoc */
73
	public function createTable(string $table, array $cols, string $primaryKey = null, bool $ifNotExists = null, bool $temp = null, string $dir = null):array {
74
		$sql = ['CREATE'];
75
76
		if($temp){
77
			$sql[] = 'TEMPORARY';
78
		}
79
80
		$sql[] = 'TABLE' ;
81
82
		if($ifNotExists){
83
			$sql[] =  'IF NOT EXISTS' ;
84
		}
85
86
		$sql[] =  $this->quote($table);
87
88
		if(!empty($cols)){
89
			$sql[] = '(';
90
			$sql[] = implode(', ', $cols);
91
92
			if(!empty($primaryKey)){
93
				$sql[] = ', PRIMARY KEY (';
94
				$sql[] = $this->quote($primaryKey);
95
				$sql[] =  ')';
96
			}
97
98
			$sql[] = ')';
99
		}
100
101
		if(!empty($this->charset)){
102
			[$charset] = explode('_', $this->charset);
103
104
			$sql[] = 'CHARACTER SET';
105
			$sql[] = $charset;
106
107
			if($charset !== $this->charset){
108
				$sql[] = 'COLLATE';
109
				$sql[] = $this->charset;
110
			}
111
112
		}
113
114
		return $sql;
115
	}
116
117
	/** @inheritdoc */
118
	public function fieldspec(string $name, string $type, $length = null, string $attribute = null, string $collation = null, bool $isNull = null, string $defaultType = null, $defaultValue = null, string $extra = null):string {
119
		$type = strtoupper(trim($type));
120
		$defaultType = strtoupper($defaultType);
0 ignored issues
show
It seems like $defaultType can also be of type null; however, parameter $string of strtoupper() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

120
		$defaultType = strtoupper(/** @scrutinizer ignore-type */ $defaultType);
Loading history...
121
122
123
		$field = [$this->quote(trim($name))];
124
125
		// @todo: whitelist types?
126
		$nolengthtypes = ['DATE', 'TINYBLOB', 'TINYTEXT', 'BLOB', 'TEXT', 'MEDIUMBLOB',
127
		                  'MEDIUMTEXT', 'LONGBLOB', 'LONGTEXT', 'SERIAL', 'BOOLEAN', 'UUID'];
128
129
		$field[] = (is_int($length) || (is_string($length) && count(explode(',', $length)) === 2)) && !in_array($type, $nolengthtypes, true)
130
			? $type.'('. $length . ')'
131
			: $type;
132
133
		if($attribute){
134
			$field[] = strtoupper($attribute);
135
		}
136
137
		$collationtypes = ['TINYTEXT', 'TEXT', 'MEDIUMTEXT', 'LONGTEXT', 'VARCHAR', 'CHAR', 'ENUM', 'SET'];
138
		if($collation && in_array($type, $collationtypes, true)){
139
			[$charset] = explode('_', $collation);
140
141
			$field[] = 'CHARACTER SET '.$charset;
142
143
			if($charset !== $collation){
144
				$field[] = 'COLLATE '.$collation;
145
			}
146
147
		}
148
149
		if($isNull !== null){
150
			$field[] = $isNull ? 'NULL' : 'NOT NULL';
151
		}
152
153
		if($defaultType === 'USER_DEFINED'){
154
155
			switch(true){
156
				case $type === 'TIMESTAMP' && intval($defaultValue) === 0:
157
					$field[] = 'DEFAULT 0';
158
					break;
159
				case $type === 'BIT':
160
					$field[] = 'DEFAULT b\''.preg_replace('/[^01]/', '0', $defaultValue).'\'';
161
					break;
162
				case $type === 'BOOLEAN':
163
					$field[] = 'DEFAULT '.(preg_match('/^1|T|TRUE|YES$/i', $defaultValue) ? 'TRUE' : 'FALSE');
164
					break;
165
				case $type === 'BINARY' || $type === 'VARBINARY':
166
					$field[] = 'DEFAULT 0x'.$defaultValue;
167
					break;
168
				case strtoupper($defaultValue) === 'NULL' && $isNull === true:
169
					$field[] = 'DEFAULT NULL';
170
					break;
171
				default:
172
					$field[] = 'DEFAULT \''.$defaultValue.'\'';
173
			}
174
175
		}
176
		else if($defaultType === 'CURRENT_TIMESTAMP'){
177
			$field[] = 'DEFAULT CURRENT_TIMESTAMP';
178
		}
179
		else if($defaultType === 'NULL' && $isNull === true){
180
			$field[] = 'DEFAULT NULL';
181
		}
182
183
184
		if($extra){
185
			$field[] = $extra;
186
		}
187
188
		return implode(' ', $field);
189
	}
190
191
	/** @inheritdoc */
192
	public function showDatabases():array{
193
		return ['SHOW DATABASES'];
194
	}
195
196
	/** @inheritdoc */
197
	public function showTables(string $database = null, string $pattern = null, string $where = null):array{
198
		return ['SHOW TABLES'];
199
	}
200
201
	/** @inheritdoc */
202
	public function showCreateTable(string $table):array{
203
		$sql = ['SHOW CREATE TABLE'];
204
		$sql[] = $this->quote($table);
205
206
		return $sql;
207
	}
208
209
}
210