[BUGFIX] dbal: Cast field to CHAR for FIND_IN_SET()
[Packages/TYPO3.CMS.git] / typo3 / sysext / dbal / Classes / Database / Specifics / PostgresSpecifics.php
1 <?php
2 namespace TYPO3\CMS\Dbal\Database\Specifics;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\GeneralUtility;
18
19 /**
20 * This class contains the specifics for PostgreSQL DBMS.
21 * Any logic is in AbstractSpecifics.
22 */
23 class PostgresSpecifics extends AbstractSpecifics {
24 /**
25 * Contains the specifics that need to be taken care of for PostgreSQL DBMS.
26 *
27 * @var array
28 */
29 protected $specificProperties = array(
30 self::CAST_FIND_IN_SET => TRUE
31 );
32
33 /**
34 * Contains the DBMS specific mapping overrides for native MySQL to ADOdb meta field types
35 */
36 protected $nativeToMetaFieldTypeOverrides = array(
37 'TINYBLOB' => 'B',
38 'INT' => 'I4',
39 'INTEGER' => 'I4',
40 'TINYINT' => 'I2',
41 'SMALLINT' => 'I2',
42 'MEDIUMINT' => 'I4'
43 );
44
45 /**
46 * Contains the DBMS specific mapping information for ADOdb meta field types to MySQL native field types
47 *
48 * @var array
49 */
50 protected $metaToNativeFieldTypeOverrides = array(
51 'R' => 'INT',
52 'I' => 'INT',
53 'I1' => 'SMALLINT',
54 'I2' => 'SMALLINT',
55 'I4' => 'INT',
56 );
57
58 /**
59 * Determine the native field length information for a table field.
60 *
61 * @param string $mysqlType
62 * @param integer $maxLength
63 * @return string
64 */
65 public function getNativeFieldLength($mysqlType, $maxLength) {
66 if ($maxLength === -1) {
67 return '';
68 }
69 switch ($mysqlType) {
70 case 'DOUBLE':
71 return '';
72 case 'TINYINT':
73 return '(4)';
74 case 'SMALLINT':
75 return '(6)';
76 case 'MEDIUMINT':
77 return '(9)';
78 case 'INT':
79 return '(11)';
80 case 'BIGINT':
81 return '(20)';
82 default:
83 return '(' . $maxLength . ')';
84 }
85 }
86
87 /**
88 * Return the default value of a field formatted to match the native MySQL SQL dialect
89 *
90 * @param array $fieldDefinition
91 * @return mixed
92 */
93 protected function getNativeDefaultValue($fieldDefinition) {
94 if (!$fieldDefinition['has_default']) {
95 $returnValue = NULL;
96 } elseif ($fieldDefinition['type'] === 'SERIAL' && substr($fieldDefinition['default_value'], 0, 7) === 'nextval') {
97 $returnValue = NULL;
98 } elseif ($fieldDefinition['type'] === 'varchar') {
99 // Strip character class and unquote string
100 $returnValue = str_replace("\\'", "'", preg_replace('/\'(.*)\'(::(?:character\svarying|varchar|character|char|text)(?:\(\d+\))?)?\z/', '\\1', $fieldDefinition['default_value']));
101 } elseif (substr($fieldDefinition['type'], 0, 3) === 'int') {
102 $returnValue = (int)preg_replace('/^\(?(\-?\d+)\)?$/', '\\1', $fieldDefinition['default_value']);
103 } else {
104 $returnValue = $fieldDefinition['default_value'];
105 }
106 return $returnValue;
107 }
108
109 /**
110 * Return the MySQL native key type indicator - https://dev.mysql.com/doc/refman/5.5/en/show-columns.html
111 * PRI - the column is a PRIMARY KEY or is one of the columns in a multiple-column PRIMARY KEY
112 * UNI - the column is the first column of a UNIQUE index
113 * MUL - the column is the first column of a nonunique index
114 * If more than one of the values applies return the one with the highest priority, in the order PRI, UNI, MUL
115 * If none applies return empty value.
116 *
117 * @param array $fieldDefinition
118 * @return string
119 */
120 protected function getNativeKeyForField($fieldDefinition) {
121 if (isset($fieldDefinition['primary_key']) && (bool)$fieldDefinition['primary_key']) {
122 $returnValue = 'PRI';
123 } elseif (isset($fieldDefinition['unique']) && (bool)$fieldDefinition['unique']) {
124 $returnValue = 'UNI';
125 } else {
126 $returnValue = '';
127 }
128 return $returnValue;
129 }
130
131 /**
132 * Return the MySQL native extra field information - https://dev.mysql.com/doc/refman/5.5/en/show-columns.html
133 * auto_increment for columns that have the AUTO_INCREMENT attribute
134 * on update CURRENT_TIMESTAMP for TIMESTAMP columns that have the ON UPDATE CURRENT_TIMESTAMP attribute.
135 *
136 * @param array $fieldDefinition
137 * @return string
138 */
139 protected function getNativeExtraFieldAttributes($fieldDefinition) {
140 if ($fieldDefinition['type'] === 'SERIAL' || substr($fieldDefinition['default_value'], 0, 7) === 'nextval') {
141 return 'auto_increment';
142 }
143 return '';
144 }
145
146 /**
147 * Adjust query parts for various DBMS
148 *
149 * @param string $select_fields
150 * @param string $from_table
151 * @param string $where_clause
152 * @param string $groupBy
153 * @param string $orderBy
154 * @param string $limit
155 * @return void
156 */
157 public function transformQueryParts(&$select_fields, &$from_table, &$where_clause, &$groupBy = '', &$orderBy = '', &$limit = '') {
158 // Strip orderBy part if select statement is a count
159 if (preg_match_all('/count\(([^)]*)\)/i', $select_fields, $matches)) {
160 $orderByFields = GeneralUtility::trimExplode(',', $orderBy);
161 $groupByFields = GeneralUtility::trimExplode(',', $groupBy);
162 foreach ($matches[1] as $matchedField) {
163 $field = $matchedField;
164 // Lookup if the field in COUNT() statement is used in GROUP BY statement
165 $index = array_search($field, $groupByFields, TRUE);
166 if ($index !== FALSE) {
167 // field is used in GROUP BY, continue with next field
168 continue;
169 }
170 // If that field isn't used in GROUP BY statement, drop the ordering for compatibility reason
171 $index = array_search($field, $orderByFields, TRUE);
172 if ($index !== FALSE) {
173 unset($orderByFields[$index]);
174 }
175 }
176 $orderBy = implode(', ', $orderByFields);
177 }
178 }
179
180 }