This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * @link http://www.yiiframework.com/ |
||
5 | * @copyright Copyright (c) 2008 Yii Software LLC |
||
6 | * @license http://www.yiiframework.com/license/ |
||
7 | */ |
||
8 | |||
9 | namespace edgardmessias\db\ibm\db2; |
||
10 | |||
11 | use yii\base\InvalidParamException; |
||
12 | use yii\db\Constraint; |
||
13 | use yii\db\Expression; |
||
14 | use yii\db\Query; |
||
15 | |||
16 | /** |
||
17 | * QueryBuilder is the query builder for DB2 databases. |
||
18 | * |
||
19 | * @property Connection $db Connetion |
||
20 | * |
||
21 | * @author Edgard Lorraine Messias <[email protected]> |
||
22 | * @author Nikita Verkhovin <[email protected]> |
||
23 | */ |
||
24 | class QueryBuilder extends \yii\db\QueryBuilder |
||
25 | { |
||
26 | public $typeMap = [ |
||
27 | Schema::TYPE_PK => 'integer NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) PRIMARY KEY', |
||
28 | Schema::TYPE_BIGPK => 'bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) PRIMARY KEY', |
||
29 | Schema::TYPE_STRING => 'varchar(255)', |
||
30 | Schema::TYPE_TEXT => 'clob', |
||
31 | Schema::TYPE_SMALLINT => 'smallint', |
||
32 | Schema::TYPE_INTEGER => 'integer', |
||
33 | Schema::TYPE_BIGINT => 'bigint', |
||
34 | Schema::TYPE_FLOAT => 'float', |
||
35 | Schema::TYPE_DOUBLE => 'double', |
||
36 | Schema::TYPE_DECIMAL => 'decimal(10,0)', |
||
37 | Schema::TYPE_DATETIME => 'timestamp', |
||
38 | Schema::TYPE_TIMESTAMP => 'timestamp', |
||
39 | Schema::TYPE_TIME => 'time', |
||
40 | Schema::TYPE_DATE => 'date', |
||
41 | Schema::TYPE_BINARY => 'blob', |
||
42 | Schema::TYPE_BOOLEAN => 'smallint', |
||
43 | Schema::TYPE_MONEY => 'decimal(19,4)', |
||
44 | ]; |
||
45 | |||
46 | 337 | protected function defaultExpressionBuilders() |
|
47 | { |
||
48 | 337 | return array_merge(parent::defaultExpressionBuilders(), [ |
|
49 | 337 | 'yii\db\conditions\InCondition' => 'edgardmessias\db\ibm\db2\conditions\InConditionBuilder', |
|
50 | 337 | 'yii\db\conditions\LikeCondition' => 'edgardmessias\db\ibm\db2\conditions\LikeConditionBuilder', |
|
51 | 337 | ]); |
|
52 | } |
||
53 | |||
54 | /** |
||
55 | * Builds a SQL statement for truncating a DB table. |
||
56 | * @param string $table the table to be truncated. The name will be properly quoted by the method. |
||
57 | * @return string the SQL statement for truncating a DB table. |
||
58 | */ |
||
59 | 1 | public function truncateTable($table) |
|
60 | { |
||
61 | 1 | return 'TRUNCATE TABLE ' . $this->db->quoteTableName($table) . ' IMMEDIATE'; |
|
62 | } |
||
63 | |||
64 | /** |
||
65 | * @inheritdoc |
||
66 | */ |
||
67 | 5 | public function resetSequence($tableName, $value = null) |
|
68 | { |
||
69 | 5 | $table = $this->db->getTableSchema($tableName); |
|
70 | |||
71 | 5 | if ($table !== null && isset($table->columns[$table->sequenceName])) { |
|
72 | 5 | if ($value === null) { |
|
73 | $sql = 'SELECT MAX("'. $table->sequenceName .'") FROM "'. $tableName . '"'; |
||
74 | $value = $this->db->createCommand($sql)->queryScalar() + 1; |
||
75 | } else { |
||
76 | 5 | $value = (int) $value; |
|
77 | } |
||
78 | 5 | return 'ALTER TABLE "' . $tableName . '" ALTER COLUMN "'.$table->sequenceName.'" RESTART WITH ' . $value; |
|
79 | } elseif ($table === null) { |
||
80 | throw new InvalidParamException("Table not found: $tableName"); |
||
81 | } else { |
||
82 | throw new InvalidParamException("There is no sequence associated with table '$tableName'."); |
||
83 | } |
||
84 | } |
||
85 | |||
86 | /** |
||
87 | * Builds a SQL statement for enabling or disabling integrity check. |
||
88 | * @param boolean $check whether to turn on or off the integrity check. |
||
89 | * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. |
||
90 | * @param string $table the table name. Defaults to empty string, meaning that no table will be changed. |
||
91 | * @return string the SQL statement for checking integrity |
||
92 | * @throws \yii\base\NotSupportedException if this is not supported by the underlying DBMS |
||
93 | * @see http://www-01.ibm.com/support/knowledgecenter/SSEPGG_10.5.0/com.ibm.db2.luw.sql.ref.doc/doc/r0000998.html?cp=SSEPGG_10.5.0%2F2-12-7-227 |
||
94 | */ |
||
95 | public function checkIntegrity($check = true, $schema = '', $table = '') |
||
96 | { |
||
97 | if ($table) { |
||
98 | $tableNames = [$table]; |
||
99 | } else { |
||
100 | if (!$schema) { |
||
101 | $schema = $this->db->defaultSchema; |
||
102 | } |
||
103 | |||
104 | //Return only tables |
||
105 | $sql = "SELECT t.tabname FROM syscat.tables AS t" |
||
106 | . " WHERE t.type in ('T') AND t.ownertype != 'S'"; |
||
107 | |||
108 | /** |
||
109 | * Filter by integrity pending |
||
110 | * @see http://www-01.ibm.com/support/knowledgecenter/SSEPGG_9.7.0/com.ibm.db2.luw.sql.ref.doc/doc/r0001063.html |
||
111 | */ |
||
112 | if ($check) { |
||
113 | $sql .= " AND t.status = 'C'"; |
||
114 | } |
||
115 | if ($schema) { |
||
116 | $sql .= ' AND t.tabschema = :schema'; |
||
117 | } |
||
118 | |||
119 | $command = $this->db->createCommand($sql); |
||
120 | if ($schema) { |
||
121 | $command->bindValue(':schema', $schema); |
||
122 | } |
||
123 | |||
124 | $tableNames = $command->queryColumn(); |
||
125 | } |
||
126 | |||
127 | if (empty($tableNames)) { |
||
128 | return ''; |
||
129 | } |
||
130 | |||
131 | $quotedTableNames = []; |
||
132 | foreach ($tableNames as $tableName) { |
||
133 | $quotedTableNames[] = $this->db->quoteTableName($tableName) . ($check? '' : ' ALL'); |
||
134 | } |
||
135 | |||
136 | $enable = $check ? 'CHECKED' : 'UNCHECKED'; |
||
137 | return 'SET INTEGRITY FOR ' . implode(', ', $quotedTableNames) . ' IMMEDIATE ' . $enable. ';'; |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * @inheritdoc |
||
142 | */ |
||
143 | 263 | public function buildOrderByAndLimit($sql, $orderBy, $limit, $offset) |
|
144 | { |
||
145 | 263 | $limitOffsetStatment = $this->buildLimit($limit, $offset); |
|
146 | 263 | if ($limitOffsetStatment != '') { |
|
147 | 25 | $sql = str_replace(':query', $sql, $limitOffsetStatment); |
|
148 | |||
149 | //convert "item"."id" to "id" to use in OVER() |
||
150 | 25 | $newOrderBy = []; |
|
151 | |||
152 | 25 | if(!empty($orderBy)){ |
|
153 | 9 | foreach ($orderBy as $name => $direction) { |
|
154 | 9 | if(is_string($name)){ |
|
155 | 9 | $e = explode('.', $name); |
|
156 | 9 | $name = array_pop($e); |
|
157 | 9 | } |
|
158 | 9 | $newOrderBy[$name] = $direction; |
|
159 | 9 | } |
|
160 | 9 | } |
|
161 | |||
162 | 25 | $orderByStatment = $this->buildOrderBy($newOrderBy); |
|
163 | |||
164 | 25 | $sql = str_replace(':order', $orderByStatment,$sql); |
|
165 | 25 | }else{ |
|
166 | 256 | $orderByStatment = $this->buildOrderBy($orderBy); |
|
167 | 256 | if ($orderByStatment !== '') { |
|
168 | 36 | $sql .= $this->separator . $orderByStatment; |
|
169 | 36 | } |
|
170 | } |
||
171 | 263 | return $sql; |
|
172 | } |
||
173 | |||
174 | /** |
||
175 | * @inheritdoc |
||
176 | */ |
||
177 | 263 | public function buildLimit($limit, $offset) |
|
178 | { |
||
179 | 263 | if (!$this->hasLimit($limit) && !$this->hasOffset($offset)) { |
|
180 | 256 | return ''; |
|
181 | } |
||
182 | |||
183 | 25 | if (!$this->hasOffset($offset)) { |
|
184 | 23 | return ':query :order FETCH FIRST ' . $limit . ' ROWS ONLY'; |
|
185 | } |
||
186 | |||
187 | /** |
||
188 | * @todo Need remote the `RN_` from result to use in "INSERT" query |
||
189 | */ |
||
190 | 3 | $limitOffsetStatment = 'SELECT * FROM (SELECT SUBQUERY_.*, ROW_NUMBER() OVER(:order) AS RN_ FROM ( :query ) AS SUBQUERY_) as t WHERE :offset :limit'; |
|
191 | |||
192 | 3 | $replacement = $this->hasOffset($offset) ? 't.RN_ > ' . $offset : 't.RN_ > 0'; |
|
193 | 3 | $limitOffsetStatment = str_replace(':offset', $replacement, $limitOffsetStatment); |
|
194 | |||
195 | 3 | $replacement = ''; |
|
196 | |||
197 | 3 | if ($this->hasLimit($limit)) { |
|
198 | 2 | if ($limit instanceof \yii\db\ExpressionInterface || $offset instanceof \yii\db\ExpressionInterface) { |
|
199 | 1 | $replacement = 'AND t.RN_ <= (' . $limit . ' + ' . $offset . ')'; |
|
200 | 1 | } else { |
|
201 | 1 | $replacement = 'AND t.RN_ <= ' . ($limit + $offset); |
|
202 | } |
||
203 | 2 | } |
|
204 | 3 | $limitOffsetStatment = str_replace(':limit', $replacement, $limitOffsetStatment); |
|
205 | |||
206 | 3 | return $limitOffsetStatment; |
|
207 | } |
||
208 | |||
209 | /** |
||
210 | * @inheritdoc |
||
211 | */ |
||
212 | 1 | public function alterColumn($table, $column, $type) |
|
213 | { |
||
214 | 1 | return 'ALTER TABLE ' . $this->db->quoteTableName($table) . ' ALTER COLUMN ' |
|
215 | 1 | . $this->db->quoteColumnName($column) . ' SET DATA TYPE ' |
|
216 | 1 | . $this->getColumnType($type); |
|
217 | } |
||
218 | |||
219 | /** |
||
220 | * @inheritdoc |
||
221 | */ |
||
222 | 62 | public function prepareInsertValues($table, $columns, $params = []) |
|
223 | { |
||
224 | 62 | $result = parent::prepareInsertValues($table, $columns, $params); |
|
225 | |||
226 | // Empty placeholders, replace for (DEFAULT, DEFAULT, ...) |
||
227 | 59 | if (empty($result[1]) && $result[2] === ' DEFAULT VALUES') { |
|
228 | 1 | $schema = $this->db->getSchema(); |
|
229 | 1 | if (($tableSchema = $schema->getTableSchema($table)) !== null) { |
|
230 | 1 | $columnSchemas = $tableSchema->columns; |
|
231 | 1 | } else { |
|
232 | $columnSchemas = []; |
||
233 | } |
||
234 | 1 | $result[1] = array_fill(0, count($columnSchemas), 'DEFAULT'); |
|
235 | 1 | } |
|
236 | |||
237 | 59 | return $result; |
|
238 | } |
||
239 | |||
240 | /** |
||
241 | * @inheritdoc |
||
242 | */ |
||
243 | 17 | public function upsert($table, $insertColumns, $updateColumns, &$params) |
|
244 | { |
||
245 | /** @var Constraint[] $constraints */ |
||
246 | 17 | list($uniqueNames, $insertNames, $updateNames) = $this->prepareUpsertColumns($table, $insertColumns, $updateColumns, $constraints); |
|
247 | 17 | if (empty($uniqueNames)) { |
|
248 | 3 | return $this->insert($table, $insertColumns, $params); |
|
249 | } |
||
250 | |||
251 | 14 | $onCondition = ['or']; |
|
252 | 14 | $quotedTableName = $this->db->quoteTableName($table); |
|
253 | 14 | foreach ($constraints as $constraint) { |
|
254 | 14 | $constraintCondition = ['and']; |
|
255 | 14 | foreach ($constraint->columnNames as $name) { |
|
0 ignored issues
–
show
|
|||
256 | 14 | $quotedName = $this->db->quoteColumnName($name); |
|
257 | 14 | $constraintCondition[] = "$quotedTableName.$quotedName=\"EXCLUDED\".$quotedName"; |
|
258 | 14 | } |
|
259 | 14 | $onCondition[] = $constraintCondition; |
|
260 | 14 | } |
|
261 | 14 | $on = $this->buildCondition($onCondition, $params); |
|
262 | 14 | list(, $placeholders, $values, $params) = $this->prepareInsertValues($table, $insertColumns, $params); |
|
263 | 14 | if (!empty($placeholders)) { |
|
264 | 6 | $usingSelectValues = []; |
|
265 | 6 | foreach ($insertNames as $index => $name) { |
|
266 | 6 | $usingSelectValues[$name] = new Expression($placeholders[$index]); |
|
267 | 6 | } |
|
268 | 6 | $usingSubQuery = (new Query()) |
|
269 | 6 | ->select($usingSelectValues) |
|
270 | 6 | ->from('SYSIBM.SYSDUMMY1'); |
|
271 | 6 | list($usingValues, $params) = $this->build($usingSubQuery, $params); |
|
272 | 6 | } |
|
273 | 14 | $mergeSql = 'MERGE INTO ' . $this->db->quoteTableName($table) . ' ' |
|
274 | 14 | . 'USING (' . (isset($usingValues) ? $usingValues : ltrim($values, ' ')) . ') "EXCLUDED" ' |
|
275 | 14 | . "ON ($on)"; |
|
276 | 14 | $insertValues = []; |
|
277 | 14 | foreach ($insertNames as $name) { |
|
278 | 14 | $quotedName = $this->db->quoteColumnName($name); |
|
279 | 14 | if (strrpos($quotedName, '.') === false) { |
|
280 | 14 | $quotedName = '"EXCLUDED".' . $quotedName; |
|
281 | 14 | } |
|
282 | 14 | $insertValues[] = $quotedName; |
|
283 | 14 | } |
|
284 | 14 | $insertSql = 'INSERT (' . implode(', ', $insertNames) . ')' |
|
285 | 14 | . ' VALUES (' . implode(', ', $insertValues) . ')'; |
|
286 | 14 | if ($updateColumns === false) { |
|
287 | 4 | return "$mergeSql WHEN NOT MATCHED THEN $insertSql"; |
|
288 | } |
||
289 | |||
290 | 10 | if ($updateColumns === true) { |
|
291 | 4 | $updateColumns = []; |
|
292 | 4 | foreach ($updateNames as $name) { |
|
293 | 4 | $quotedName = $this->db->quoteColumnName($name); |
|
294 | 4 | if (strrpos($quotedName, '.') === false) { |
|
295 | 4 | $quotedName = '"EXCLUDED".' . $quotedName; |
|
296 | 4 | } |
|
297 | 4 | $updateColumns[$name] = new Expression($quotedName); |
|
298 | 4 | } |
|
299 | 4 | } |
|
300 | 10 | list($updates, $params) = $this->prepareUpdateSets($table, $updateColumns, $params); |
|
301 | 10 | $updateSql = 'UPDATE SET ' . implode(', ', $updates); |
|
302 | 10 | return "$mergeSql WHEN MATCHED THEN $updateSql WHEN NOT MATCHED THEN $insertSql"; |
|
303 | } |
||
304 | |||
305 | /** |
||
306 | * Creates a SELECT EXISTS() SQL statement. |
||
307 | * @param string $rawSql the subquery in a raw form to select from. |
||
308 | * @return string the SELECT EXISTS() SQL statement. |
||
309 | * |
||
310 | * @since 2.0.8 |
||
311 | */ |
||
312 | 21 | public function selectExists($rawSql) |
|
313 | { |
||
314 | 21 | return 'SELECT CASE WHEN COUNT(*)>0 THEN 1 ELSE 0 END FROM (' . $rawSql . ') CHECKEXISTS';; |
|
315 | } |
||
316 | |||
317 | /** |
||
318 | * Builds a SQL command for adding comment to column |
||
319 | * |
||
320 | * @param string $table the table whose column is to be commented. The table name will be properly quoted by the method. |
||
321 | * @param string $column the name of the column to be commented. The column name will be properly quoted by the method. |
||
322 | * @return string the SQL statement for adding comment on column |
||
323 | * @since 2.0.8 |
||
324 | */ |
||
325 | 2 | public function dropCommentFromColumn($table, $column) |
|
326 | { |
||
327 | 2 | return 'COMMENT ON COLUMN ' . $this->db->quoteTableName($table) . '.' . $this->db->quoteColumnName($column) . " IS ''"; |
|
328 | } |
||
329 | |||
330 | /** |
||
331 | * Builds a SQL command for adding comment to table |
||
332 | * |
||
333 | * @param string $table the table whose column is to be commented. The table name will be properly quoted by the method. |
||
334 | * @return string the SQL statement for adding comment on column |
||
335 | * @since 2.0.8 |
||
336 | */ |
||
337 | 1 | public function dropCommentFromTable($table) |
|
338 | { |
||
339 | 1 | return 'COMMENT ON TABLE ' . $this->db->quoteTableName($table) . " IS ''"; |
|
340 | } |
||
341 | |||
342 | /** |
||
343 | * @inheritdoc |
||
344 | */ |
||
345 | 2 | public function dropIndex($name, $table) |
|
346 | { |
||
347 | 2 | return 'DROP INDEX ' . $this->db->quoteTableName($name); |
|
348 | } |
||
349 | |||
350 | /** |
||
351 | * {@inheritdoc} |
||
352 | */ |
||
353 | 2 | public function addDefaultValue($name, $table, $column, $value) |
|
354 | { |
||
355 | 2 | return 'ALTER TABLE ' . $this->db->quoteTableName($table) |
|
356 | 2 | . ' ALTER COLUMN ' . $this->db->quoteColumnName($column) |
|
357 | 2 | . ' SET DEFAULT ' . $this->db->quoteValue($value); |
|
358 | } |
||
359 | |||
360 | /** |
||
361 | * {@inheritdoc} |
||
362 | */ |
||
363 | 2 | public function dropDefaultValue($name, $table) |
|
364 | { |
||
365 | 2 | return 'ALTER TABLE ' . $this->db->quoteTableName($table) |
|
366 | 2 | . ' ALTER COLUMN ' . $this->db->quoteColumnName($name) |
|
367 | 2 | . ' DROP DEFAULT'; |
|
368 | } |
||
369 | } |
||
370 |
There are different options of fixing this problem.
If you want to be on the safe side, you can add an additional type-check:
If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:
Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.