ChangeLog
[Packages/TYPO3.CMS.git] / typo3 / sysext / dbal / class.ux_t3lib_sqlparser.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2004 Kasper Skaarhoj (kasperYYYY@typo3.com)
6 * (c) 2004-2006 Karsten Dambekalns <karsten@typo3.org>
7 * All rights reserved
8 *
9 * This script is part of the TYPO3 project. The TYPO3 project is
10 * free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * The GNU General Public License can be found at
16 * http://www.gnu.org/copyleft/gpl.html.
17 * A copy is found in the textfile GPL.txt and important notices to the license
18 * from the author is found in LICENSE.txt distributed with these scripts.
19 *
20 *
21 * This script is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * This copyright notice MUST APPEAR in all copies of the script!
27 ***************************************************************/
28 /**
29 * PHP SQL engine
30 *
31 * $Id$
32 *
33 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
34 * @author Karsten Dambekalns <k.dambekalns@fishfarm.de>
35 */
36
37
38 /**
39 * PHP SQL engine / server
40 * Some parts are experimental for now.
41 *
42 * @author Kasper Skaarhoj <kasper@typo3.com>
43 * @package TYPO3
44 * @subpackage t3lib
45 */
46 class ux_t3lib_sqlparser extends t3lib_sqlparser {
47
48 /*************************
49 *
50 * Compiling queries
51 *
52 *************************/
53
54 /**
55 * Compiles an SQL query from components
56 *
57 * @param array Array of SQL query components
58 * @return string SQL query
59 * @see parseSQL()
60 */
61 function compileSQL($components) {
62
63 switch($components['type']) {
64 case 'SELECT':
65 $query = $this->compileSELECT($components);
66 break;
67 case 'UPDATE':
68 $query = $this->compileUPDATE($components);
69 break;
70 case 'INSERT':
71 $query = $this->compileINSERT($components);
72 break;
73 case 'DELETE':
74 $query = $this->compileDELETE($components);
75 break;
76 case 'EXPLAIN':
77 $query = 'EXPLAIN '.$this->compileSELECT($components);
78 break;
79 case 'DROPTABLE':
80 $query = $this->compileDROPTABLE($components);
81 break;
82 case 'CREATETABLE':
83 $query = $this->compileCREATETABLE($components);
84 break;
85 case 'ALTERTABLE':
86 $query = $this->compileALTERTABLE($components);
87 break;
88 }
89
90 return $query;
91 }
92
93
94 function compileINSERT($components) {
95 switch((string)$GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
96 case 'native':
97 parent::compileINSERT($components);
98 break;
99 case 'adodb':
100 if(isset($components['VALUES_ONLY']) && is_array($components['VALUES_ONLY'])) {
101 $fields = $GLOBALS['TYPO3_DB']->cache_fieldType[$components['TABLE']];
102 $fc = 0;
103 foreach($fields as $fn => $fd) {
104 $query[$fn] = $components['VALUES_ONLY'][$fc++][0];
105 }
106 } else {
107 // Initialize:
108 foreach($components['FIELDS'] as $fN => $fV) {
109 $query[$fN]=$fV[0];
110 }
111 }
112 break;
113 }
114
115 return $query;
116 }
117
118 function compileDROPTABLE($components) {
119 switch((string)$GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
120 case 'native':
121 $query = 'DROP TABLE'.($components['ifExists']?' IF EXISTS':'').' '.$components['TABLE'];
122 break;
123 case 'adodb':
124 $query = $GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->handler_getFromTableList($components['TABLE'])]->DataDictionary->DropTableSQL('`'.$components['TABLE'].'`');
125 break;
126 }
127
128 return $query;
129 }
130
131 /**
132 * Compiles a CREATE TABLE statement from components array
133 *
134 * @param array Array of SQL query components
135 * @return array array with SQL CREATE TABLE/INDEX command(s)
136 * @see parseCREATETABLE()
137 */
138 function compileCREATETABLE($components) {
139 // Execute query (based on handler derived from the TABLE name which we actually know for once!)
140 switch((string)$GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->handler_getFromTableList($components['TABLE'])]['type']) {
141 case 'native':
142 $query[] = parent::compileCREATETABLE($components);
143 break;
144 case 'adodb':
145 // Create fields and keys:
146 $fieldsKeys = array();
147 $indexKeys = array();
148
149 foreach($components['FIELDS'] as $fN => $fCfg) {
150 // the backticks get converted to the correct quote char automatically
151 $fieldsKeys[$fN] = $GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->handler_getFromTableList($components['TABLE'])]->DataDictionary->nameQuote('`'.$fN.'`').' '.$this->compileFieldCfg($fCfg['definition']);
152 }
153
154 if(isset($components['KEYS']) && is_array($components['KEYS'])) {
155 foreach($components['KEYS'] as $kN => $kCfg) {
156 if ($kN == 'PRIMARYKEY') {
157 foreach($kCfg as $n => $field) {
158 $fieldsKeys[$field] .= ' PRIMARY';
159 }
160 } elseif ($kN == 'UNIQUE') {
161 foreach($kCfg as $n => $field) {
162 $indexKeys = array_merge($indexKeys, $GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->handler_getFromTableList($components['TABLE'])]->DataDictionary->CreateIndexSQL($n, $components['TABLE'], $field, array('UNIQUE')));
163 }
164 } else {
165 $indexKeys = array_merge($indexKeys, $GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->handler_getFromTableList($components['TABLE'])]->DataDictionary->CreateIndexSQL($components['TABLE'].'_'.$kN, $components['TABLE'], $kCfg));
166 }
167 }
168 }
169
170 // Fetch table/index generation query:
171 $query = array_merge($GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->lastHandlerKey]->DataDictionary->CreateTableSQL('`'.$components['TABLE'].'`',implode(','.chr(10), $fieldsKeys)), $indexKeys);
172 break;
173 }
174
175 return $query;
176 }
177
178 function compileALTERTABLE($components) {
179 // Execute query (based on handler derived from the TABLE name which we actually know for once!)
180 switch((string)$GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
181 case 'native':
182 $query[] = parent::compileALTERTABLE($components);
183 break;
184 case 'adodb':
185 switch(strtoupper(str_replace(array(" ","\n","\r","\t"),'',$components['action']))) {
186 case 'ADD':
187 $query = $GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->lastHandlerKey]->DataDictionary->AddColumnSQL('`'.$components['TABLE'].'`','`'.$components['FIELD'].'` '.$this->compileFieldCfg($components['definition']));
188 break;
189 case 'CHANGE':
190 $query = $GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->lastHandlerKey]->DataDictionary->AlterColumnSQL('`'.$components['TABLE'].'`','`'.$components['FIELD'].'` '.$this->compileFieldCfg($components['definition']));
191 break;
192 case 'DROP':
193 case 'DROPKEY':
194 break;
195 case 'ADDKEY':
196 case 'ADDPRIMARYKEY':
197 $query.=' ('.implode(',',$components['fields']).')';
198 break;
199 }
200 break;
201 }
202
203 return $query;
204 }
205
206 /**
207 * Compile field definition
208 *
209 * @param array Field definition parts
210 * @return string Field definition string
211 */
212 function compileFieldCfg($fieldCfg) {
213
214 switch((string)$GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
215 case 'native':
216 $cfg = parent::compileFieldCfg($fieldCfg);
217 break;
218 case 'adodb':
219 // Set type:
220 $cfg = $GLOBALS['TYPO3_DB']->MySQLMetaType($fieldCfg['fieldType']);
221
222 // Add value, if any:
223 if (strlen($fieldCfg['value']) && (in_array($cfg, array('C','C2')))) {
224 $cfg .= ' '.$fieldCfg['value'];
225 } elseif (!isset($fieldCfg['value']) && (in_array($cfg, array('C','C2')))) {
226 $cfg .= ' 255'; // add 255 as length for varchar without specified length (e.g. coming from tinytext, tinyblob)
227 }
228
229 // Add additional features:
230 if (is_array($fieldCfg['featureIndex'])) {
231
232 // MySQL assigns DEFAULT value automatically if NOT NULL, fake this here
233 if(isset($fieldCfg['featureIndex']['NOTNULL']) && !isset($fieldCfg['featureIndex']['DEFAULT']) && !isset($fieldCfg['featureIndex']['AUTO_INCREMENT'])) {
234 $fieldCfg['featureIndex']['DEFAULT'] = array('keyword' => 'DEFAULT', 'value' => array('','\''));
235 }
236
237 foreach($fieldCfg['featureIndex'] as $feature => $featureDef) {
238 switch(true) {
239 // unsigned only for mysql, as it is mysql specific
240 case ($feature == 'UNSIGNED' && !$GLOBALS['TYPO3_DB']->runningNative()) :
241 // auto_increment is removed, it is handled by (emulated) sequences
242 case ($feature == 'AUTO_INCREMENT') :
243 // never add NOT NULL as it is useless in TYPO3 and breaks most databases other than MySQL
244 case ($feature == 'NOTNULL') :
245 continue;
246 }
247
248 $cfg.=' '.$featureDef['keyword'];
249
250 // Add value if found:
251 if (is_array($featureDef['value'])) {
252 if(!is_numeric($featureDef['value'][0]) && empty($featureDef['value'][0])) {
253 $cfg .= ' "\'\'"';
254 } else {
255 $cfg.=' '.$featureDef['value'][1].$this->compileAddslashes($featureDef['value'][0]).$featureDef['value'][1];
256 }
257 }
258 }
259 }
260 $cfg .= ' NOQUOTE';
261 break;
262 }
263
264 // Return field definition string:
265 return $cfg;
266 }
267
268 function checkEmptyDefaultValue($featureIndex) {
269 if (is_array($featureIndex['DEFAULT']['value'])) {
270 if(!is_numeric($featureIndex['DEFAULT']['value'][0]) && empty($featureIndex['DEFAULT']['value'][0])) {
271 return true;
272 } else {
273 return false;
274 }
275 }
276 return true;
277 }
278 }
279
280
281 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_sqlparser.php']) {
282 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_sqlparser.php']);
283 }
284 ?>