2 namespace TYPO3\CMS\Dbal\Database\SqlCompilers;
18 use TYPO3\CMS\Dbal\Database\Specifics;
36 if (isset($components[
'VALUES_ONLY']) && is_array($components[
'VALUES_ONLY'])) {
37 $valuesComponents = $components[
'EXTENDED'] ===
'1' ? $components[
'VALUES_ONLY'] : array($components[
'VALUES_ONLY']);
38 $tableFields = array_keys($this->databaseConnection->cache_fieldType[$components[
'TABLE']]);
40 $valuesComponents = $components[
'EXTENDED'] ===
'1' ? $components[
'FIELDS'] : array($components[
'FIELDS']);
41 $tableFields = array_keys($valuesComponents[0]);
43 foreach ($valuesComponents as $valuesComponent) {
46 foreach ($valuesComponent as $fV) {
47 $fields[$tableFields[$fc++]] = $fV[0];
51 return count($values) === 1 ? $values[0] : $values;
64 $fieldsKeys = array();
66 foreach ($components[
'FIELDS'] as $fN => $fCfg) {
67 $handlerKey = $this->databaseConnection->handler_getFromTableList($components[
'TABLE']);
68 $fieldsKeys[$fN] = $this->databaseConnection->quoteName($fN, $handlerKey,
true) .
' ' . $this->
compileFieldCfg($fCfg[
'definition']);
70 if (isset($components[
'KEYS']) && is_array($components[
'KEYS'])) {
71 foreach ($components[
'KEYS'] as $kN => $kCfg) {
72 if ($kN ===
'PRIMARYKEY') {
73 foreach ($kCfg as $field) {
74 $fieldsKeys[$field] .=
' PRIMARY';
76 }
elseif ($kN ===
'UNIQUE') {
77 foreach ($kCfg as $n => $field) {
78 $indexKeys = array_merge($indexKeys, $this->
compileCREATEINDEX($n, $components[
'TABLE'], $field, array(
'UNIQUE')));
81 $indexKeys = array_merge($indexKeys, $this->
compileCREATEINDEX($kN, $components[
'TABLE'], $kCfg));
86 $tableOptions = array(
'postgres' =>
'WITHOUT OIDS');
88 $tableName = $this->databaseConnection->quoteName($components[
'TABLE'], null,
true);
89 $query = array_merge($this->databaseConnection->handlerInstance[$this->databaseConnection->lastHandlerKey]->DataDictionary->CreateTableSQL($tableName, implode(
',' . LF, $fieldsKeys), $tableOptions), $indexKeys);
103 $tableName = $this->databaseConnection->quoteName($components[
'TABLE'], null,
true);
104 $fieldName = $this->databaseConnection->quoteName($components[
'FIELD'], null,
true);
105 switch (strtoupper(str_replace(array(
' ',
"\n",
"\r",
"\t"),
'', $components[
'action']))) {
107 $query = $this->databaseConnection->handlerInstance[$this->databaseConnection->lastHandlerKey]->DataDictionary->AddColumnSQL($tableName, $fieldName .
' ' . $this->
compileFieldCfg($components[
'definition']));
110 $query = $this->databaseConnection->handlerInstance[$this->databaseConnection->lastHandlerKey]->DataDictionary->AlterColumnSQL($tableName, $fieldName .
' ' . $this->
compileFieldCfg($components[
'definition']));
119 $query = $this->
compileCREATEINDEX($components[
'KEY'], $components[
'TABLE'], $components[
'fields']);
122 $query = $this->
compileCREATEINDEX($components[
'KEY'], $components[
'TABLE'], $components[
'fields'], array(
'UNIQUE'));
124 case 'ADDPRIMARYKEY':
127 case 'DEFAULTCHARACTERSET':
151 $indexIdentifier = $this->databaseConnection->quoteName(hash(
'crc32b', $tableName) .
'_' . $indexName, null,
true);
152 $dbmsSpecifics = $this->databaseConnection->getSpecifics();
155 foreach ($indexFields as $key => $fieldName) {
156 if (!$keepFieldLengths) {
157 $fieldName = preg_replace(
'/\A([^\(]+)(\(\d+\))/',
'\\1', $fieldName);
160 $indexFields[$key] =
'`' . str_replace(
'`',
'``', $fieldName) .
'`';
163 return $this->databaseConnection->handlerInstance[$this->databaseConnection->handler_getFromTableList($tableName)]->DataDictionary->CreateIndexSQL(
164 $indexIdentifier, $this->databaseConnection->quoteName($tableName, null,
true), $indexFields, $indexOptions
181 $indexIdentifier = $this->databaseConnection->quoteName(hash(
'crc32b', $tableName) .
'_' . $indexName, null,
true);
183 return $this->databaseConnection->handlerInstance[$this->databaseConnection->handler_getFromTableList($tableName)]->DataDictionary->DropIndexSQL(
184 $indexIdentifier, $this->databaseConnection->quoteName($tableName)
198 public function compileFieldList($selectFields, $compileComments =
true, $functionMapping =
true)
202 if (is_array($selectFields)) {
203 $outputParts = array();
204 foreach ($selectFields as $k => $v) {
206 switch ($v[
'type']) {
208 $outputParts[$k] = $v[
'function'] .
'(' . $v[
'func_content'] .
')';
211 if ($v[
'flow-control'][
'type'] ===
'CASE') {
216 $outputParts[$k] = ($v[
'distinct'] ? $v[
'distinct'] :
'') . ($v[
'table'] ? $v[
'table'] .
'.' :
'') . $v[
'field'];
221 $outputParts[$k] .=
' ' . $v[
'as_keyword'] .
' ' . $v[
'as'];
225 $outputParts[$k] .=
' ' . $v[
'sortDir'];
229 if (
false && $selectFields[0][
'comments']) {
230 $output = $selectFields[0][
'comments'] .
' ';
232 $output .= implode(
', ', $outputParts);
259 $type = $this->databaseConnection->getSpecifics()->getMetaFieldType($fieldCfg[
'fieldType']);
262 if ((
string)$fieldCfg[
'value'] !==
'' && in_array($type, array(
'C',
'C2'))) {
263 $cfg .=
' ' . $fieldCfg[
'value'];
264 }
elseif (!isset($fieldCfg[
'value']) && in_array($type, array(
'C',
'C2'))) {
269 if (is_array($fieldCfg[
'featureIndex'])) {
272 if (isset($fieldCfg[
'featureIndex'][
'NOTNULL']) && !isset($fieldCfg[
'featureIndex'][
'DEFAULT']) && !isset($fieldCfg[
'featureIndex'][
'AUTO_INCREMENT'])) {
279 $fieldCfg[
'featureIndex'][
'DEFAULT'] = array(
'keyword' =>
'DEFAULT',
'value' => array(
'0',
''));
282 $fieldCfg[
'featureIndex'][
'DEFAULT'] = array(
'keyword' =>
'DEFAULT',
'value' => array(
'',
'\''));
285 foreach ($fieldCfg[
'featureIndex'] as $feature => $featureDef) {
287 case $feature ===
'UNSIGNED' && !$this->databaseConnection->runningADOdbDriver(
'mysql'):
288 case $feature ===
'NOTNULL' && $this->databaseConnection->runningADOdbDriver(
'oci8'):
290 case $feature ===
'AUTO_INCREMENT':
291 $cfg .=
' AUTOINCREMENT';
293 case $feature ===
'NOTNULL':
297 $cfg .=
' ' . $featureDef[
'keyword'];
300 if (is_array($featureDef[
'value'])) {
301 if ($featureDef[
'value'][0] ===
'') {
304 $cfg .=
' ' . $featureDef[
'value'][1] . $this->
compileAddslashes($featureDef[
'value'][0]) . $featureDef[
'value'][1];
305 if (!is_numeric($featureDef[
'value'][0])) {
340 if (is_array($clauseArray)) {
341 foreach ($clauseArray as $v) {
343 $output .= $v[
'operator'] ?
' ' . $v[
'operator'] :
'';
345 if (is_array($v[
'sub'])) {
347 }
elseif (isset($v[
'func']) && $v[
'func'][
'type'] ===
'EXISTS') {
348 $output .=
' ' . trim($v[
'modifier']) .
' EXISTS (' . $this->
compileSELECT($v[
'func'][
'subquery']) .
')';
350 if (isset($v[
'func']) && $v[
'func'][
'type'] ===
'LOCATE') {
351 $output .=
' ' . trim($v[
'modifier']);
353 case $this->databaseConnection->runningADOdbDriver(
'mssql') && $functionMapping:
354 $output .=
' CHARINDEX(';
355 $output .= $v[
'func'][
'substr'][1] . $v[
'func'][
'substr'][0] . $v[
'func'][
'substr'][1];
356 $output .=
', ' . ($v[
'func'][
'table'] ? $v[
'func'][
'table'] .
'.' :
'') . $v[
'func'][
'field'];
357 $output .= isset($v[
'func'][
'pos']) ?
', ' . $v[
'func'][
'pos'][0] :
'';
360 case $this->databaseConnection->runningADOdbDriver(
'oci8') && $functionMapping:
361 $output .=
' INSTR(';
362 $output .= ($v[
'func'][
'table'] ? $v[
'func'][
'table'] .
'.' :
'') . $v[
'func'][
'field'];
363 $output .=
', ' . $v[
'func'][
'substr'][1] . $v[
'func'][
'substr'][0] . $v[
'func'][
'substr'][1];
364 $output .= isset($v[
'func'][
'pos']) ?
', ' . $v[
'func'][
'pos'][0] :
'';
368 $output .=
' LOCATE(';
369 $output .= $v[
'func'][
'substr'][1] . $v[
'func'][
'substr'][0] . $v[
'func'][
'substr'][1];
370 $output .=
', ' . ($v[
'func'][
'table'] ? $v[
'func'][
'table'] .
'.' :
'') . $v[
'func'][
'field'];
371 $output .= isset($v[
'func'][
'pos']) ?
', ' . $v[
'func'][
'pos'][0] :
'';
374 }
elseif (isset($v[
'func']) && $v[
'func'][
'type'] ===
'IFNULL') {
375 $output .=
' ' . trim($v[
'modifier']) .
' ';
377 case $this->databaseConnection->runningADOdbDriver(
'mssql') && $functionMapping:
380 case $this->databaseConnection->runningADOdbDriver(
'oci8') && $functionMapping:
387 $output .= ($v[
'func'][
'table'] ? $v[
'func'][
'table'] .
'.' :
'') . $v[
'func'][
'field'];
388 $output .=
', ' . $v[
'func'][
'default'][1] . $this->
compileAddslashes($v[
'func'][
'default'][0]) . $v[
'func'][
'default'][1];
390 }
elseif (isset($v[
'func']) && $v[
'func'][
'type'] ===
'FIND_IN_SET') {
391 $output .=
' ' . trim($v[
'modifier']) .
' ';
392 if ($functionMapping) {
394 case $this->databaseConnection->runningADOdbDriver(
'mssql'):
395 $field = ($v[
'func'][
'table'] ? $v[
'func'][
'table'] .
'.' :
'') . $v[
'func'][
'field'];
396 if (!isset($v[
'func'][
'str_like'])) {
397 $v[
'func'][
'str_like'] = $v[
'func'][
'str'][0];
399 $output .=
'\',\
'+' . $field .
'+\',\' LIKE \'%,' . $v[
'func'][
'str_like'] .
',%\'';
401 case $this->databaseConnection->runningADOdbDriver(
'oci8'):
402 $field = ($v[
'func'][
'table'] ? $v[
'func'][
'table'] .
'.' :
'') . $v[
'func'][
'field'];
403 if (!isset($v[
'func'][
'str_like'])) {
404 $v[
'func'][
'str_like'] = $v[
'func'][
'str'][0];
406 $output .=
'\',\
'||' . $field .
'||\',\' LIKE \'%,' . $v[
'func'][
'str_like'] .
',%\'';
408 case $this->databaseConnection->runningADOdbDriver(
'postgres'):
409 $output .=
' FIND_IN_SET(';
410 $output .= $v[
'func'][
'str'][1] . $v[
'func'][
'str'][0] . $v[
'func'][
'str'][1];
411 $output .=
', ' . ($v[
'func'][
'table'] ? $v[
'func'][
'table'] .
'.' :
'') . $v[
'func'][
'field'];
415 $field = ($v[
'func'][
'table'] ? $v[
'func'][
'table'] .
'.' :
'') . $v[
'func'][
'field'];
416 if (!isset($v[
'func'][
'str_like'])) {
417 $v[
'func'][
'str_like'] = $v[
'func'][
'str'][0];
419 $output .=
'(' . $field .
' LIKE \'%,' . $v[
'func'][
'str_like'] .
',%\'' .
' OR ' . $field .
' LIKE \'' . $v[
'func'][
'str_like'] .
',%\'' .
' OR ' . $field .
' LIKE \'%,' . $v[
'func'][
'str_like'] .
'\'' .
' OR ' . $field .
'= ' . $v[
'func'][
'str'][1] . $v[
'func'][
'str'][0] . $v[
'func'][
'str'][1] .
')';
423 case $this->databaseConnection->runningADOdbDriver(
'mssql'):
425 case $this->databaseConnection->runningADOdbDriver(
'oci8'):
427 case $this->databaseConnection->runningADOdbDriver(
'postgres'):
428 $output .=
' FIND_IN_SET(';
429 $output .= $v[
'func'][
'str'][1] . $v[
'func'][
'str'][0] . $v[
'func'][
'str'][1];
430 $output .=
', ' . ($v[
'func'][
'table'] ? $v[
'func'][
'table'] .
'.' :
'') . $v[
'func'][
'field'];
434 $field = ($v[
'func'][
'table'] ? $v[
'func'][
'table'] .
'.' :
'') . $v[
'func'][
'field'];
435 if (!isset($v[
'func'][
'str_like'])) {
436 $v[
'func'][
'str_like'] = $v[
'func'][
'str'][0];
438 $output .=
'(' . $field .
' LIKE \'%,' . $v[
'func'][
'str_like'] .
',%\'' .
' OR ' . $field .
' LIKE \'' . $v[
'func'][
'str_like'] .
',%\'' .
' OR ' . $field .
' LIKE \'%,' . $v[
'func'][
'str_like'] .
'\'' .
' OR ' . $field .
'= ' . $v[
'func'][
'str'][1] . $v[
'func'][
'str'][0] . $v[
'func'][
'str'][1] .
')';
443 $output .=
' ' . trim($v[
'modifier']) .
' ';
445 if ($v[
'calc'] ===
'&' && $functionMapping) {
447 case $this->databaseConnection->runningADOdbDriver(
'oci8'):
449 $output .=
'BITAND(' . trim(($v[
'table'] ? $v[
'table'] .
'.' :
'') . $v[
'field']) .
',' . $v[
'calc_value'][1] . $this->
compileAddslashes($v[
'calc_value'][0]) . $v[
'calc_value'][1] .
')';
453 $output .= trim(($v[
'table'] ? $v[
'table'] .
'.' :
'') . $v[
'field']) . $v[
'calc'] . $v[
'calc_value'][1] . $this->
compileAddslashes($v[
'calc_value'][0]) . $v[
'calc_value'][1];
456 $output .= trim(($v[
'table'] ? $v[
'table'] .
'.' :
'') . $v[
'field']) . $v[
'calc'];
457 if (isset($v[
'calc_table'])) {
458 $output .= trim(($v[
'calc_table'] ? $v[
'calc_table'] .
'.' :
'') . $v[
'calc_field']);
460 $output .= $v[
'calc_value'][1] . $this->
compileAddslashes($v[
'calc_value'][0]) . $v[
'calc_value'][1];
462 }
elseif (!($this->databaseConnection->runningADOdbDriver(
'oci8') && preg_match(
'/(NOT )?LIKE( BINARY)?/', $v[
'comparator']) && $functionMapping)) {
463 $output .= trim(($v[
'table'] ? $v[
'table'] .
'.' :
'') . $v[
'field']);
467 if ($v[
'comparator']) {
468 $isLikeOperator = preg_match(
'/(NOT )?LIKE( BINARY)?/', $v[
'comparator']);
470 case $this->databaseConnection->runningADOdbDriver(
'oci8') && $isLikeOperator && $functionMapping:
472 if (isset($v[
'value'][
'operator'])) {
474 foreach ($v[
'value'][
'args'] as $fieldDef) {
475 $values[] = ($fieldDef[
'table'] ? $fieldDef[
'table'] .
'.' :
'') . $fieldDef[
'field'];
477 $compareValue =
' ' . $v[
'value'][
'operator'] .
'(' . implode(
',', $values) .
')';
479 $compareValue = $v[
'value'][1] . $this->
compileAddslashes(trim($v[
'value'][0],
'%')) . $v[
'value'][1];
488 $tableName = substr($v[
'table'], 1, strlen($v[
'table']) - 2);
489 $fieldName = substr($v[
'field'], 1, strlen($v[
'field']) - 2);
490 $fieldType = $this->databaseConnection->sql_field_metatype($tableName, $fieldName);
491 $isLob = $fieldType ===
'B' || $fieldType ===
'XL';
493 if (strtoupper(substr($v[
'comparator'], -6)) ===
'BINARY') {
495 $output .=
'(dbms_lob.instr(' . trim(($v[
'table'] ? $v[
'table'] .
'.' :
'') . $v[
'field']) .
', ' . $compareValue .
',1,1) > 0)';
497 $output .=
'(instr(' . trim((($v[
'table'] ? $v[
'table'] .
'.' :
'') . $v[
'field'])) .
', ' . $compareValue .
',1,1) > 0)';
501 $output .=
'(dbms_lob.instr(LOWER(' . trim(($v[
'table'] ? $v[
'table'] .
'.' :
'') . $v[
'field']) .
'), ' .
GeneralUtility::strtolower($compareValue) .
',1,1) > 0)';
503 $output .=
'(instr(LOWER(' . trim(($v[
'table'] ? $v[
'table'] .
'.' :
'') . $v[
'field']) .
'), ' .
GeneralUtility::strtolower($compareValue) .
',1,1) > 0)';
508 if ($isLikeOperator && $functionMapping) {
509 if ($this->databaseConnection->runningADOdbDriver(
'postgres') || $this->databaseConnection->runningADOdbDriver(
'postgres64') || $this->databaseConnection->runningADOdbDriver(
'postgres7') || $this->databaseConnection->runningADOdbDriver(
'postgres8')) {
512 switch ($v[
'comparator']) {
514 $v[
'comparator'] =
'ILIKE';
517 $v[
'comparator'] =
'NOT ILIKE';
520 $v[
'comparator'] = str_replace(
' BINARY',
'', $v[
'comparator']);
524 $v[
'comparator'] = str_replace(
' BINARY',
'', $v[
'comparator']);
527 $output .=
' ' . $v[
'comparator'];
531 if (isset($v[
'subquery'])) {
532 $output .=
' (' . $this->
compileSELECT($v[
'subquery']) .
')';
534 $valueBuffer = array();
535 foreach ($v[
'value'] as $realValue) {
536 $valueBuffer[] = $realValue[1] . $this->
compileAddslashes($realValue[0]) . $realValue[1];
539 $dbmsSpecifics = $this->databaseConnection->getSpecifics();
540 if ($dbmsSpecifics === null) {
541 $output .=
' (' . trim(implode(
',', $valueBuffer)) .
')';
543 $chunkedList = $dbmsSpecifics->splitMaxExpressions($valueBuffer);
544 $chunkCount = count($chunkedList);
546 if ($chunkCount === 1) {
547 $output .=
' (' . trim(implode(
',', $valueBuffer)) .
')';
549 $listExpressions = array();
550 $field = trim(($v[
'table'] ? $v[
'table'] .
'.' :
'') . $v[
'field']);
552 switch ($comparator) {
563 for ($i = 0; $i < $chunkCount; ++$i) {
564 $listPart = trim(implode(
',', $chunkedList[$i]));
565 $listExpressions[] =
' (' . $listPart .
')';
568 $implodeString =
' ' . $operator .
' ' . $field .
' ' . $v[
'comparator'];
571 $lastFieldPos = strrpos($output, $field);
572 $output = substr_replace($output,
'(', $lastFieldPos, 0);
573 $output .= implode($implodeString, $listExpressions) .
')';
578 $lbound = $v[
'values'][0];
579 $ubound = $v[
'values'][1];
583 }
elseif (isset($v[
'value'][
'operator'])) {
585 foreach ($v[
'value'][
'args'] as $fieldDef) {
586 $values[] = ($fieldDef[
'table'] ? $fieldDef[
'table'] .
'.' :
'') . $fieldDef[
'field'];
588 $output .=
' ' . $v[
'value'][
'operator'] .
'(' . implode(
',', $values) .
')';
590 $output .=
' ' . $v[
'value'][1] . $this->
compileAddslashes($v[
'value'][0]) . $v[
'value'][1];