PageRenderTime 38ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/typo3/sysext/dbal/class.ux_t3lib_db.php

https://github.com/andreaswolf/typo3-tceforms
PHP | 3891 lines | 2448 code | 380 blank | 1063 comment | 527 complexity | 76ddac9259d9bc49e86e428aa782a7c5 MD5 | raw file
Possible License(s): Apache-2.0, BSD-2-Clause, LGPL-3.0
  1. <?php
  2. /***************************************************************
  3. * Copyright notice
  4. *
  5. * (c) 2004-2009 Kasper Skårhøj (kasperYYYY@typo3.com)
  6. * (c) 2004-2009 Karsten Dambekalns <karsten@typo3.org>
  7. * (c) 2009-2010 Xavier Perseguers <typo3@perseguers.ch>
  8. * All rights reserved
  9. *
  10. * This script is part of the TYPO3 project. The TYPO3 project is
  11. * free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * The GNU General Public License can be found at
  17. * http://www.gnu.org/copyleft/gpl.html.
  18. * A copy is found in the textfile GPL.txt and important notices to the license
  19. * from the author is found in LICENSE.txt distributed with these scripts.
  20. *
  21. *
  22. * This script is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU General Public License for more details.
  26. *
  27. * This copyright notice MUST APPEAR in all copies of the script!
  28. ***************************************************************/
  29. /**
  30. * Contains a database abstraction layer class for TYPO3
  31. *
  32. * $Id: class.ux_t3lib_db.php 42596 2011-01-25 20:02:07Z xperseguers $
  33. *
  34. * @author Kasper Skårhøj <kasper@typo3.com>
  35. * @author Karsten Dambekalns <k.dambekalns@fishfarm.de>
  36. * @author Xavier Perseguers <typo3@perseguers.ch>
  37. */
  38. /**
  39. * [CLASS/FUNCTION INDEX of SCRIPT]
  40. *
  41. *
  42. *
  43. * 161: class ux_t3lib_DB extends t3lib_DB
  44. * 229: public function __construct()
  45. * 260: protected function initInternalVariables()
  46. * 283: public function clearCachedFieldInfo()
  47. * 294: public function cacheFieldInfo()
  48. * 342: protected function analyzeFields($parsedExtSQL)
  49. * 375: protected function mapCachedFieldInfo($fieldInfo)
  50. *
  51. * SECTION: Query Building (Overriding parent methods)
  52. * 438: public function exec_INSERTquery($table, $fields_values, $no_quote_fields = '')
  53. * 575: public function exec_INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE)
  54. * 600: public function exec_UPDATEquery($table,$where,$fields_values,$no_quote_fields = '')
  55. * 692: public function exec_DELETEquery($table, $where)
  56. * 759: public function exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '')
  57. * 856: public function exec_TRUNCATEquery($table)
  58. * 914: protected function exec_query(array $queryParts)
  59. *
  60. * SECTION: Query building
  61. * 978: public function INSERTquery($table, $fields_values, $no_quote_fields = '')
  62. * 1052: public function INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE)
  63. * 1085: public function UPDATEquery($table, $where, $fields_values, $no_quote_fields = '')
  64. * 1170: public function DELETEquery($table, $where)
  65. * 1196: public function SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '')
  66. * 1229: protected function SELECTqueryFromArray(array $params)
  67. * 1267: protected function compileSelectParameters(array $params)
  68. * 1283: public function TRUNCATEquery($table)
  69. *
  70. * SECTION: Prepared Query Support
  71. * 1314: public function prepare_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '', array $input_parameters = array())
  72. * 1416: protected function getQueryComponents($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit)
  73. * 1465: protected function precompileSELECTquery(array $components)
  74. * 1523: public function exec_PREPAREDquery($query, array $precompiledParts)
  75. *
  76. * SECTION: Functions for quoting table/field names
  77. * 1619: protected function quoteSELECTsubquery(array $components)
  78. * 1634: public function quoteSelectFields($select_fields)
  79. * 1644: public function quoteFieldNames($select_fields)
  80. * 1664: protected function _quoteFieldNames(array $select_fields)
  81. * 1701: public function quoteFromTables($from_table)
  82. * 1717: protected function _quoteFromTables(array $from_table)
  83. * 1746: public function quoteWhereClause($where_clause)
  84. * 1767: protected function _quoteWhereClause(array $where_clause)
  85. * 1843: protected function quoteGroupBy($groupBy)
  86. * 1860: protected function _quoteGroupBy(array $groupBy)
  87. * 1877: protected function quoteOrderBy($orderBy)
  88. * 1894: protected function _quoteOrderBy(array $orderBy)
  89. *
  90. * SECTION: Various helper functions
  91. * 1919: public function fullQuoteStr($str, $table)
  92. * 1932: public function quoteStr($str, $table)
  93. * 1965: public function quoteName($name, $handlerKey = NULL, $useBackticks = FALSE)
  94. * 1984: public function MetaType($type, $table, $max_length = -1)
  95. * 2015: public function MySQLMetaType($t)
  96. * 2062: public function MySQLActualType($meta)
  97. *
  98. * SECTION: SQL wrapper functions (Overriding parent methods)
  99. * 2105: public function sql_error()
  100. * 2125: public function sql_errno()
  101. * 2146: public function sql_num_rows(&$res)
  102. * 2170: public function sql_fetch_assoc(&$res)
  103. * 2233: public function sql_fetch_row(&$res)
  104. * 2279: public function sql_free_result(&$res)
  105. * 2308: public function sql_insert_id()
  106. * 2328: public function sql_affected_rows()
  107. * 2350: public function sql_data_seek(&$res, $seek)
  108. * 2375: public function sql_field_metatype($table, $field)
  109. * 2405: public function sql_field_type(&$res,$pointer)
  110. *
  111. * SECTION: Legacy functions, bound to _DEFAULT handler. (Overriding parent methods)
  112. * 2459: public function sql($db,$query)
  113. * 2477: public function sql_query($query)
  114. * 2516: public function sql_pconnect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password)
  115. * 2534: public function sql_select_db($TYPO3_db)
  116. *
  117. * SECTION: SQL admin functions
  118. * 2566: public function admin_get_dbs()
  119. * 2607: public function admin_get_tables()
  120. * 2673: public function admin_get_fields($tableName)
  121. * 2742: public function admin_get_keys($tableName)
  122. * 2847: public function admin_get_charsets()
  123. * 2857: public function admin_query($query)
  124. *
  125. * SECTION: Handler management
  126. * 2941: public function handler_getFromTableList($tableList)
  127. * 2989: public function handler_init($handlerKey)
  128. * 3107: public function isConnected()
  129. * 3127: public function runningNative()
  130. * 3138: public function runningADOdbDriver($driver)
  131. *
  132. * SECTION: Table/Field mapping
  133. * 3165: protected function map_needMapping($tableList, $fieldMappingOnly = FALSE, array &$parsedTableList = array())
  134. * 3215: protected function map_assocArray($input, $tables, $rev = FALSE)
  135. * 3263: protected function map_remapSELECTQueryParts($select_fields, $from_table, $where_clause, $groupBy, $orderBy)
  136. * 3357: protected function getMappingKey($tableName)
  137. * 3371: protected function getFreeMappingKey($tableName)
  138. * 3387: protected function map_sqlParts(&$sqlPartArray, $defaultTable)
  139. * 3549: protected function map_subquery(&$parsedQuery)
  140. * 3589: protected function map_genericQueryParsed(&$parsedQuery)
  141. * 3654: protected function map_fieldNamesInArray($table,&$fieldArray)
  142. *
  143. * SECTION: Debugging
  144. * 3695: public function debugHandler($function,$execTime,$inData)
  145. * 3790: public function debug_WHERE($table, $where, $script = '')
  146. * 3813: public function debug_log($query,$ms,$data,$join,$errorFlag, $script='')
  147. * 3846: public function debug_explain($query)
  148. *
  149. * TOTAL FUNCTIONS: 82
  150. * (This index is automatically created/updated by the extension "extdeveval")
  151. *
  152. */
  153. /**
  154. * TYPO3 database abstraction layer
  155. *
  156. * @author Kasper Skårhøj <kasper@typo3.com>
  157. * @author Karsten Dambekalns <k.dambekalns@fishfarm.de>
  158. * @package TYPO3
  159. * @subpackage tx_dbal
  160. */
  161. class ux_t3lib_DB extends t3lib_DB {
  162. // Internal, static:
  163. var $printErrors = FALSE; // Enable output of SQL errors after query executions. Set through TYPO3_CONF_VARS, see init()
  164. var $debug = FALSE; // Enable debug mode. Set through TYPO3_CONF_VARS, see init()
  165. var $conf = array(); // Configuration array, copied from TYPO3_CONF_VARS in constructor.
  166. var $mapping = array(); // See manual.
  167. var $table2handlerKeys = array(); // See manual.
  168. var $handlerCfg = array( // See manual.
  169. '_DEFAULT' => array(
  170. 'type' => 'native',
  171. 'config' => array(
  172. 'username' => '', // Set by default (overridden)
  173. 'password' => '', // Set by default (overridden)
  174. 'host' => '', // Set by default (overridden)
  175. 'database' => '', // Set by default (overridden)
  176. 'driver' => '', // ONLY "adodb" type; eg. "mysql"
  177. 'sequenceStart' => 1, // ONLY "adodb", first number in sequences/serials/...
  178. 'useNameQuote' => 0 // ONLY "adodb", whether to use NameQuote() method from ADOdb to quote names
  179. )
  180. ),
  181. );
  182. // Internal, dynamic:
  183. var $handlerInstance = array(); // Contains instance of the handler objects as they are created. Exception is the native mySQL calls which are registered as an array with keys "handlerType" = "native" and "link" pointing to the link resource for the connection.
  184. var $lastHandlerKey = ''; // Storage of the handler key of last ( SELECT) query - used for subsequent fetch-row calls etc.
  185. var $lastQuery = ''; // Storage of last SELECT query
  186. var $lastParsedAndMappedQueryArray = array(); // Query array, the last one parsed
  187. var $resourceIdToTableNameMap = array(); // Mapping of resource ids to table names.
  188. // Internal, caching:
  189. var $cache_handlerKeyFromTableList = array(); // Caching handlerKeys for table lists
  190. var $cache_mappingFromTableList = array(); // Caching mapping information for table lists
  191. var $cache_autoIncFields = array(); // parsed SQL from standard DB dump file
  192. var $cache_fieldType = array(); // field types for tables/fields
  193. var $cache_primaryKeys = array(); // primary keys
  194. /**
  195. * SQL parser
  196. *
  197. * @var tx_dbal_sqlengine
  198. */
  199. var $SQLparser;
  200. /**
  201. * Installer
  202. *
  203. * @var t3lib_install
  204. */
  205. var $Installer;
  206. /**
  207. * Cache for queries
  208. *
  209. * @var t3lib_cache_frontend_VariableFrontend
  210. */
  211. protected $queryCache;
  212. /**
  213. * Constructor.
  214. * Creates SQL parser object and imports configuration from $TYPO3_CONF_VARS['EXTCONF']['dbal']
  215. */
  216. public function __construct() {
  217. // Set SQL parser object for internal use:
  218. $this->SQLparser = t3lib_div::makeInstance('tx_dbal_sqlengine');
  219. $this->Installer = t3lib_div::makeInstance('t3lib_install');
  220. if (TYPO3_UseCachingFramework) {
  221. tx_dbal_querycache::initializeCachingFramework();
  222. try {
  223. $this->queryCache = $GLOBALS['typo3CacheManager']->getCache(
  224. 'dbal'
  225. );
  226. } catch (t3lib_cache_exception_NoSuchCache $e) {
  227. tx_dbal_querycache::initDbalCache();
  228. $this->queryCache = $GLOBALS['typo3CacheManager']->getCache(
  229. 'dbal'
  230. );
  231. }
  232. }
  233. // Set internal variables with configuration:
  234. $this->conf = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal'];
  235. $this->initInternalVariables();
  236. }
  237. /**
  238. * Setting internal variables from $this->conf.
  239. *
  240. * @return void
  241. */
  242. protected function initInternalVariables() {
  243. // Set outside configuration:
  244. if (isset($this->conf['mapping'])) {
  245. $this->mapping = $this->conf['mapping'];
  246. }
  247. if (isset($this->conf['table2handlerKeys'])) {
  248. $this->table2handlerKeys = $this->conf['table2handlerKeys'];
  249. }
  250. if (isset($this->conf['handlerCfg'])) {
  251. $this->handlerCfg = $this->conf['handlerCfg'];
  252. }
  253. $this->cacheFieldInfo();
  254. // Debugging settings:
  255. $this->printErrors = $this->conf['debugOptions']['printErrors'] ? TRUE : FALSE;
  256. $this->debug = $this->conf['debugOptions']['enabled'] ? TRUE : FALSE;
  257. }
  258. /**
  259. * Clears the cached field information file.
  260. *
  261. * @return void
  262. */
  263. public function clearCachedFieldInfo() {
  264. if (file_exists(PATH_typo3conf . 'temp_fieldInfo.php')) {
  265. unlink(PATH_typo3conf . 'temp_fieldInfo.php');
  266. }
  267. }
  268. /**
  269. * Caches the field information.
  270. *
  271. * @return void
  272. */
  273. public function cacheFieldInfo() {
  274. $extSQL = '';
  275. $parsedExtSQL = array();
  276. // try to fetch cached file first
  277. // file is removed when admin_query() is called
  278. if (file_exists(PATH_typo3conf . 'temp_fieldInfo.php')) {
  279. $fdata = unserialize(t3lib_div::getUrl(PATH_typo3conf . 'temp_fieldInfo.php'));
  280. $this->cache_autoIncFields = $fdata['incFields'];
  281. $this->cache_fieldType = $fdata['fieldTypes'];
  282. $this->cache_primaryKeys = $fdata['primaryKeys'];
  283. } else {
  284. // handle stddb.sql, parse and analyze
  285. $extSQL = t3lib_div::getUrl(PATH_site . 't3lib/stddb/tables.sql');
  286. $parsedExtSQL = $this->Installer->getFieldDefinitions_fileContent($extSQL);
  287. $this->analyzeFields($parsedExtSQL);
  288. // loop over all installed extensions
  289. foreach ($GLOBALS['TYPO3_LOADED_EXT'] as $ext => $v) {
  290. if (!is_array($v) || !isset($v['ext_tables.sql'])) {
  291. continue;
  292. }
  293. // fetch db dump (if any) and parse it, then analyze
  294. $extSQL = t3lib_div::getUrl($v['ext_tables.sql']);
  295. $parsedExtSQL = $this->Installer->getFieldDefinitions_fileContent($extSQL);
  296. $this->analyzeFields($parsedExtSQL);
  297. }
  298. $cachedFieldInfo = array('incFields' => $this->cache_autoIncFields, 'fieldTypes' => $this->cache_fieldType, 'primaryKeys' => $this->cache_primaryKeys);
  299. $cachedFieldInfo = serialize($this->mapCachedFieldInfo($cachedFieldInfo));
  300. // write serialized content to file
  301. t3lib_div::writeFile(PATH_typo3conf . 'temp_fieldInfo.php', $cachedFieldInfo);
  302. if (strcmp(t3lib_div::getUrl(PATH_typo3conf . 'temp_fieldInfo.php'), $cachedFieldInfo)) {
  303. die('typo3conf/temp_fieldInfo.php was NOT updated properly (written content didn\'t match file content) - maybe write access problem?');
  304. }
  305. }
  306. }
  307. /**
  308. * Analyzes fields and adds the extracted information to the field type, auto increment and primary key info caches.
  309. *
  310. * @param array $parsedExtSQL The output produced by t3lib_install::getFieldDefinitions_fileContent()
  311. * @return void
  312. * @see t3lib_install::getFieldDefinitions_fileContent()
  313. */
  314. protected function analyzeFields($parsedExtSQL) {
  315. foreach ($parsedExtSQL as $table => $tdef) {
  316. if (is_array($tdef['fields'])) {
  317. foreach ($tdef['fields'] as $field => $fdef) {
  318. $fdef = $this->SQLparser->parseFieldDef($fdef);
  319. $this->cache_fieldType[$table][$field]['type'] = $fdef['fieldType'];
  320. $this->cache_fieldType[$table][$field]['metaType'] = $this->MySQLMetaType($fdef['fieldType']);
  321. $this->cache_fieldType[$table][$field]['notnull'] = (isset($fdef['featureIndex']['NOTNULL']) && !$this->SQLparser->checkEmptyDefaultValue($fdef['featureIndex'])) ? 1 : 0;
  322. if (isset($fdef['featureIndex']['DEFAULT'])) {
  323. $default = $fdef['featureIndex']['DEFAULT']['value'][0];
  324. if (isset($fdef['featureIndex']['DEFAULT']['value'][1])) {
  325. $default = $fdef['featureIndex']['DEFAULT']['value'][1] . $default . $fdef['featureIndex']['DEFAULT']['value'][1];
  326. }
  327. $this->cache_fieldType[$table][$field]['default'] = $default;
  328. }
  329. if (isset($fdef['featureIndex']['AUTO_INCREMENT'])) {
  330. $this->cache_autoIncFields[$table] = $field;
  331. }
  332. if (isset($tdef['keys']['PRIMARY'])) {
  333. $this->cache_primaryKeys[$table] = substr($tdef['keys']['PRIMARY'], 13, -1);
  334. }
  335. }
  336. }
  337. }
  338. }
  339. /**
  340. * This function builds all definitions for mapped tables and fields
  341. * @see cacheFieldInfo()
  342. */
  343. protected function mapCachedFieldInfo($fieldInfo) {
  344. if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['mapping'])) {
  345. foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['mapping'] as $mappedTable => $mappedConf) {
  346. if (array_key_exists($mappedTable, $fieldInfo['incFields'])) {
  347. $mappedTableAlias = $mappedConf['mapTableName'];
  348. if (isset($mappedConf['mapFieldNames'][$fieldInfo['incFields'][$mappedTable]])) {
  349. $fieldInfo['incFields'][$mappedTableAlias] = $mappedConf['mapFieldNames'][$fieldInfo['incFields'][$mappedTable]];
  350. } else {
  351. $fieldInfo['incFields'][$mappedTableAlias] = $fieldInfo['incFields'][$mappedTable];
  352. }
  353. }
  354. if (array_key_exists($mappedTable, $fieldInfo['fieldTypes'])) {
  355. foreach ($fieldInfo['fieldTypes'][$mappedTable] as $field => $fieldConf) {
  356. $tempMappedFieldConf[$mappedConf['mapFieldNames'][$field]] = $fieldConf;
  357. }
  358. $fieldInfo['fieldTypes'][$mappedConf['mapTableName']] = $tempMappedFieldConf;
  359. }
  360. if (array_key_exists($mappedTable, $fieldInfo['primaryKeys'])) {
  361. $mappedTableAlias = $mappedConf['mapTableName'];
  362. if (isset($mappedConf['mapFieldNames'][$fieldInfo['primaryKeys'][$mappedTable]])) {
  363. $fieldInfo['primaryKeys'][$mappedTableAlias] = $mappedConf['mapFieldNames'][$fieldInfo['primaryKeys'][$mappedTable]];
  364. } else {
  365. $fieldInfo['primaryKeys'][$mappedTableAlias] = $fieldInfo['primaryKeys'][$mappedTable];
  366. }
  367. }
  368. }
  369. }
  370. return $fieldInfo;
  371. }
  372. /************************************
  373. *
  374. * Query Building (Overriding parent methods)
  375. * These functions are extending counterparts in the parent class.
  376. *
  377. **************************************/
  378. /* From the ADOdb documentation, this is what we do (_Execute for SELECT, _query for the other actions)
  379. Execute() is the default way to run queries. You can use the low-level functions _Execute() and _query() to reduce query overhead.
  380. Both these functions share the same parameters as Execute().
  381. If you do not have any bind parameters or your database supports binding (without emulation), then you can call _Execute() directly.
  382. Calling this function bypasses bind emulation. Debugging is still supported in _Execute().
  383. If you do not require debugging facilities nor emulated binding, and do not require a recordset to be returned, then you can call _query.
  384. This is great for inserts, updates and deletes. Calling this function bypasses emulated binding, debugging, and recordset handling. Either
  385. the resultid, TRUE or FALSE are returned by _query().
  386. */
  387. /**
  388. * Inserts a record for $table from the array with field/value pairs $fields_values.
  389. *
  390. * @param string Table name
  391. * @param array Field values as key=>value pairs. Values will be escaped internally. Typically you would fill an array like "$insertFields" with 'fieldname'=>'value' and pass it to this function as argument.
  392. * @param mixed List/array of keys NOT to quote (eg. SQL functions)
  393. * @return mixed Result from handler, usually TRUE when success and FALSE on failure
  394. */
  395. public function exec_INSERTquery($table, $fields_values, $no_quote_fields = '') {
  396. if ($this->debug) {
  397. $pt = t3lib_div::milliseconds();
  398. }
  399. // Do field mapping if needed:
  400. $ORIG_tableName = $table;
  401. if ($tableArray = $this->map_needMapping($table)) {
  402. // Field mapping of array:
  403. $fields_values = $this->map_assocArray($fields_values, $tableArray);
  404. // Table name:
  405. if ($this->mapping[$table]['mapTableName']) {
  406. $table = $this->mapping[$table]['mapTableName'];
  407. }
  408. }
  409. // Select API:
  410. $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
  411. $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
  412. switch ($hType) {
  413. case 'native':
  414. $this->lastQuery = $this->INSERTquery($table, $fields_values, $no_quote_fields);
  415. if (is_string($this->lastQuery)) {
  416. $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
  417. } else {
  418. $sqlResult = mysql_query($this->lastQuery[0], $this->handlerInstance[$this->lastHandlerKey]['link']);
  419. $new_id = $this->sql_insert_id();
  420. $where = $this->cache_autoIncFields[$table] . '=' . $new_id;
  421. foreach ($this->lastQuery[1] as $field => $content) {
  422. mysql_query('UPDATE ' . $this->quoteFromTables($table) . ' SET ' . $this->quoteFromTables($field) . '=' . $this->fullQuoteStr($content, $table) . ' WHERE ' . $this->quoteWhereClause($where), $this->handlerInstance[$this->lastHandlerKey]['link']);
  423. }
  424. }
  425. break;
  426. case 'adodb':
  427. // auto generate ID for auto_increment fields if not present (static import needs this!)
  428. // should we check the table name here (static_*)?
  429. if (isset($this->cache_autoIncFields[$table])) {
  430. if (isset($fields_values[$this->cache_autoIncFields[$table]])) {
  431. $new_id = $fields_values[$this->cache_autoIncFields[$table]];
  432. if ($table != 'tx_dbal_debuglog') {
  433. $this->handlerInstance[$this->lastHandlerKey]->last_insert_id = $new_id;
  434. }
  435. } else {
  436. $new_id = $this->handlerInstance[$this->lastHandlerKey]->GenID($table . '_' . $this->cache_autoIncFields[$table], $this->handlerInstance[$this->lastHandlerKey]->sequenceStart);
  437. $fields_values[$this->cache_autoIncFields[$table]] = $new_id;
  438. if ($table != 'tx_dbal_debuglog') {
  439. $this->handlerInstance[$this->lastHandlerKey]->last_insert_id = $new_id;
  440. }
  441. }
  442. }
  443. $this->lastQuery = $this->INSERTquery($table, $fields_values, $no_quote_fields);
  444. if (is_string($this->lastQuery)) {
  445. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, FALSE);
  446. } else {
  447. $this->handlerInstance[$this->lastHandlerKey]->StartTrans();
  448. if (strlen($this->lastQuery[0])) {
  449. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery[0], FALSE);
  450. }
  451. if (is_array($this->lastQuery[1])) {
  452. foreach ($this->lastQuery[1] as $field => $content) {
  453. if (empty($content)) continue;
  454. if (isset($this->cache_autoIncFields[$table]) && isset($new_id)) {
  455. $this->handlerInstance[$this->lastHandlerKey]->UpdateBlob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($this->cache_autoIncFields[$table] . '=' . $new_id));
  456. } elseif (isset($this->cache_primaryKeys[$table])) {
  457. $where = '';
  458. $pks = explode(',', $this->cache_primaryKeys[$table]);
  459. foreach ($pks as $pk) {
  460. if (isset($fields_values[$pk]))
  461. $where .= $pk . '=' . $this->fullQuoteStr($fields_values[$pk], $table) . ' AND ';
  462. }
  463. $where = $this->quoteWhereClause($where . '1=1');
  464. $this->handlerInstance[$this->lastHandlerKey]->UpdateBlob($this->quoteFromTables($table), $field, $content, $where);
  465. } else {
  466. $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans(FALSE);
  467. die('Could not update BLOB >>>> no WHERE clause found!'); // should never ever happen
  468. }
  469. }
  470. }
  471. if (is_array($this->lastQuery[2])) {
  472. foreach ($this->lastQuery[2] as $field => $content) {
  473. if (empty($content)) continue;
  474. if (isset($this->cache_autoIncFields[$table]) && isset($new_id)) {
  475. $this->handlerInstance[$this->lastHandlerKey]->UpdateClob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($this->cache_autoIncFields[$table] . '=' . $new_id));
  476. } elseif (isset($this->cache_primaryKeys[$table])) {
  477. $where = '';
  478. $pks = explode(',', $this->cache_primaryKeys[$table]);
  479. foreach ($pks as $pk) {
  480. if (isset($fields_values[$pk]))
  481. $where .= $pk . '=' . $this->fullQuoteStr($fields_values[$pk], $table) . ' AND ';
  482. }
  483. $where = $this->quoteWhereClause($where . '1=1');
  484. $this->handlerInstance[$this->lastHandlerKey]->UpdateClob($this->quoteFromTables($table), $field, $content, $where);
  485. } else {
  486. $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans(FALSE);
  487. die('Could not update CLOB >>>> no WHERE clause found!'); // should never ever happen
  488. }
  489. }
  490. }
  491. $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans();
  492. }
  493. break;
  494. case 'userdefined':
  495. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_INSERTquery($table, $fields_values, $no_quote_fields);
  496. break;
  497. }
  498. if ($this->printErrors && $this->sql_error()) {
  499. debug(array($this->lastQuery, $this->sql_error()));
  500. }
  501. if ($this->debug) {
  502. $this->debugHandler(
  503. 'exec_INSERTquery',
  504. t3lib_div::milliseconds() - $pt,
  505. array(
  506. 'handlerType' => $hType,
  507. 'args' => array($table, $fields_values),
  508. 'ORIG_tablename' => $ORIG_tableName
  509. )
  510. );
  511. }
  512. // Return output:
  513. return $sqlResult;
  514. }
  515. /**
  516. * Creates and executes an INSERT SQL-statement for $table with multiple rows.
  517. * This method uses exec_INSERTquery() and is just a syntax wrapper to it.
  518. *
  519. * @param string Table name
  520. * @param array Field names
  521. * @param array Table rows. Each row should be an array with field values mapping to $fields
  522. * @param string/array See fullQuoteArray()
  523. * @return mixed Result from last handler, usually TRUE when success and FALSE on failure
  524. */
  525. public function exec_INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE) {
  526. if ((string) $this->handlerCfg[$this->lastHandlerKey]['type'] === 'native') {
  527. return parent::exec_INSERTmultipleRows($table, $fields, $rows, $no_quote_fields);
  528. }
  529. foreach ($rows as $row) {
  530. $fields_values = array();
  531. foreach ($fields as $key => $value) {
  532. $fields_values[$value] = $row[$key];
  533. }
  534. $res = $this->exec_INSERTquery($table, $fields_values, $no_quote_fields);
  535. }
  536. return $res;
  537. }
  538. /**
  539. * Updates a record from $table
  540. *
  541. * @param string Database tablename
  542. * @param string WHERE clause, eg. "uid=1". NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
  543. * @param array Field values as key=>value pairs. Values will be escaped internally. Typically you would fill an array like "$updateFields" with 'fieldname'=>'value' and pass it to this function as argument.
  544. * @param mixed List/array of keys NOT to quote (eg. SQL functions)
  545. * @return mixed Result from handler, usually TRUE when success and FALSE on failure
  546. */
  547. public function exec_UPDATEquery($table, $where, $fields_values, $no_quote_fields = '') {
  548. if ($this->debug) {
  549. $pt = t3lib_div::milliseconds();
  550. }
  551. // Do table/field mapping:
  552. $ORIG_tableName = $table;
  553. if ($tableArray = $this->map_needMapping($table)) {
  554. // Field mapping of array:
  555. $fields_values = $this->map_assocArray($fields_values, $tableArray);
  556. // Where clause table and field mapping:
  557. $whereParts = $this->SQLparser->parseWhereClause($where);
  558. $this->map_sqlParts($whereParts, $tableArray[0]['table']);
  559. $where = $this->SQLparser->compileWhereClause($whereParts, FALSE);
  560. // Table name:
  561. if ($this->mapping[$table]['mapTableName']) {
  562. $table = $this->mapping[$table]['mapTableName'];
  563. }
  564. }
  565. // Select API
  566. $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
  567. $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
  568. switch ($hType) {
  569. case 'native':
  570. $this->lastQuery = $this->UPDATEquery($table, $where, $fields_values, $no_quote_fields);
  571. if (is_string($this->lastQuery)) {
  572. $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
  573. }
  574. else {
  575. $sqlResult = mysql_query($this->lastQuery[0], $this->handlerInstance[$this->lastHandlerKey]['link']);
  576. foreach ($this->lastQuery[1] as $field => $content) {
  577. mysql_query('UPDATE ' . $this->quoteFromTables($table) . ' SET ' . $this->quoteFromTables($field) . '=' . $this->fullQuoteStr($content, $table) . ' WHERE ' . $this->quoteWhereClause($where), $this->handlerInstance[$this->lastHandlerKey]['link']);
  578. }
  579. }
  580. break;
  581. case 'adodb':
  582. $this->lastQuery = $this->UPDATEquery($table, $where, $fields_values, $no_quote_fields);
  583. if (is_string($this->lastQuery)) {
  584. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, FALSE);
  585. } else {
  586. $this->handlerInstance[$this->lastHandlerKey]->StartTrans();
  587. if (strlen($this->lastQuery[0])) {
  588. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery[0], FALSE);
  589. }
  590. if (is_array($this->lastQuery[1])) {
  591. foreach ($this->lastQuery[1] as $field => $content) {
  592. $this->handlerInstance[$this->lastHandlerKey]->UpdateBlob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($where));
  593. }
  594. }
  595. if (is_array($this->lastQuery[2])) {
  596. foreach ($this->lastQuery[2] as $field => $content) {
  597. $this->handlerInstance[$this->lastHandlerKey]->UpdateClob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($where));
  598. }
  599. }
  600. $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans();
  601. }
  602. break;
  603. case 'userdefined':
  604. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_UPDATEquery($table, $where, $fields_values, $no_quote_fields);
  605. break;
  606. }
  607. if ($this->printErrors && $this->sql_error()) {
  608. debug(array($this->lastQuery, $this->sql_error()));
  609. }
  610. if ($this->debug) {
  611. $this->debugHandler(
  612. 'exec_UPDATEquery',
  613. t3lib_div::milliseconds() - $pt,
  614. array(
  615. 'handlerType' => $hType,
  616. 'args' => array($table, $where, $fields_values),
  617. 'ORIG_from_table' => $ORIG_tableName
  618. )
  619. );
  620. }
  621. // Return result:
  622. return $sqlResult;
  623. }
  624. /**
  625. * Deletes records from table
  626. *
  627. * @param string Database tablename
  628. * @param string WHERE clause, eg. "uid=1". NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
  629. * @return mixed Result from handler
  630. */
  631. public function exec_DELETEquery($table, $where) {
  632. if ($this->debug) {
  633. $pt = t3lib_div::milliseconds();
  634. }
  635. // Do table/field mapping:
  636. $ORIG_tableName = $table;
  637. if ($tableArray = $this->map_needMapping($table)) {
  638. // Where clause:
  639. $whereParts = $this->SQLparser->parseWhereClause($where);
  640. $this->map_sqlParts($whereParts, $tableArray[0]['table']);
  641. $where = $this->SQLparser->compileWhereClause($whereParts, FALSE);
  642. // Table name:
  643. if ($this->mapping[$table]['mapTableName']) {
  644. $table = $this->mapping[$table]['mapTableName'];
  645. }
  646. }
  647. // Select API
  648. $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
  649. $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
  650. switch ($hType) {
  651. case 'native':
  652. $this->lastQuery = $this->DELETEquery($table, $where);
  653. $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
  654. break;
  655. case 'adodb':
  656. $this->lastQuery = $this->DELETEquery($table, $where);
  657. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, FALSE);
  658. break;
  659. case 'userdefined':
  660. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_DELETEquery($table, $where);
  661. break;
  662. }
  663. if ($this->printErrors && $this->sql_error()) {
  664. debug(array($this->lastQuery, $this->sql_error()));
  665. }
  666. if ($this->debug) {
  667. $this->debugHandler(
  668. 'exec_DELETEquery',
  669. t3lib_div::milliseconds() - $pt,
  670. array(
  671. 'handlerType' => $hType,
  672. 'args' => array($table, $where),
  673. 'ORIG_from_table' => $ORIG_tableName
  674. )
  675. );
  676. }
  677. // Return result:
  678. return $sqlResult;
  679. }
  680. /**
  681. * Selects records from Data Source
  682. *
  683. * @param string $select_fields List of fields to select from the table. This is what comes right after "SELECT ...". Required value.
  684. * @param string $from_table Table(s) from which to select. This is what comes right after "FROM ...". Required value.
  685. * @param string $where_clause Optional additional WHERE clauses put in the end of the query. NOTICE: You must escape values in this argument with $this->fullQquoteStr() yourself! DO NOT PUT IN GROUP BY, ORDER BY or LIMIT!
  686. * @param string $groupBy Optional GROUP BY field(s), if none, supply blank string.
  687. * @param string $orderBy Optional ORDER BY field(s), if none, supply blank string.
  688. * @param string $limit Optional LIMIT value ([begin,]max), if none, supply blank string.
  689. * @return mixed Result from handler. Typically object from DBAL layers.
  690. */
  691. public function exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '') {
  692. if ($this->debug) {
  693. $pt = t3lib_div::milliseconds();
  694. }
  695. // Map table / field names if needed:
  696. $ORIG_tableName = $from_table; // Saving table names in $ORIG_from_table since $from_table is transformed beneath:
  697. $parsedFromTable = array();
  698. $remappedParameters = array();
  699. if ($tableArray = $this->map_needMapping($ORIG_tableName, FALSE, $parsedFromTable)) {
  700. $from = $parsedFromTable ? $parsedFromTable : $from_table;
  701. $remappedParameters = $this->map_remapSELECTQueryParts($select_fields, $from, $where_clause, $groupBy, $orderBy);
  702. }
  703. // Get handler key and select API:
  704. $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
  705. $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
  706. switch ($hType) {
  707. case 'native':
  708. if (count($remappedParameters) > 0) {
  709. list($select_fields, $from_table, $where_clause, $groupBy, $orderBy) = $this->compileSelectParameters($remappedParameters);
  710. }
  711. $this->lastQuery = $this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
  712. $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
  713. $this->resourceIdToTableNameMap[(string) $sqlResult] = $ORIG_tableName;
  714. break;
  715. case 'adodb':
  716. if ($limit != '') {
  717. $splitLimit = t3lib_div::intExplode(',', $limit); // Splitting the limit values:
  718. if ($splitLimit[1]) { // If there are two parameters, do mapping differently than otherwise:
  719. $numrows = $splitLimit[1];
  720. $offset = $splitLimit[0];
  721. } else {
  722. $numrows = $splitLimit[0];
  723. $offset = 0;
  724. }
  725. if (count($remappedParameters) > 0) {
  726. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit($this->SELECTqueryFromArray($remappedParameters), $numrows, $offset);
  727. } else {
  728. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit($this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy), $numrows, $offset);
  729. }
  730. $this->lastQuery = $sqlResult->sql;
  731. } else {
  732. if (count($remappedParameters) > 0) {
  733. $this->lastQuery = $this->SELECTqueryFromArray($remappedParameters);
  734. } else {
  735. $this->lastQuery = $this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy);
  736. }
  737. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_Execute($this->lastQuery);
  738. }
  739. $sqlResult->TYPO3_DBAL_handlerType = 'adodb'; // Setting handler type in result object (for later recognition!)
  740. $sqlResult->TYPO3_DBAL_tableList = $ORIG_tableName;
  741. break;
  742. case 'userdefined':
  743. if (count($remappedParameters) > 0) {
  744. list($select_fields, $from_table, $where_clause, $groupBy, $orderBy) = $this->compileSelectParameters($remappedParameters);
  745. }
  746. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
  747. if (is_object($sqlResult)) {
  748. $sqlResult->TYPO3_DBAL_handlerType = 'userdefined'; // Setting handler type in result object (for later recognition!)
  749. $sqlResult->TYPO3_DBAL_tableList = $ORIG_tableName;
  750. }
  751. break;
  752. }
  753. if ($this->printErrors && $this->sql_error()) {
  754. debug(array($this->lastQuery, $this->sql_error()));
  755. }
  756. if ($this->debug) {
  757. $data = array(
  758. 'handlerType' => $hType,
  759. 'args' => array($from_table, $select_fields, $where_clause, $groupBy, $orderBy, $limit),
  760. 'ORIG_from_table' => $ORIG_tableName,
  761. );
  762. if ($this->conf['debugOptions']['numberRows']) {
  763. $data['numberRows'] = $this->sql_num_rows($sqlResult);
  764. }
  765. $this->debugHandler(
  766. 'exec_SELECTquery',
  767. t3lib_div::milliseconds() - $pt,
  768. $data
  769. );
  770. }
  771. // Return result handler.
  772. return $sqlResult;
  773. }
  774. /**
  775. * Truncates a table.
  776. *
  777. * @param string Database tablename
  778. * @return mixed Result from handler
  779. */
  780. public function exec_TRUNCATEquery($table) {
  781. if ($this->debug) {
  782. $pt = t3lib_div::milliseconds();
  783. }
  784. // Do table/field mapping:
  785. $ORIG_tableName = $table;
  786. if ($tableArray = $this->map_needMapping($table)) {
  787. // Table name:
  788. if ($this->mapping[$table]['mapTableName']) {
  789. $table = $this->mapping[$table]['mapTableName'];
  790. }
  791. }
  792. // Select API
  793. $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
  794. $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
  795. switch ($hType) {
  796. case 'native':
  797. $this->lastQuery = $this->TRUNCATEquery($table);
  798. $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
  799. break;
  800. case 'adodb':
  801. $this->lastQuery = $this->TRUNCATEquery($table);
  802. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, FALSE);
  803. break;
  804. case 'userdefined':
  805. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_TRUNCATEquery($table);
  806. break;
  807. }
  808. if ($this->printErrors && $this->sql_error()) {
  809. debug(array($this->lastQuery, $this->sql_error()));
  810. }
  811. if ($this->debug) {
  812. $this->debugHandler(
  813. 'exec_TRUNCATEquery',
  814. t3lib_div::milliseconds() - $pt,
  815. array(
  816. 'handlerType' => $hType,
  817. 'args' => array($table),
  818. 'ORIG_from_table' => $ORIG_tableName
  819. )
  820. );
  821. }
  822. // Return result:
  823. return $sqlResult;
  824. }
  825. /**
  826. * Executes a query.
  827. * EXPERIMENTAL since TYPO3 4.4.
  828. *
  829. * @param array $queryParts SQL parsed by method parseSQL() of t3lib_sqlparser
  830. * @return pointer Result pointer / DBAL object
  831. * @see ux_t3lib_db::sql_query()
  832. */
  833. protected function exec_query(array $queryParts) {
  834. switch ($queryParts['type']) {
  835. case 'SELECT':
  836. $selectFields = $this->SQLparser->compileFieldList($queryParts['SELECT']);
  837. $fromTables = $this->SQLparser->compileFromTables($queryParts['FROM']);
  838. $whereClause = isset($queryParts['WHERE']) ? $this->SQLparser->compileWhereClause($queryParts['WHERE']) : '1=1';
  839. $groupBy = isset($queryParts['GROUPBY']) ? $this->SQLparser->compileFieldList($queryParts['GROUPBY']) : '';
  840. $orderBy = isset($queryParts['ORDERBY']) ? $this->SQLparser->compileFieldList($queryParts['ORDERBY']) : '';
  841. $limit = isset($queryParts['LIMIT']) ? $this->SQLparser->compileWhereClause($queryParts['LIMIT']) : '';
  842. return $this->exec_SELECTquery($selectFields, $fromTables, $whereClause, $groupBy, $orderBy, $limit);
  843. case 'UPDATE':
  844. $table = $queryParts['TABLE'];
  845. $fields = array();
  846. foreach ($queryParts['FIELDS'] as $fN => $fV) {
  847. $fields[$fN] = $fV[0];
  848. }
  849. $whereClause = isset($queryParts['WHERE']) ? $this->SQLparser->compileWhereClause($queryParts['WHERE']) : '1=1';
  850. return $this->exec_UPDATEquery($table, $whereClause, $fields);
  851. case 'INSERT':
  852. $table = $queryParts['TABLE'];
  853. $values = array();
  854. if (isset($queryParts['VALUES_ONLY']) && is_array($queryParts['VALUES_ONLY'])) {
  855. $fields = $GLOBALS['TYPO3_DB']->cache_fieldType[$table];
  856. $fc = 0;
  857. foreach ($fields as $fn => $fd) {
  858. $values[$fn] = $queryParts['VALUES_ONLY'][$fc++][0];
  859. }
  860. } else {
  861. foreach ($queryParts['FIELDS'] as $fN => $fV) {
  862. $values[$fN] = $fV[0];
  863. }
  864. }
  865. return $this->exec_INSERTquery($table, $values);
  866. case 'DELETE':
  867. $table = $queryParts['TABLE'];
  868. $whereClause = isset($queryParts['WHERE']) ? $this->SQLparser->compileWhereClause($queryParts['WHERE']) : '1=1';
  869. return $this->exec_DELETEquery($table, $whereClause);
  870. case 'TRUNCATETABLE':
  871. $table = $queryParts['TABLE'];
  872. return $this->exec_TRUNCATEquery($table);
  873. }
  874. }
  875. /**************************************
  876. *
  877. * Query building
  878. *
  879. **************************************/
  880. /**
  881. * Creates an INSERT SQL-statement for $table from the array with field/value pairs $fields_values.
  882. * Usage count/core: 4
  883. *
  884. * @param string See exec_INSERTquery()
  885. * @param array See exec_INSERTquery()
  886. * @param mixed See exec_INSERTquery()
  887. * @return mixed Full SQL query for INSERT as string or array (unless $fields_values does not contain any elements in which case it will be FALSE). If BLOB fields will be affected and one is not running the native type, an array will be returned, where 0 => plain SQL, 1 => fieldname/value pairs of BLOB fields
  888. */
  889. public function INSERTquery($table, $fields_values, $no_quote_fields = '') {
  890. // Table and fieldnames should be "SQL-injection-safe" when supplied to this function (contrary to values in the arrays which may be insecure).
  891. if (is_array($fields_values) && count($fields_values)) {
  892. if (is_string($no_quote_fields)) {
  893. $no_quote_fields = explode(',', $no_quote_fields);
  894. } elseif (!is_array($no_quote_fields)) {
  895. $no_quote_fields = array();
  896. }
  897. $blobfields = array();
  898. $nArr = array();
  899. foreach ($fields_values as $k => $v) {
  900. if (!$this->runningNative() && $this->sql_field_metatype($table, $k) == 'B') {
  901. // we skip the field in the regular INSERT statement, it is only in blobfields
  902. $blobfields[$this->quoteFieldNames($k)] = $v;
  903. } elseif (!$this->runningNative() && $this->sql_field_metatype($table, $k) == 'XL') {
  904. // we skip the field in the regular INSERT statement, it is only in clobfields
  905. $clobfields[$this->quoteFieldNames($k)] = $v;
  906. } else {
  907. // Add slashes old-school:
  908. // cast numerical values
  909. $mt = $this->sql_field_metatype($table, $k);
  910. if ($mt{0} == 'I') {
  911. $v = (int) $v;
  912. } else if ($mt{0} == 'F') {
  913. $v = (double) $v;
  914. }
  915. $nArr[$this->quoteFieldNames($k)] = (!in_array($k, $no_quote_fields)) ? $this->fullQuoteStr($v, $table) : $v;
  916. }
  917. }
  918. if (count($blobfields) || count($clobfields)) {
  919. if (count($nArr)) {
  920. $query[0] = 'INSERT INTO ' . $this->quoteFromTables($table) . '
  921. (
  922. ' . implode(',
  923. ', array_keys($nArr)) . '
  924. ) VALUES (
  925. ' . implode(',
  926. ', $nArr) . '
  927. )';
  928. }
  929. if (count($blobfields)) $query[1] = $blobfields;
  930. if (count($clobfields)) $query[2] = $clobfields;
  931. if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query[0];
  932. } else {
  933. $query = 'INSERT INTO ' . $this->quoteFromTables($table) . '
  934. (
  935. ' . implode(',
  936. ', array_keys($nArr)) . '
  937. ) VALUES (
  938. ' . implode(',
  939. ', $nArr) . '
  940. )';
  941. if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query;
  942. }
  943. return $query;
  944. }
  945. }
  946. /**
  947. * Creates an INSERT SQL-statement for $table with multiple rows.
  948. * This method will create multiple INSERT queries concatenated with ';'
  949. *
  950. * @param string Table name
  951. * @param array Field names
  952. * @param array Table rows. Each row should be an array with field values mapping to $fields
  953. * @param string/array See fullQuoteArray()
  954. * @return array Full SQL query for INSERT as array of strings (unless $fields_values does not contain any elements in which case it will be FALSE). If BLOB fields will be affected and one is not running the native type, an array will be returned for each row, where 0 => plain SQL, 1 => fieldname/value pairs of BLOB fields.
  955. */
  956. public function INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE) {
  957. if ((string) $this->handlerCfg[$this->lastHandlerKey]['type'] === 'native') {
  958. return parent::INSERTmultipleRows($table, $fields, $rows, $no_quote_fields);
  959. }
  960. $result = array();
  961. foreach ($rows as $row) {
  962. $fields_values = array();
  963. foreach ($fields as $key => $value) {
  964. $fields_values[$value] = $row[$key];
  965. }
  966. $rowQuery = $this->INSERTquery($table, $fields_values, $no_quote_fields);
  967. if (is_array($rowQuery)) {
  968. $result[] = $rowQuery;
  969. } else {
  970. $result[][0] = $rowQuery;
  971. }
  972. }
  973. return $result;
  974. }
  975. /**
  976. * Creates an UPDATE SQL-statement for $table where $where-clause (typ. 'uid=...') from the array with field/value pairs $fields_values.
  977. * Usage count/core: 6
  978. *
  979. * @param string See exec_UPDATEquery()
  980. * @param string See exec_UPDATEquery()
  981. * @param array See exec_UPDATEquery()
  982. * @param mixed See exec_UPDATEquery()
  983. * @return mixed Full SQL query for UPDATE as string or array (unless $fields_values does not contain any elements in which case it will be FALSE). If BLOB fields will be affected and one is not running the native type, an array will be returned, where 0 => plain SQL, 1 => fieldname/value pairs of BLOB fields
  984. */
  985. public function UPDATEquery($table, $where, $fields_values, $no_quote_fields = '') {
  986. // Table and fieldnames should be "SQL-injection-safe" when supplied to this function (contrary to values in the arrays which may be insecure).
  987. if (is_string($where)) {
  988. $fields = array();
  989. $blobfields = array();
  990. $clobfields = array();
  991. if (is_array($fields_values) && count($fields_values)) {
  992. if (is_string($no_quote_fields)) {
  993. $no_quote_fields = explode(',', $no_quote_fields);
  994. } elseif (!is_array($no_quote_fields)) {
  995. $no_quote_fields = array();
  996. }
  997. $nArr = array();
  998. foreach ($fields_values as $k => $v) {
  999. if (!$this->runningNative() && $this->sql_field_metatype($table, $k) == 'B') {
  1000. // we skip the field in the regular UPDATE statement, it is only in blobfields
  1001. $blobfields[$this->quoteFieldNames($k)] = $v;
  1002. } elseif (!$this->runningNative() && $this->sql_field_metatype($table, $k) == 'XL') {
  1003. // we skip the field in the regular UPDATE statement, it is only in clobfields
  1004. $clobfields[$this->quoteFieldNames($k)] = $v;
  1005. } else {
  1006. // Add slashes old-school:
  1007. // cast numeric values
  1008. $mt = $this->sql_field_metatype($table, $k);
  1009. if ($mt{0} == 'I') {
  1010. $v = (int) $v;
  1011. } else if ($mt{0} == 'F') {
  1012. $v = (double) $v;
  1013. }
  1014. $nArr[] = $this->quoteFieldNames($k) . '=' . ((!in_array($k, $no_quote_fields)) ? $this->fullQuoteStr($v, $table) : $v);
  1015. }
  1016. }
  1017. }
  1018. if (count($blobfields) || count($clobfields)) {
  1019. if (count($nArr)) {
  1020. $query[0] = 'UPDATE ' . $this->quoteFromTables($table) . '
  1021. SET
  1022. ' . implode(',
  1023. ', $nArr) .
  1024. (strlen($where) > 0 ? '
  1025. WHERE
  1026. ' . $this->quoteWhereClause($where) : '');
  1027. }
  1028. if (count($blobfields)) {
  1029. $query[1] = $blobfields;
  1030. }
  1031. if (count($clobfields)) {
  1032. $query[2] = $clobfields;
  1033. }
  1034. if ($this->debugOutput || $this->store_lastBuiltQuery) {
  1035. $this->debug_lastBuiltQuery = $query[0];
  1036. }
  1037. } else {
  1038. $query = 'UPDATE ' . $this->quoteFromTables($table) . '
  1039. SET
  1040. ' . implode(',
  1041. ', $nArr) .
  1042. (strlen($where) > 0 ? '
  1043. WHERE
  1044. ' . $this->quoteWhereClause($where) : '');
  1045. if ($this->debugOutput || $this->store_lastBuiltQuery) {
  1046. $this->debug_lastBuiltQuery = $query;
  1047. }
  1048. }
  1049. return $query;
  1050. } else {
  1051. throw new InvalidArgumentException(
  1052. 'TYPO3 Fatal Error: "Where" clause argument for UPDATE query was not a string in $this->UPDATEquery() !',
  1053. 1270853880
  1054. );
  1055. }
  1056. }
  1057. /**
  1058. * Creates a DELETE SQL-statement for $table where $where-clause
  1059. * Usage count/core: 3
  1060. *
  1061. * @param string See exec_DELETEquery()
  1062. * @param string See exec_DELETEquery()
  1063. * @return string Full SQL query for DELETE
  1064. */
  1065. public function DELETEquery($table, $where) {
  1066. if (is_string($where)) {
  1067. $table = $this->quoteFromTables($table);
  1068. $where = $this->quoteWhereClause($where);
  1069. $query = parent::DELETEquery($table, $where);
  1070. if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query;
  1071. return $query;
  1072. } else {
  1073. die('<strong>TYPO3 Fatal Error:</strong> "Where" clause argument for DELETE query was not a string in $this->DELETEquery() !');
  1074. }
  1075. }
  1076. /**
  1077. * Creates a SELECT SQL-statement
  1078. * Usage count/core: 11
  1079. *
  1080. * @param string See exec_SELECTquery()
  1081. * @param string See exec_SELECTquery()
  1082. * @param string See exec_SELECTquery()
  1083. * @param string See exec_SELECTquery()
  1084. * @param string See exec_SELECTquery()
  1085. * @param string See exec_SELECTquery()
  1086. * @return string Full SQL query for SELECT
  1087. */
  1088. public function SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '') {
  1089. $this->lastHandlerKey = $this->handler_getFromTableList($from_table);
  1090. $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
  1091. if ($hType === 'adodb' && $this->runningADOdbDriver('postgres')) {
  1092. // Possibly rewrite the LIMIT to be PostgreSQL-compatible
  1093. $splitLimit = t3lib_div::intExplode(',', $limit); // Splitting the limit values:
  1094. if ($splitLimit[1]) { // If there are two parameters, do mapping differently than otherwise:
  1095. $numrows = $splitLimit[1];
  1096. $offset = $splitLimit[0];
  1097. $limit = $numrows . ' OFFSET ' . $offset;
  1098. }
  1099. }
  1100. $select_fields = $this->quoteFieldNames($select_fields);
  1101. $from_table = $this->quoteFromTables($from_table);
  1102. $where_clause = $this->quoteWhereClause($where_clause);
  1103. $groupBy = $this->quoteGroupBy($groupBy);
  1104. $orderBy = $this->quoteOrderBy($orderBy);
  1105. // Call parent method to build actual query
  1106. $query = parent::SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
  1107. if ($this->debugOutput || $this->store_lastBuiltQuery) {
  1108. $this->debug_lastBuiltQuery = $query;
  1109. }
  1110. return $query;
  1111. }
  1112. /**
  1113. * Creates a SELECT SQL-statement to be used with an ADOdb backend.
  1114. *
  1115. * @param array parsed parameters: array($select_fields, $from_table, $where_clause, $groupBy, $orderBy)
  1116. * @return string Full SQL query for SELECT
  1117. */
  1118. protected function SELECTqueryFromArray(array $params) {
  1119. // $select_fields
  1120. $params[0] = $this->_quoteFieldNames($params[0]);
  1121. // $from_table
  1122. $params[1] = $this->_quoteFromTables($params[1]);
  1123. // $where_clause
  1124. if (count($params[2]) > 0) {
  1125. $params[2] = $this->_quoteWhereClause($params[2]);
  1126. }
  1127. // $group_by
  1128. if (count($params[3]) > 0) {
  1129. $params[3] = $this->_quoteGroupBy($params[3]);
  1130. }
  1131. // $order_by
  1132. if (count($params[4]) > 0) {
  1133. $params[4] = $this->_quoteOrderBy($params[4]);
  1134. }
  1135. // Compile the SELECT parameters
  1136. list($select_fields, $from_table, $where_clause, $groupBy, $orderBy) = $this->compileSelectParameters($params);
  1137. // Call parent method to build actual query
  1138. $query = parent::SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy);
  1139. if ($this->debugOutput || $this->store_lastBuiltQuery) {
  1140. $this->debug_lastBuiltQuery = $query;
  1141. }
  1142. return $query;
  1143. }
  1144. /**
  1145. * Compiles and returns an array of SELECTquery parameters (without $limit) to
  1146. * be used with SELECTquery() or exec_SELECTquery().
  1147. *
  1148. * @param array $params
  1149. * @return array array($select_fields, $from_table, $where_clause, $groupBy, $orderBy)
  1150. */
  1151. protected function compileSelectParameters(array $params) {
  1152. $select_fields = $this->SQLparser->compileFieldList($params[0]);
  1153. $from_table = $this->SQLparser->compileFromTables($params[1]);
  1154. $where_clause = (count($params[2]) > 0) ? $this->SQLparser->compileWhereClause($params[2]) : '';
  1155. $groupBy = (count($params[3]) > 0) ? $this->SQLparser->compileFieldList($params[3]) : '';
  1156. $orderBy = (count($params[4]) > 0) ? $this->SQLparser->compileFieldList($params[4]) : '';
  1157. return array($select_fields, $from_table, $where_clause, $groupBy, $orderBy);
  1158. }
  1159. /**
  1160. * Creates a TRUNCATE TABLE SQL-statement
  1161. *
  1162. * @param string See exec_TRUNCATEquery()
  1163. * @return string Full SQL query for TRUNCATE TABLE
  1164. */
  1165. public function TRUNCATEquery($table) {
  1166. $table = $this->quoteFromTables($table);
  1167. // Call parent method to build actual query
  1168. $query = parent::TRUNCATEquery($table);
  1169. if ($this->debugOutput || $this->store_lastBuiltQuery) {
  1170. $this->debug_lastBuiltQuery = $query;
  1171. }
  1172. return $query;
  1173. }
  1174. /**************************************
  1175. *
  1176. * Prepared Query Support
  1177. *
  1178. **************************************/
  1179. /**
  1180. * Creates a SELECT prepared SQL statement.
  1181. *
  1182. * @param string See exec_SELECTquery()
  1183. * @param string See exec_SELECTquery()
  1184. * @param string See exec_SELECTquery()
  1185. * @param string See exec_SELECTquery()
  1186. * @param string See exec_SELECTquery()
  1187. * @param string See exec_SELECTquery()
  1188. * @param array $input_parameters An array of values with as many elements as there are bound parameters in the SQL statement being executed. All values are treated as t3lib_db_PreparedStatement::PARAM_AUTOTYPE.
  1189. * @return t3lib_db_PreparedStatement Prepared statement
  1190. */
  1191. public function prepare_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '', array $input_parameters = array()) {
  1192. if ($this->debug) {
  1193. $pt = t3lib_div::milliseconds();
  1194. }
  1195. $precompiledParts = array();
  1196. if ($this->queryCache) {
  1197. $cacheKey = 'prepare_SELECTquery-' . tx_dbal_querycache::getCacheKey(array(
  1198. 'selectFields' => $select_fields,
  1199. 'fromTable' => $from_table,
  1200. 'whereClause' => $where_clause,
  1201. 'groupBy' => $groupBy,
  1202. 'orderBy' => $orderBy,
  1203. 'limit' => $limit,
  1204. ));
  1205. if ($this->queryCache->has($cacheKey)) {
  1206. $precompiledParts = $this->queryCache->get($cacheKey);
  1207. if ($this->debug) {
  1208. $data = array(
  1209. 'args' => array($from_table, $select_fields, $where_clause, $groupBy, $orderBy, $limit, $input_parameters),
  1210. 'precompiledParts' => $precompiledParts,
  1211. );
  1212. $this->debugHandler(
  1213. 'prepare_SELECTquery (cache hit)',
  1214. t3lib_div::milliseconds() - $pt,
  1215. $data
  1216. );
  1217. }
  1218. }
  1219. }
  1220. if (count($precompiledParts) == 0) {
  1221. // Map table / field names if needed:
  1222. $ORIG_tableName = $from_table; // Saving table names in $ORIG_from_table since $from_table is transformed beneath:
  1223. $parsedFromTable = array();
  1224. $queryComponents = array();
  1225. if ($tableArray = $this->map_needMapping($ORIG_tableName, FALSE, $parsedFromTable)) {
  1226. $from = $parsedFromTable ? $parsedFromTable : $from_table;
  1227. $components = $this->map_remapSELECTQueryParts($select_fields, $from, $where_clause, $groupBy, $orderBy);
  1228. $queryComponents['SELECT'] = $components[0];
  1229. $queryComponents['FROM'] = $components[1];
  1230. $queryComponents['WHERE'] = $components[2];
  1231. $queryComponents['GROUPBY'] = $components[3];
  1232. $queryComponents['ORDERBY'] = $components[4];
  1233. $queryComponents['parameters'] = $components[5];
  1234. } else {
  1235. $queryComponents = $this->getQueryComponents($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
  1236. }
  1237. $queryComponents['ORIG_tableName'] = $ORIG_tableName;
  1238. if (!$this->runningNative()) {
  1239. // Quotes all fields
  1240. $queryComponents['SELECT'] = $this->_quoteFieldNames($queryComponents['SELECT']);
  1241. $queryComponents['FROM'] = $this->_quoteFromTables($queryComponents['FROM']);
  1242. $queryComponents['WHERE'] = $this->_quoteWhereClause($queryComponents['WHERE']);
  1243. $queryComponents['GROUPBY'] = $this->_quoteGroupBy($queryComponents['GROUPBY']);
  1244. $queryComponents['ORDERBY'] = $this->_quoteOrderBy($queryComponents['ORDERBY']);
  1245. }
  1246. $precompiledParts = $this->precompileSELECTquery($queryComponents);
  1247. if ($this->queryCache) {
  1248. try {
  1249. $this->queryCache->set($cacheKey, $precompiledParts);
  1250. } catch (t3lib_cache_Exception $e) {
  1251. if ($this->debug) {
  1252. t3lib_div::devLog($e->getMessage(), 'dbal', 1);
  1253. }
  1254. }
  1255. }
  1256. }
  1257. $preparedStatement = t3lib_div::makeInstance('t3lib_db_PreparedStatement', '', $from_table, $precompiledParts);
  1258. /* @var $preparedStatement t3lib_db_PreparedStatement */
  1259. // Bind values to parameters
  1260. foreach ($input_parameters as $key => $value) {
  1261. $preparedStatement->bindValue($key, $value, t3lib_db_PreparedStatement::PARAM_AUTOTYPE);
  1262. }
  1263. if ($this->debug) {
  1264. $data = array(
  1265. 'args' => array($from_table, $select_fields, $where_clause, $groupBy, $orderBy, $limit, $input_parameters),
  1266. 'ORIG_from_table' => $ORIG_tableName,
  1267. );
  1268. $this->debugHandler(
  1269. 'prepare_SELECTquery',
  1270. t3lib_div::milliseconds() - $pt,
  1271. $data
  1272. );
  1273. }
  1274. // Return prepared statement
  1275. return $preparedStatement;
  1276. }
  1277. /**
  1278. * Returns the parsed query components.
  1279. *
  1280. * @param string $select_fields
  1281. * @param string $from_table
  1282. * @param string $where_clause
  1283. * @param string $groupBy
  1284. * @param string $orderBy
  1285. * @param string $limit
  1286. * @return array
  1287. */
  1288. protected function getQueryComponents($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit) {
  1289. $queryComponents = array(
  1290. 'SELECT' => '',
  1291. 'FROM' => '',
  1292. 'WHERE' => '',
  1293. 'GROUPBY' => '',
  1294. 'ORDERBY' => '',
  1295. 'LIMIT' => '',
  1296. 'parameters' => array(),
  1297. );
  1298. $this->lastHandlerKey = $this->handler_getFromTableList($from_table);
  1299. $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
  1300. if ($hType === 'adodb' && $this->runningADOdbDriver('postgres')) {
  1301. // Possibly rewrite the LIMIT to be PostgreSQL-compatible
  1302. $splitLimit = t3lib_div::intExplode(',', $limit); // Splitting the limit values:
  1303. if ($splitLimit[1]) { // If there are two parameters, do mapping differently than otherwise:
  1304. $numrows = $splitLimit[1];
  1305. $offset = $splitLimit[0];
  1306. $limit = $numrows . ' OFFSET ' . $offset;
  1307. }
  1308. }
  1309. $queryComponents['LIMIT'] = $limit;
  1310. $queryComponents['SELECT'] = $this->SQLparser->parseFieldList($select_fields);
  1311. if ($this->SQLparser->parse_error) {
  1312. die($this->SQLparser->parse_error . ' in ' . __FILE__ . ' : ' . __LINE__);
  1313. }
  1314. $queryComponents['FROM'] = $this->SQLparser->parseFromTables($from_table);
  1315. $queryComponents['WHERE'] = $this->SQLparser->parseWhereClause($where_clause, '', $queryComponents['parameters']);
  1316. if (!is_array($queryComponents['WHERE'])) {
  1317. die('Could not parse where clause in ' . __FILE__ . ' : ' . __LINE__);
  1318. }
  1319. $queryComponents['GROUPBY'] = $this->SQLparser->parseFieldList($groupBy);
  1320. $queryComponents['ORDERBY'] = $this->SQLparser->parseFieldList($orderBy);
  1321. // Return the query components
  1322. return $queryComponents;
  1323. }
  1324. /**
  1325. * Precompiles a SELECT prepared SQL statement.
  1326. *
  1327. * @param array $components
  1328. * @return array Precompiled SQL statement
  1329. */
  1330. protected function precompileSELECTquery(array $components) {
  1331. $parameterWrap = '__' . dechex(time()) . '__';
  1332. foreach ($components['parameters'] as $key => $params) {
  1333. if ($key === '?') {
  1334. foreach ($params as $index => $param) {
  1335. $components['parameters'][$key][$index][0] = $parameterWrap . $param[0] . $parameterWrap;
  1336. }
  1337. } else {
  1338. $components['parameters'][$key][0] = $parameterWrap . $params[0] . $parameterWrap;
  1339. }
  1340. }
  1341. $select_fields = $this->SQLparser->compileFieldList($components['SELECT']);
  1342. $from_table = $this->SQLparser->compileFromTables($components['FROM']);
  1343. $where_clause = $this->SQLparser->compileWhereClause($components['WHERE']);
  1344. $groupBy = $this->SQLparser->compileFieldList($components['GROUPBY']);
  1345. $orderBy = $this->SQLparser->compileFieldList($components['ORDERBY']);
  1346. $limit = $components['LIMIT'];
  1347. $precompiledParts = array();
  1348. $this->lastHandlerKey = $this->handler_getFromTableList($components['ORIG_tableName']);
  1349. $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
  1350. $precompiledParts['handler'] = $hType;
  1351. $precompiledParts['ORIG_tableName'] = $components['ORIG_tableName'];
  1352. switch ($hType) {
  1353. case 'native':
  1354. $query = parent::SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
  1355. $precompiledParts['queryParts'] = explode($parameterWrap, $query);
  1356. break;
  1357. case 'adodb':
  1358. $query = parent::SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy);
  1359. $precompiledParts['queryParts'] = explode($parameterWrap, $query);
  1360. $precompiledParts['LIMIT'] = $limit;
  1361. break;
  1362. case 'userdefined':
  1363. $precompiledParts['queryParts'] = array(
  1364. 'SELECT' => $select_fields,
  1365. 'FROM' => $from_table,
  1366. 'WHERE' => $where_clause,
  1367. 'GROUPBY' => $groupBy,
  1368. 'ORDERBY' => $orderBy,
  1369. 'LIMIT' => $limit,
  1370. );
  1371. break;
  1372. }
  1373. return $precompiledParts;
  1374. }
  1375. /**
  1376. * Executes a prepared query.
  1377. *
  1378. * @param string $query The query to execute
  1379. * @param array $queryComponents The components of the query to execute
  1380. * @return pointer MySQL result pointer / DBAL object
  1381. * @access protected This method may only be called by t3lib_db_PreparedStatement
  1382. */
  1383. public function exec_PREPAREDquery($query, array $precompiledParts) {
  1384. if ($this->debug) {
  1385. $pt = t3lib_div::milliseconds();
  1386. }
  1387. // Get handler key and select API:
  1388. switch ($precompiledParts['handler']) {
  1389. case 'native':
  1390. $this->lastQuery = $query;
  1391. $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
  1392. $this->resourceIdToTableNameMap[(string) $sqlResult] = $precompiledParts['ORIG_tableName'];
  1393. break;
  1394. case 'adodb':
  1395. $limit = $precompiledParts['LIMIT'];
  1396. if ($this->runningADOdbDriver('postgres')) {
  1397. // Possibly rewrite the LIMIT to be PostgreSQL-compatible
  1398. $splitLimit = t3lib_div::intExplode(',', $limit); // Splitting the limit values:
  1399. if ($splitLimit[1]) { // If there are two parameters, do mapping differently than otherwise:
  1400. $numrows = $splitLimit[1];
  1401. $offset = $splitLimit[0];
  1402. $limit = $numrows . ' OFFSET ' . $offset;
  1403. }
  1404. }
  1405. if ($limit != '') {
  1406. $splitLimit = t3lib_div::intExplode(',', $limit); // Splitting the limit values:
  1407. if ($splitLimit[1]) { // If there are two parameters, do mapping differently than otherwise:
  1408. $numrows = $splitLimit[1];
  1409. $offset = $splitLimit[0];
  1410. } else {
  1411. $numrows = $splitLimit[0];
  1412. $offset = 0;
  1413. }
  1414. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit($query, $numrows, $offset);
  1415. $this->lastQuery = $sqlResult->sql;
  1416. } else {
  1417. $this->lastQuery = $query;
  1418. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_Execute($this->lastQuery);
  1419. }
  1420. $sqlResult->TYPO3_DBAL_handlerType = 'adodb'; // Setting handler type in result object (for later recognition!)
  1421. $sqlResult->TYPO3_DBAL_tableList = $precompiledParts['ORIG_tableName'];
  1422. break;
  1423. case 'userdefined':
  1424. $queryParts = $precompiledParts['queryParts'];
  1425. $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_SELECTquery(
  1426. $queryParts['SELECT'],
  1427. $queryParts['FROM'],
  1428. $queryParts['WHERE'],
  1429. $queryParts['GROUPBY'],
  1430. $queryParts['ORDERBY'],
  1431. $queryParts['LIMIT']
  1432. );
  1433. if (is_object($sqlResult)) {
  1434. $sqlResult->TYPO3_DBAL_handlerType = 'userdefined'; // Setting handler type in result object (for later recognition!)
  1435. $sqlResult->TYPO3_DBAL_tableList = $precompiledParts['ORIG_tableName'];
  1436. }
  1437. break;
  1438. }
  1439. if ($this->printErrors && $this->sql_error()) {
  1440. debug(array($this->lastQuery, $this->sql_error()));
  1441. }
  1442. if ($this->debug) {
  1443. $data = array(
  1444. 'handlerType' => $precompiledParts['handler'],
  1445. 'args' => $precompiledParts,
  1446. 'ORIG_from_table' => $precompiledParts['ORIG_tableName'],
  1447. );
  1448. if ($this->conf['debugOptions']['numberRows']) {
  1449. $data['numberRows'] = $this->sql_num_rows($sqlResult);
  1450. }
  1451. $this->debugHandler(
  1452. 'exec_PREPAREDquery',
  1453. t3lib_div::milliseconds() - $pt,
  1454. $data
  1455. );
  1456. }
  1457. // Return result handler.
  1458. return $sqlResult;
  1459. }
  1460. /**************************************
  1461. *
  1462. * Functions for quoting table/field names
  1463. *
  1464. **************************************/
  1465. /**
  1466. * Quotes components of a SELECT subquery.
  1467. *
  1468. * @param array $components Array of SQL query components
  1469. * @return array
  1470. */
  1471. protected function quoteSELECTsubquery(array $components) {
  1472. $components['SELECT'] = $this->_quoteFieldNames($components['SELECT']);
  1473. $components['FROM'] = $this->_quoteFromTables($components['FROM']);
  1474. $components['WHERE'] = $this->_quoteWhereClause($components['WHERE']);
  1475. return $components;
  1476. }
  1477. /**
  1478. * Quotes field (and table) names with the quote character suitable for the DB being used
  1479. * Use quoteFieldNames instead!
  1480. *
  1481. * @param string List of fields to be selected from DB
  1482. * @return string Quoted list of fields to be selected from DB
  1483. * @deprecated since TYPO3 4.0, will be removed in TYPO3 4.6
  1484. */
  1485. public function quoteSelectFields($select_fields) {
  1486. t3lib_div::logDeprecatedFunction();
  1487. $this->quoteFieldNames($select_fields);
  1488. }
  1489. /**
  1490. * Quotes field (and table) names with the quote character suitable for the DB being used
  1491. *
  1492. * @param string List of fields to be used in query to DB
  1493. * @return string Quoted list of fields to be in query to DB
  1494. */
  1495. public function quoteFieldNames($select_fields) {
  1496. if ($select_fields == '') {
  1497. return '';
  1498. }
  1499. if ($this->runningNative()) {
  1500. return $select_fields;
  1501. }
  1502. $select_fields = $this->SQLparser->parseFieldList($select_fields);
  1503. if ($this->SQLparser->parse_error) {
  1504. die($this->SQLparser->parse_error . ' in ' . __FILE__ . ' : ' . __LINE__);
  1505. }
  1506. $select_fields = $this->_quoteFieldNames($select_fields);
  1507. return $this->SQLparser->compileFieldList($select_fields);
  1508. }
  1509. /**
  1510. * Quotes field (and table) names in a SQL SELECT clause acccording to DB rules
  1511. *
  1512. * @param array $select_fields The parsed fields to quote
  1513. * @return array
  1514. * @see quoteFieldNames()
  1515. */
  1516. protected function _quoteFieldNames(array $select_fields) {
  1517. foreach ($select_fields as $k => $v) {
  1518. if ($select_fields[$k]['field'] != '' && $select_fields[$k]['field'] != '*' && !is_numeric($select_fields[$k]['field'])) {
  1519. $select_fields[$k]['field'] = $this->quoteName($select_fields[$k]['field']);
  1520. }
  1521. if ($select_fields[$k]['table'] != '' && !is_numeric($select_fields[$k]['table'])) {
  1522. $select_fields[$k]['table'] = $this->quoteName($select_fields[$k]['table']);
  1523. }
  1524. if ($select_fields[$k]['as'] != '') {
  1525. $select_fields[$k]['as'] = $this->quoteName($select_fields[$k]['as']);
  1526. }
  1527. if (isset($select_fields[$k]['func_content.']) && $select_fields[$k]['func_content.'][0]['func_content'] != '*') {
  1528. $select_fields[$k]['func_content.'][0]['func_content'] = $this->quoteFieldNames($select_fields[$k]['func_content.'][0]['func_content']);
  1529. $select_fields[$k]['func_content'] = $this->quoteFieldNames($select_fields[$k]['func_content']);
  1530. }
  1531. if (isset($select_fields[$k]['flow-control'])) {
  1532. // Quoting flow-control statements
  1533. if ($select_fields[$k]['flow-control']['type'] === 'CASE') {
  1534. if (isset($select_fields[$k]['flow-control']['case_field'])) {
  1535. $select_fields[$k]['flow-control']['case_field'] = $this->quoteFieldNames($select_fields[$k]['flow-control']['case_field']);
  1536. }
  1537. foreach ($select_fields[$k]['flow-control']['when'] as $key => $when) {
  1538. $select_fields[$k]['flow-control']['when'][$key]['when_value'] = $this->_quoteWhereClause($when['when_value']);
  1539. }
  1540. }
  1541. }
  1542. }
  1543. return $select_fields;
  1544. }
  1545. /**
  1546. * Quotes table names with the quote character suitable for the DB being used
  1547. *
  1548. * @param string List of tables to be selected from DB
  1549. * @return string Quoted list of tables to be selected from DB
  1550. */
  1551. public function quoteFromTables($from_table) {
  1552. if ($from_table == '') {
  1553. return '';
  1554. }
  1555. if ($this->runningNative()) {
  1556. return $from_table;
  1557. }
  1558. $from_table = $this->SQLparser->parseFromTables($from_table);
  1559. $from_table = $this->_quoteFromTables($from_table);
  1560. return $this->SQLparser->compileFromTables($from_table);
  1561. }
  1562. /**
  1563. * Quotes table names in a SQL FROM clause acccording to DB rules
  1564. *
  1565. * @param array $from_table The parsed FROM clause to quote
  1566. * @return array
  1567. * @see quoteFromTables()
  1568. */
  1569. protected function _quoteFromTables(array $from_table) {
  1570. foreach ($from_table as $k => $v) {
  1571. $from_table[$k]['table'] = $this->quoteName($from_table[$k]['table']);
  1572. if ($from_table[$k]['as'] != '') {
  1573. $from_table[$k]['as'] = $this->quoteName($from_table[$k]['as']);
  1574. }
  1575. if (is_array($v['JOIN'])) {
  1576. foreach ($v['JOIN'] as $joinCnt => $join) {
  1577. $from_table[$k]['JOIN'][$joinCnt]['withTable'] = $this->quoteName($join['withTable']);
  1578. $from_table[$k]['JOIN'][$joinCnt]['as'] = ($join['as']) ? $this->quoteName($join['as']) : '';
  1579. foreach ($from_table[$k]['JOIN'][$joinCnt]['ON'] as &$condition) {
  1580. $condition['left']['table'] = ($condition['left']['table']) ? $this->quoteName($condition['left']['table']) : '';
  1581. $condition['left']['field'] = $this->quoteName($condition['left']['field']);
  1582. $condition['right']['table'] = ($condition['right']['table']) ? $this->quoteName($condition['right']['table']) : '';
  1583. $condition['right']['field'] = $this->quoteName($condition['right']['field']);
  1584. }
  1585. }
  1586. }
  1587. }
  1588. return $from_table;
  1589. }
  1590. /**
  1591. * Quotes the field (and table) names within a where clause with the quote character suitable for the DB being used
  1592. *
  1593. * @param string A where clause that can be parsed by parseWhereClause
  1594. * @return string Usable where clause with quoted field/table names
  1595. */
  1596. public function quoteWhereClause($where_clause) {
  1597. if ($where_clause === '' || $this->runningNative()) {
  1598. return $where_clause;
  1599. }
  1600. $where_clause = $this->SQLparser->parseWhereClause($where_clause);
  1601. if (is_array($where_clause)) {
  1602. $where_clause = $this->_quoteWhereClause($where_clause);
  1603. $where_clause = $this->SQLparser->compileWhereClause($where_clause);
  1604. } else {
  1605. die('Could not parse where clause in ' . __FILE__ . ' : ' . __LINE__);
  1606. }
  1607. return $where_clause;
  1608. }
  1609. /**
  1610. * Quotes field names in a SQL WHERE clause acccording to DB rules
  1611. *
  1612. * @param array $where_clause The parsed WHERE clause to quote
  1613. * @return array
  1614. * @see quoteWhereClause()
  1615. */
  1616. protected function _quoteWhereClause(array $where_clause) {
  1617. foreach ($where_clause as $k => $v) {
  1618. // Look for sublevel:
  1619. if (is_array($where_clause[$k]['sub'])) {
  1620. $where_clause[$k]['sub'] = $this->_quoteWhereClause($where_clause[$k]['sub']);
  1621. } elseif (isset($v['func'])) {
  1622. switch ($where_clause[$k]['func']['type']) {
  1623. case 'EXISTS':
  1624. $where_clause[$k]['func']['subquery'] = $this->quoteSELECTsubquery($v['func']['subquery']);
  1625. break;
  1626. case 'FIND_IN_SET':
  1627. // quoteStr that will be used for Oracle
  1628. $pattern = str_replace($where_clause[$k]['func']['str'][1], '\\' . $where_clause[$k]['func']['str'][1], $where_clause[$k]['func']['str'][0]);
  1629. // table is not really needed and may in fact be empty in real statements
  1630. // but it's not overriden from t3lib_db at the moment...
  1631. $patternForLike = $this->escapeStrForLike($pattern, $where_clause[$k]['func']['table']);
  1632. $where_clause[$k]['func']['str_like'] = $patternForLike;
  1633. // BEWARE: no break here to have next statements too
  1634. case 'IFNULL':
  1635. case 'LOCATE':
  1636. if ($where_clause[$k]['func']['table'] != '') {
  1637. $where_clause[$k]['func']['table'] = $this->quoteName($v['func']['table']);
  1638. }
  1639. if ($where_clause[$k]['func']['field'] != '') {
  1640. $where_clause[$k]['func']['field'] = $this->quoteName($v['func']['field']);
  1641. }
  1642. break;
  1643. }
  1644. } else {
  1645. if ($where_clause[$k]['table'] != '') {
  1646. $where_clause[$k]['table'] = $this->quoteName($where_clause[$k]['table']);
  1647. }
  1648. if (!is_numeric($where_clause[$k]['field'])) {
  1649. $where_clause[$k]['field'] = $this->quoteName($where_clause[$k]['field']);
  1650. }
  1651. if (isset($where_clause[$k]['calc_table'])) {
  1652. if ($where_clause[$k]['calc_table'] != '') {
  1653. $where_clause[$k]['calc_table'] = $this->quoteName($where_clause[$k]['calc_table']);
  1654. }
  1655. if ($where_clause[$k]['calc_field'] != '') {
  1656. $where_clause[$k]['calc_field'] = $this->quoteName($where_clause[$k]['calc_field']);
  1657. }
  1658. }
  1659. }
  1660. if ($where_clause[$k]['comparator']) {
  1661. if (isset($v['value']['operator'])) {
  1662. foreach ($where_clause[$k]['value']['args'] as $argK => $fieldDef) {
  1663. $where_clause[$k]['value']['args'][$argK]['table'] = $this->quoteName($fieldDef['table']);
  1664. $where_clause[$k]['value']['args'][$argK]['field'] = $this->quoteName($fieldDef['field']);
  1665. }
  1666. } else {
  1667. // Detecting value type; list or plain:
  1668. if (t3lib_div::inList('NOTIN,IN', strtoupper(str_replace(array(' ', "\n", "\r", "\t"), '', $where_clause[$k]['comparator'])))) {
  1669. if (isset($v['subquery'])) {
  1670. $where_clause[$k]['subquery'] = $this->quoteSELECTsubquery($v['subquery']);
  1671. }
  1672. } else {
  1673. if ((!isset($where_clause[$k]['value'][1]) || $where_clause[$k]['value'][1] == '') && is_string($where_clause[$k]['value'][0]) && strstr($where_clause[$k]['value'][0], '.')) {
  1674. $where_clause[$k]['value'][0] = $this->quoteFieldNames($where_clause[$k]['value'][0]);
  1675. }
  1676. }
  1677. }
  1678. }
  1679. }
  1680. return $where_clause;
  1681. }
  1682. /**
  1683. * Quotes the field (and table) names within a group by clause with the quote
  1684. * character suitable for the DB being used
  1685. *
  1686. * @param string A group by clause that can by parsed by parseFieldList
  1687. * @return string Usable group by clause with quoted field/table names
  1688. */
  1689. protected function quoteGroupBy($groupBy) {
  1690. if ($groupBy === '') {
  1691. return '';
  1692. }
  1693. if ($this->runningNative()) {
  1694. return $groupBy;
  1695. }
  1696. $groupBy = $this->SQLparser->parseFieldList($groupBy);
  1697. $groupBy = $this->_quoteGroupBy($groupBy);
  1698. return $this->SQLparser->compileFieldList($groupBy);
  1699. }
  1700. /**
  1701. * Quotes field names in a SQL GROUP BY clause acccording to DB rules
  1702. *
  1703. * @param array $groupBy The parsed GROUP BY clause to quote
  1704. * @return array
  1705. * @see quoteGroupBy()
  1706. */
  1707. protected function _quoteGroupBy(array $groupBy) {
  1708. foreach ($groupBy as $k => $v) {
  1709. $groupBy[$k]['field'] = $this->quoteName($groupBy[$k]['field']);
  1710. if ($groupBy[$k]['table'] != '') {
  1711. $groupBy[$k]['table'] = $this->quoteName($groupBy[$k]['table']);
  1712. }
  1713. }
  1714. return $groupBy;
  1715. }
  1716. /**
  1717. * Quotes the field (and table) names within an order by clause with the quote
  1718. * character suitable for the DB being used
  1719. *
  1720. * @param string An order by clause that can by parsed by parseFieldList
  1721. * @return string Usable order by clause with quoted field/table names
  1722. */
  1723. protected function quoteOrderBy($orderBy) {
  1724. if ($orderBy === '') {
  1725. return '';
  1726. }
  1727. if ($this->runningNative()) {
  1728. return $orderBy;
  1729. }
  1730. $orderBy = $this->SQLparser->parseFieldList($orderBy);
  1731. $orderBy = $this->_quoteOrderBy($orderBy);
  1732. return $this->SQLparser->compileFieldList($orderBy);
  1733. }
  1734. /**
  1735. * Quotes field names in a SQL ORDER BY clause acccording to DB rules
  1736. *
  1737. * @param array $orderBy The parsed ORDER BY clause to quote
  1738. * @return array
  1739. * @see quoteOrderBy()
  1740. */
  1741. protected function _quoteOrderBy(array $orderBy) {
  1742. foreach ($orderBy as $k => $v) {
  1743. $orderBy[$k]['field'] = $this->quoteName($orderBy[$k]['field']);
  1744. if ($orderBy[$k]['table'] != '') {
  1745. $orderBy[$k]['table'] = $this->quoteName($orderBy[$k]['table']);
  1746. }
  1747. }
  1748. return $orderBy;
  1749. }
  1750. /**************************************
  1751. *
  1752. * Various helper functions
  1753. *
  1754. **************************************/
  1755. /**
  1756. * Escaping and quoting values for SQL statements.
  1757. *
  1758. * @param string Input string
  1759. * @param string Table name for which to quote string. Just enter the table that the field-value is selected from (and any DBAL will look up which handler to use and then how to quote the string!).
  1760. * @return string Output string; Wrapped in single quotes and quotes in the string (" / ') and \ will be backslashed (or otherwise based on DBAL handler)
  1761. * @see quoteStr()
  1762. */
  1763. public function fullQuoteStr($str, $table) {
  1764. return '\'' . $this->quoteStr($str, $table) . '\'';
  1765. }
  1766. /**
  1767. * Substitution for PHP function "addslashes()"
  1768. * NOTICE: You must wrap the output of this function in SINGLE QUOTES to be DBAL compatible. Unless you have to apply the single quotes yourself you should rather use ->fullQuoteStr()!
  1769. *
  1770. * @param string Input string
  1771. * @param string Table name for which to quote string. Just enter the table that the field-value is selected from (and any DBAL will look up which handler to use and then how to quote the string!).
  1772. * @return string Output string; Quotes (" / ') and \ will be backslashed (or otherwise based on DBAL handler)
  1773. * @see quoteStr()
  1774. */
  1775. public function quoteStr($str, $table) {
  1776. $this->lastHandlerKey = $this->handler_getFromTableList($table);
  1777. switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
  1778. case 'native':
  1779. if ($this->handlerInstance[$this->lastHandlerKey]['link']) {
  1780. $str = mysql_real_escape_string($str, $this->handlerInstance[$this->lastHandlerKey]['link']);
  1781. } else {
  1782. // link may be null when unit testing DBAL
  1783. $str = str_replace('\'', '\\\'', $str);
  1784. }
  1785. break;
  1786. case 'adodb':
  1787. $str = substr($this->handlerInstance[$this->lastHandlerKey]->qstr($str), 1, -1);
  1788. break;
  1789. case 'userdefined':
  1790. $str = $this->handlerInstance[$this->lastHandlerKey]->quoteStr($str);
  1791. break;
  1792. default:
  1793. die('No handler found!!!');
  1794. break;
  1795. }
  1796. return $str;
  1797. }
  1798. /**
  1799. * Quotes an object name (table name, field, ...)
  1800. *
  1801. * @param string Object's name
  1802. * @param string Handler key
  1803. * @param boolean If method NameQuote() is not used, whether to use backticks instead of driver-specific quotes
  1804. * @return string Properly-quoted object's name
  1805. */
  1806. public function quoteName($name, $handlerKey = NULL, $useBackticks = FALSE) {
  1807. $handlerKey = $handlerKey ? $handlerKey : $this->lastHandlerKey;
  1808. $useNameQuote = isset($this->handlerCfg[$handlerKey]['config']['useNameQuote']) ? $this->handlerCfg[$handlerKey]['config']['useNameQuote'] : FALSE;
  1809. if ($useNameQuote) {
  1810. return $this->handlerInstance[$handlerKey]->DataDictionary->NameQuote($name);
  1811. } else {
  1812. $quote = $useBackticks ? '`' : $this->handlerInstance[$handlerKey]->nameQuote;
  1813. return $quote . $name . $quote;
  1814. }
  1815. }
  1816. /**
  1817. * Return MetaType for native field type (ADOdb only!)
  1818. *
  1819. * @param string native type as reported by admin_get_fields()
  1820. * @param string Table name for which query type string. Important for detection of DBMS handler of the query!
  1821. * @return string Meta type (currenly ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
  1822. */
  1823. public function MetaType($type, $table, $max_length = -1) {
  1824. $this->lastHandlerKey = $this->handler_getFromTableList($table);
  1825. $str = '';
  1826. switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
  1827. case 'native':
  1828. $str = $type;
  1829. break;
  1830. case 'adodb':
  1831. if (in_array($table, $this->cache_fieldType)) {
  1832. $rs = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit('SELECT * FROM ' . $this->quoteFromTables($table), 1);
  1833. $str = $rs->MetaType($type, $max_length);
  1834. }
  1835. break;
  1836. case 'userdefined':
  1837. $str = $this->handlerInstance[$this->lastHandlerKey]->MetaType($str, $table, $max_length);
  1838. break;
  1839. default:
  1840. die('No handler found!!!');
  1841. break;
  1842. }
  1843. return $str;
  1844. }
  1845. /**
  1846. * Return MetaType for native MySQL field type
  1847. *
  1848. * @param string native type as reported as in mysqldump files
  1849. * @return string Meta type (currenly ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
  1850. */
  1851. public function MySQLMetaType($t) {
  1852. switch (strtoupper($t)) {
  1853. case 'STRING':
  1854. case 'CHAR':
  1855. case 'VARCHAR':
  1856. case 'TINYBLOB':
  1857. case 'TINYTEXT':
  1858. case 'ENUM':
  1859. case 'SET':
  1860. return 'C';
  1861. case 'TEXT':
  1862. case 'LONGTEXT':
  1863. case 'MEDIUMTEXT':
  1864. return 'XL';
  1865. case 'IMAGE':
  1866. case 'LONGBLOB':
  1867. case 'BLOB':
  1868. case 'MEDIUMBLOB':
  1869. return 'B';
  1870. case 'YEAR':
  1871. case 'DATE':
  1872. return 'D';
  1873. case 'TIME':
  1874. case 'DATETIME':
  1875. case 'TIMESTAMP':
  1876. return 'T';
  1877. case 'FLOAT':
  1878. case 'DOUBLE':
  1879. return 'F';
  1880. case 'INT':
  1881. case 'INTEGER':
  1882. case 'TINYINT':
  1883. case 'SMALLINT':
  1884. case 'MEDIUMINT':
  1885. case 'BIGINT':
  1886. return 'I8'; // we always return I8 to be on the safe side. Under some circumstances the fields are to small otherwise...
  1887. default:
  1888. return 'N';
  1889. }
  1890. }
  1891. /**
  1892. * Return actual MySQL type for meta field type
  1893. *
  1894. * @param string Meta type (currenly ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
  1895. * @return string native type as reported as in mysqldump files, uppercase
  1896. */
  1897. public function MySQLActualType($meta) {
  1898. switch (strtoupper($meta)) {
  1899. case 'C':
  1900. return 'VARCHAR';
  1901. case 'XL':
  1902. case 'X':
  1903. return 'LONGTEXT';
  1904. case 'C2':
  1905. return 'VARCHAR';
  1906. case 'X2':
  1907. return 'LONGTEXT';
  1908. case 'B':
  1909. return 'LONGBLOB';
  1910. case 'D':
  1911. return 'DATE';
  1912. case 'T':
  1913. return 'DATETIME';
  1914. case 'L':
  1915. return 'TINYINT';
  1916. case 'I':
  1917. case 'I1':
  1918. case 'I2':
  1919. case 'I4':
  1920. case 'I8':
  1921. return 'BIGINT'; // we only have I8 in DBAL, see MySQLMetaType()
  1922. case 'F':
  1923. return 'DOUBLE';
  1924. case 'N':
  1925. return 'NUMERIC';
  1926. default:
  1927. return $meta;
  1928. }
  1929. }
  1930. /**************************************
  1931. *
  1932. * SQL wrapper functions (Overriding parent methods)
  1933. * (For use in your applications)
  1934. *
  1935. **************************************/
  1936. /**
  1937. * Returns the error status on the most recent sql() execution (based on $this->lastHandlerKey)
  1938. *
  1939. * @return string Handler error strings
  1940. */
  1941. public function sql_error() {
  1942. switch ($this->handlerCfg[$this->lastHandlerKey]['type']) {
  1943. case 'native':
  1944. $output = mysql_error($this->handlerInstance[$this->lastHandlerKey]['link']);
  1945. break;
  1946. case 'adodb':
  1947. $output = $this->handlerInstance[$this->lastHandlerKey]->ErrorMsg();
  1948. break;
  1949. case 'userdefined':
  1950. $output = $this->handlerInstance[$this->lastHandlerKey]->sql_error();
  1951. break;
  1952. }
  1953. return $output;
  1954. }
  1955. /**
  1956. * Returns the error number on the most recent sql() execution (based on $this->lastHandlerKey)
  1957. *
  1958. * @return int Handler error number
  1959. */
  1960. public function sql_errno() {
  1961. switch ($this->handlerCfg[$this->lastHandlerKey]['type']) {
  1962. case 'native':
  1963. $output = mysql_errno($this->handlerInstance[$this->lastHandlerKey]['link']);
  1964. break;
  1965. case 'adodb':
  1966. $output = $this->handlerInstance[$this->lastHandlerKey]->ErrorNo();
  1967. break;
  1968. case 'userdefined':
  1969. $output = $this->handlerInstance[$this->lastHandlerKey]->sql_errno();
  1970. break;
  1971. }
  1972. return $output;
  1973. }
  1974. /**
  1975. * Returns the number of selected rows.
  1976. *
  1977. * @param pointer Result pointer / DBAL object
  1978. * @return integer Number of resulting rows.
  1979. */
  1980. public function sql_num_rows(&$res) {
  1981. if ($res === FALSE) {
  1982. return 0;
  1983. }
  1984. $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
  1985. switch ($handlerType) {
  1986. case 'native':
  1987. $output = mysql_num_rows($res);
  1988. break;
  1989. case 'adodb':
  1990. $output = method_exists($res, 'RecordCount') ? $res->RecordCount() : 0;
  1991. break;
  1992. case 'userdefined':
  1993. $output = $res->sql_num_rows();
  1994. break;
  1995. }
  1996. return $output;
  1997. }
  1998. /**
  1999. * Returns an associative array that corresponds to the fetched row, or FALSE if there are no more rows.
  2000. *
  2001. * @param pointer MySQL result pointer (of SELECT query) / DBAL object
  2002. * @return array Associative array of result row.
  2003. */
  2004. public function sql_fetch_assoc(&$res) {
  2005. $output = array();
  2006. $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : (is_resource($res) ? 'native' : FALSE);
  2007. switch ($handlerType) {
  2008. case 'native':
  2009. $output = mysql_fetch_assoc($res);
  2010. $tableList = $this->resourceIdToTableNameMap[(string) $res]; // Reading list of tables from SELECT query:
  2011. break;
  2012. case 'adodb':
  2013. // Check if method exists for the current $res object.
  2014. // If a table exists in TCA but not in the db, a error
  2015. // occured because $res is not a valid object.
  2016. if (method_exists($res, 'FetchRow')) {
  2017. $output = $res->FetchRow();
  2018. $tableList = $res->TYPO3_DBAL_tableList; // Reading list of tables from SELECT query:
  2019. // Removing all numeric/integer keys.
  2020. // A workaround because in ADOdb we would need to know what we want before executing the query...
  2021. // MSSQL does not support ADODB_FETCH_BOTH and always returns an assoc. array instead. So
  2022. // we don't need to remove anything.
  2023. if (is_array($output)) {
  2024. if ($this->runningADOdbDriver('mssql')) {
  2025. // MSSQL does not know such thing as an empty string. So it returns one space instead, which we must fix.
  2026. foreach ($output as $key => $value) {
  2027. if ($value === ' ') {
  2028. $output[$key] = '';
  2029. }
  2030. }
  2031. } else {
  2032. foreach ($output as $key => $value) {
  2033. if (is_integer($key)) {
  2034. unset($output[$key]);
  2035. }
  2036. }
  2037. }
  2038. }
  2039. }
  2040. break;
  2041. case 'userdefined':
  2042. $output = $res->sql_fetch_assoc();
  2043. $tableList = $res->TYPO3_DBAL_tableList; // Reading list of tables from SELECT query:
  2044. break;
  2045. }
  2046. // Table/Fieldname mapping:
  2047. if (is_array($output)) {
  2048. if ($tables = $this->map_needMapping($tableList, TRUE)) {
  2049. $output = $this->map_assocArray($output, $tables, 1);
  2050. }
  2051. }
  2052. // Return result:
  2053. return $output;
  2054. }
  2055. /**
  2056. * Returns an array that corresponds to the fetched row, or FALSE if there are no more rows.
  2057. * The array contains the values in numerical indices.
  2058. *
  2059. * @param pointer MySQL result pointer (of SELECT query) / DBAL object
  2060. * @return array Array with result rows.
  2061. */
  2062. public function sql_fetch_row(&$res) {
  2063. $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
  2064. switch ($handlerType) {
  2065. case 'native':
  2066. $output = mysql_fetch_row($res);
  2067. break;
  2068. case 'adodb':
  2069. // Check if method exists for the current $res object.
  2070. // If a table exists in TCA but not in the db, a error
  2071. // occured because $res is not a valid object.
  2072. if (method_exists($res, 'FetchRow')) {
  2073. $output = $res->FetchRow();
  2074. // Removing all assoc. keys.
  2075. // A workaround because in ADOdb we would need to know what we want before executing the query...
  2076. // MSSQL does not support ADODB_FETCH_BOTH and always returns an assoc. array instead. So
  2077. // we need to convert resultset.
  2078. if (is_array($output)) {
  2079. $keyIndex = 0;
  2080. foreach ($output as $key => $value) {
  2081. unset($output[$key]);
  2082. if (is_integer($key) || $this->runningADOdbDriver('mssql')) {
  2083. $output[$keyIndex] = $value;
  2084. if ($value === ' ') {
  2085. // MSSQL does not know such thing as an empty string. So it returns one space instead, which we must fix.
  2086. $output[$keyIndex] = '';
  2087. }
  2088. $keyIndex++;
  2089. }
  2090. }
  2091. }
  2092. }
  2093. break;
  2094. case 'userdefined':
  2095. $output = $res->sql_fetch_row();
  2096. break;
  2097. }
  2098. return $output;
  2099. }
  2100. /**
  2101. * Free result memory / unset result object
  2102. *
  2103. * @param pointer MySQL result pointer to free / DBAL object
  2104. * @return boolean Returns TRUE on success or FALSE on failure.
  2105. */
  2106. public function sql_free_result(&$res) {
  2107. if ($res === FALSE) {
  2108. return FALSE;
  2109. }
  2110. $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
  2111. switch ($handlerType) {
  2112. case 'native':
  2113. $output = mysql_free_result($res);
  2114. break;
  2115. case 'adodb':
  2116. if (method_exists($res, 'Close')) {
  2117. $res->Close();
  2118. unset($res);
  2119. $output = TRUE;
  2120. } else {
  2121. $output = FALSE;
  2122. }
  2123. break;
  2124. case 'userdefined':
  2125. unset($res);
  2126. break;
  2127. }
  2128. return $output;
  2129. }
  2130. /**
  2131. * Get the ID generated from the previous INSERT operation
  2132. *
  2133. * @return integer The uid of the last inserted record.
  2134. */
  2135. public function sql_insert_id() {
  2136. switch ($this->handlerCfg[$this->lastHandlerKey]['type']) {
  2137. case 'native':
  2138. $output = mysql_insert_id($this->handlerInstance[$this->lastHandlerKey]['link']);
  2139. break;
  2140. case 'adodb':
  2141. $output = $this->handlerInstance[$this->lastHandlerKey]->last_insert_id;
  2142. break;
  2143. case 'userdefined':
  2144. $output = $this->handlerInstance[$this->lastHandlerKey]->sql_insert_id();
  2145. break;
  2146. }
  2147. return $output;
  2148. }
  2149. /**
  2150. * Returns the number of rows affected by the last INSERT, UPDATE or DELETE query
  2151. *
  2152. * @return integer Number of rows affected by last query
  2153. */
  2154. public function sql_affected_rows() {
  2155. switch ($this->handlerCfg[$this->lastHandlerKey]['type']) {
  2156. case 'native':
  2157. $output = mysql_affected_rows();
  2158. break;
  2159. case 'adodb':
  2160. $output = $this->handlerInstance[$this->lastHandlerKey]->Affected_Rows();
  2161. break;
  2162. case 'userdefined':
  2163. $output = $this->handlerInstance[$this->lastHandlerKey]->sql_affected_rows();
  2164. break;
  2165. }
  2166. return $output;
  2167. }
  2168. /**
  2169. * Move internal result pointer
  2170. *
  2171. * @param pointer MySQL result pointer (of SELECT query) / DBAL object
  2172. * @param integer Seek result number.
  2173. * @return boolean Returns TRUE on success or FALSE on failure.
  2174. */
  2175. public function sql_data_seek(&$res, $seek) {
  2176. $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
  2177. switch ($handlerType) {
  2178. case 'native':
  2179. $output = mysql_data_seek($res, $seek);
  2180. break;
  2181. case 'adodb':
  2182. $output = $res->Move($seek);
  2183. break;
  2184. case 'userdefined':
  2185. $output = $res->sql_data_seek($seek);
  2186. break;
  2187. }
  2188. return $output;
  2189. }
  2190. /**
  2191. * Get the type of the specified field in a result
  2192. *
  2193. * If the first parameter is a string, it is used as table name for the lookup.
  2194. *
  2195. * @param pointer MySQL result pointer (of SELECT query) / DBAL object / table name
  2196. * @param integer Field index. In case of ADOdb a string (field name!) FIXME
  2197. * @return string Returns the type of the specified field index
  2198. */
  2199. public function sql_field_metatype($table, $field) {
  2200. // If $table and/or $field are mapped, use the original names instead
  2201. foreach ($this->mapping as $tableName => $tableMapInfo) {
  2202. if (isset($tableMapInfo['mapTableName']) && $tableMapInfo['mapTableName'] === $table) {
  2203. // Table name is mapped => use original name
  2204. $table = $tableName;
  2205. }
  2206. if (isset($tableMapInfo['mapFieldNames'])) {
  2207. foreach ($tableMapInfo['mapFieldNames'] as $fieldName => $fieldMapInfo) {
  2208. if ($fieldMapInfo === $field) {
  2209. // Field name is mapped => use original name
  2210. $field = $fieldName;
  2211. }
  2212. }
  2213. }
  2214. }
  2215. return $this->cache_fieldType[$table][$field]['metaType'];
  2216. }
  2217. /**
  2218. * Get the type of the specified field in a result
  2219. *
  2220. * If the first parameter is a string, it is used as table name for the lookup.
  2221. *
  2222. * @param pointer MySQL result pointer (of SELECT query) / DBAL object / table name
  2223. * @param integer Field index. In case of ADOdb a string (field name!) FIXME
  2224. * @return string Returns the type of the specified field index
  2225. */
  2226. public function sql_field_type(&$res, $pointer) {
  2227. if ($res === null) {
  2228. debug(array('no res in sql_field_type!'));
  2229. return 'text';
  2230. }
  2231. elseif (is_string($res)) {
  2232. if ($res === 'tx_dbal_debuglog') return 'text';
  2233. $handlerType = 'adodb';
  2234. }
  2235. else {
  2236. $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
  2237. }
  2238. switch ($handlerType) {
  2239. case 'native':
  2240. $output = mysql_field_type($res, $pointer);
  2241. break;
  2242. case 'adodb':
  2243. if (is_string($pointer)) {
  2244. $output = $this->cache_fieldType[$res][$pointer]['type'];
  2245. }
  2246. break;
  2247. case 'userdefined':
  2248. $output = $res->sql_field_type($pointer);
  2249. break;
  2250. }
  2251. return $output;
  2252. }
  2253. /**********
  2254. *
  2255. * Legacy functions, bound to _DEFAULT handler. (Overriding parent methods)
  2256. * Deprecated or still experimental.
  2257. *
  2258. **********/
  2259. /**
  2260. * Executes query (on DEFAULT handler!)
  2261. * DEPRECATED - use exec_* functions from this class instead!
  2262. *
  2263. * @param string Database name
  2264. * @param string Query to execute
  2265. * @return pointer Result pointer
  2266. * @deprecated since TYPO3 4.1, will be removed in TYPO3 4.6
  2267. */
  2268. public function sql($db, $query) {
  2269. t3lib_div::logDeprecatedFunction();
  2270. return $this->sql_query($query);
  2271. }
  2272. /**
  2273. * Executes a query
  2274. * EXPERIMENTAL - This method will make its best to handle the query correctly
  2275. * but if it cannot, it will simply pass the query to DEFAULT handler.
  2276. *
  2277. * You should use exec_* function from this class instead!
  2278. * If you don't, anything that does not use the _DEFAULT handler will probably break!
  2279. *
  2280. * This method was deprecated in TYPO3 4.1 but is considered experimental since TYPO3 4.4
  2281. * as it tries to handle the query correctly anyway.
  2282. *
  2283. * @param string Query to execute
  2284. * @return pointer Result pointer / DBAL object
  2285. */
  2286. public function sql_query($query) {
  2287. $globalConfig = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['dbal']);
  2288. if ($globalConfig['sql_query.passthrough']) {
  2289. return parent::sql_query($query);
  2290. }
  2291. // This method is heavily used by Extbase, try to handle it with DBAL-native methods
  2292. $queryParts = $this->SQLparser->parseSQL($query);
  2293. if (is_array($queryParts) && t3lib_div::inList('SELECT,UPDATE,INSERT,DELETE', $queryParts['type'])) {
  2294. return $this->exec_query($queryParts);
  2295. }
  2296. switch ($this->handlerCfg['_DEFAULT']['type']) {
  2297. case 'native':
  2298. $sqlResult = mysql_query($query, $this->handlerInstance['_DEFAULT']['link']);
  2299. break;
  2300. case 'adodb':
  2301. $sqlResult = $this->handlerInstance['_DEFAULT']->Execute($query);
  2302. $sqlResult->TYPO3_DBAL_handlerType = 'adodb';
  2303. break;
  2304. case 'userdefined':
  2305. $sqlResult = $this->handlerInstance['_DEFAULT']->sql_query($query);
  2306. $sqlResult->TYPO3_DBAL_handlerType = 'userdefined';
  2307. break;
  2308. }
  2309. if ($this->printErrors && $this->sql_error()) {
  2310. debug(array($this->lastQuery, $this->sql_error()));
  2311. }
  2312. return $sqlResult;
  2313. }
  2314. /**
  2315. * Opening the _DEFAULT connection handler to the database.
  2316. * This is typically done by the scripts "init.php" in the backend or "index_ts.php" in the frontend (tslib_fe->connectToMySQL())
  2317. * You wouldn't need to use this at any time - let TYPO3 core handle this.
  2318. *
  2319. * @param string Database host IP/domain
  2320. * @param string Username to connect with.
  2321. * @param string Password to connect with.
  2322. * @return mixed Returns handler connection value
  2323. * @see handler_init()
  2324. */
  2325. public function sql_pconnect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password) {
  2326. // Overriding the _DEFAULT handler configuration of username, password, localhost and database name:
  2327. $this->handlerCfg['_DEFAULT']['config']['username'] = $TYPO3_db_username;
  2328. $this->handlerCfg['_DEFAULT']['config']['password'] = $TYPO3_db_password;
  2329. $this->handlerCfg['_DEFAULT']['config']['host'] = $TYPO3_db_host;
  2330. $this->handlerCfg['_DEFAULT']['config']['database'] = TYPO3_db;
  2331. // Initializing and output value:
  2332. $sqlResult = $this->handler_init('_DEFAULT');
  2333. return $sqlResult;
  2334. }
  2335. /**
  2336. * Select database for _DEFAULT handler.
  2337. *
  2338. * @param string Database to connect to.
  2339. * @return boolean Always returns TRUE; function is obsolete, database selection is made in handler_init() function!
  2340. */
  2341. public function sql_select_db($TYPO3_db) {
  2342. return TRUE;
  2343. }
  2344. /**************************************
  2345. *
  2346. * SQL admin functions
  2347. * (For use in the Install Tool and Extension Manager)
  2348. *
  2349. **************************************/
  2350. /**
  2351. * Listing databases from current MySQL connection. NOTICE: It WILL try to select those databases and thus break selection of current database.
  2352. * Use in Install Tool only!
  2353. * Usage count/core: 1
  2354. *
  2355. * @return array Each entry represents a database name
  2356. */
  2357. public function admin_get_dbs() {
  2358. $dbArr = array();
  2359. switch ($this->handlerCfg['_DEFAULT']['type']) {
  2360. case 'native':
  2361. $db_list = mysql_list_dbs($this->link);
  2362. while ($row = mysql_fetch_object($db_list)) {
  2363. if ($this->sql_select_db($row->Database)) {
  2364. $dbArr[] = $row->Database;
  2365. }
  2366. }
  2367. break;
  2368. case 'adodb':
  2369. // check needed for install tool - otherwise it will just die because the call to
  2370. // MetaDatabases is done on a stdClass instance
  2371. if (method_exists($this->handlerInstance['_DEFAULT'], 'MetaDatabases')) {
  2372. $sqlDBs = $this->handlerInstance['_DEFAULT']->MetaDatabases();
  2373. if (is_array($sqlDBs)) {
  2374. foreach ($sqlDBs as $k => $theDB) {
  2375. $dbArr[] = $theDB;
  2376. }
  2377. }
  2378. }
  2379. break;
  2380. case 'userdefined':
  2381. $dbArr = $this->handlerInstance['_DEFAULT']->admin_get_tables();
  2382. break;
  2383. }
  2384. return $dbArr;
  2385. }
  2386. /**
  2387. * Returns the list of tables from the system (quering the DBMSs)
  2388. * It looks up all tables from the DBMS of the _DEFAULT handler and then add all tables *configured* to be managed by other handlers
  2389. *
  2390. * When fetching the tables, it skips tables whose names begin with BIN$, as this is taken as a table coming from the "Recycle Bin" on Oracle.
  2391. *
  2392. * @return array Tables in an array (tablename is in both key and value)
  2393. * @todo Should the check for Oracle Recycle Bin stuff be moved elsewhere?
  2394. * @todo Should return table details in value! see t3lib_db::admin_get_tables()
  2395. */
  2396. public function admin_get_tables() {
  2397. $whichTables = array();
  2398. // Getting real list of tables:
  2399. switch ($this->handlerCfg['_DEFAULT']['type']) {
  2400. case 'native':
  2401. $tables_result = mysql_query('SHOW TABLE STATUS FROM `' . TYPO3_db . '`', $this->handlerInstance['_DEFAULT']['link']);
  2402. if (!$this->sql_error()) {
  2403. while ($theTable = $this->sql_fetch_assoc($tables_result)) {
  2404. $whichTables[$theTable['Name']] = $theTable;
  2405. }
  2406. }
  2407. break;
  2408. case 'adodb':
  2409. // check needed for install tool - otherwise it will just die because the call to
  2410. // MetaTables is done on a stdClass instance
  2411. if (method_exists($this->handlerInstance['_DEFAULT'], 'MetaTables')) {
  2412. $sqlTables = $this->handlerInstance['_DEFAULT']->MetaTables('TABLES');
  2413. while (list($k, $theTable) = each($sqlTables)) {
  2414. if (preg_match('/BIN\$/', $theTable)) continue; // skip tables from the Oracle 10 Recycle Bin
  2415. $whichTables[$theTable] = $theTable;
  2416. }
  2417. }
  2418. break;
  2419. case 'userdefined':
  2420. $whichTables = $this->handlerInstance['_DEFAULT']->admin_get_tables();
  2421. break;
  2422. }
  2423. // Check mapping:
  2424. if (is_array($this->mapping) && count($this->mapping)) {
  2425. // Mapping table names in reverse, first getting list of real table names:
  2426. $tMap = array();
  2427. foreach ($this->mapping as $tN => $tMapInfo) {
  2428. if (isset($tMapInfo['mapTableName'])) {
  2429. $tMap[$tMapInfo['mapTableName']] = $tN;
  2430. }
  2431. }
  2432. // Do mapping:
  2433. $newList = array();
  2434. foreach ($whichTables as $tN => $tDefinition) {
  2435. if (isset($tMap[$tN])) {
  2436. $tN = $tMap[$tN];
  2437. }
  2438. $newList[$tN] = $tDefinition;
  2439. }
  2440. $whichTables = $newList;
  2441. }
  2442. // Adding tables configured to reside in other DBMS (handler by other handlers than the default):
  2443. if (is_array($this->table2handlerKeys)) {
  2444. foreach ($this->table2handlerKeys as $key => $handlerKey) {
  2445. $whichTables[$key] = $key;
  2446. }
  2447. }
  2448. return $whichTables;
  2449. }
  2450. /**
  2451. * Returns information about each field in the $table (quering the DBMS)
  2452. * In a DBAL this should look up the right handler for the table and return compatible information
  2453. * This function is important not only for the Install Tool but probably for DBALs as well since they might need to look up table specific information in order to construct correct queries. In such cases this information should probably be cached for quick delivery
  2454. *
  2455. * @param string Table name
  2456. * @return array Field information in an associative array with fieldname => field row
  2457. */
  2458. public function admin_get_fields($tableName) {
  2459. $output = array();
  2460. // Do field mapping if needed:
  2461. $ORIG_tableName = $tableName;
  2462. if ($tableArray = $this->map_needMapping($tableName)) {
  2463. // Table name:
  2464. if ($this->mapping[$tableName]['mapTableName']) {
  2465. $tableName = $this->mapping[$tableName]['mapTableName'];
  2466. }
  2467. }
  2468. // Find columns
  2469. $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
  2470. switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
  2471. case 'native':
  2472. $columns_res = mysql_query('SHOW columns FROM ' . $tableName, $this->handlerInstance[$this->lastHandlerKey]['link']);
  2473. while ($fieldRow = mysql_fetch_assoc($columns_res)) {
  2474. $output[$fieldRow['Field']] = $fieldRow;
  2475. }
  2476. break;
  2477. case 'adodb':
  2478. $fieldRows = $this->handlerInstance[$this->lastHandlerKey]->MetaColumns($tableName, FALSE);
  2479. if (is_array($fieldRows)) {
  2480. foreach ($fieldRows as $k => $fieldRow) {
  2481. settype($fieldRow, 'array');
  2482. $fieldRow['Field'] = $fieldRow['name'];
  2483. $ntype = $this->MySQLActualType($this->MetaType($fieldRow['type'], $tableName));
  2484. $ntype .= (($fieldRow['max_length'] != -1) ? (($ntype == 'INT') ? '(11)' : '(' . $fieldRow['max_length'] . ')') : '');
  2485. $fieldRow['Type'] = strtolower($ntype);
  2486. $fieldRow['Null'] = '';
  2487. $fieldRow['Key'] = '';
  2488. $fieldRow['Default'] = $fieldRow['default_value'];
  2489. $fieldRow['Extra'] = '';
  2490. $output[$fieldRow['name']] = $fieldRow;
  2491. }
  2492. }
  2493. break;
  2494. case 'userdefined':
  2495. $output = $this->handlerInstance[$this->lastHandlerKey]->admin_get_fields($tableName);
  2496. break;
  2497. }
  2498. // mapping should be done:
  2499. if (is_array($tableArray) && is_array($this->mapping[$ORIG_tableName]['mapFieldNames'])) {
  2500. $revFields = array_flip($this->mapping[$ORIG_tableName]['mapFieldNames']);
  2501. $newOutput = array();
  2502. foreach ($output as $fN => $fInfo) {
  2503. if (isset($revFields[$fN])) {
  2504. $fN = $revFields[$fN];
  2505. $fInfo['Field'] = $fN;
  2506. }
  2507. $newOutput[$fN] = $fInfo;
  2508. }
  2509. $output = $newOutput;
  2510. }
  2511. return $output;
  2512. }
  2513. /**
  2514. * Returns information about each index key in the $table (quering the DBMS)
  2515. * In a DBAL this should look up the right handler for the table and return compatible information
  2516. *
  2517. * @param string Table name
  2518. * @return array Key information in a numeric array
  2519. */
  2520. public function admin_get_keys($tableName) {
  2521. $output = array();
  2522. // Do field mapping if needed:
  2523. $ORIG_tableName = $tableName;
  2524. if ($tableArray = $this->map_needMapping($tableName)) {
  2525. // Table name:
  2526. if ($this->mapping[$tableName]['mapTableName']) {
  2527. $tableName = $this->mapping[$tableName]['mapTableName'];
  2528. }
  2529. }
  2530. // Find columns
  2531. $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
  2532. switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
  2533. case 'native':
  2534. $keyRes = mysql_query('SHOW keys FROM ' . $tableName, $this->handlerInstance[$this->lastHandlerKey]['link']);
  2535. while ($keyRow = mysql_fetch_assoc($keyRes)) {
  2536. $output[] = $keyRow;
  2537. }
  2538. break;
  2539. case 'adodb':
  2540. $keyRows = $this->handlerInstance[$this->lastHandlerKey]->MetaIndexes($tableName);
  2541. if ($keyRows !== FALSE) {
  2542. while (list($k, $theKey) = each($keyRows)) {
  2543. $theKey['Table'] = $tableName;
  2544. $theKey['Non_unique'] = (int) !$theKey['unique'];
  2545. $theKey['Key_name'] = str_replace($tableName . '_', '', $k);
  2546. // the following are probably not needed anyway...
  2547. $theKey['Collation'] = '';
  2548. $theKey['Cardinality'] = '';
  2549. $theKey['Sub_part'] = '';
  2550. $theKey['Packed'] = '';
  2551. $theKey['Null'] = '';
  2552. $theKey['Index_type'] = '';
  2553. $theKey['Comment'] = '';
  2554. // now map multiple fields into multiple rows (we mimic MySQL, remember...)
  2555. $keycols = $theKey['columns'];
  2556. while (list($c, $theCol) = each($keycols)) {
  2557. $theKey['Seq_in_index'] = $c + 1;
  2558. $theKey['Column_name'] = $theCol;
  2559. $output[] = $theKey;
  2560. }
  2561. }
  2562. }
  2563. $priKeyRow = $this->handlerInstance[$this->lastHandlerKey]->MetaPrimaryKeys($tableName);
  2564. $theKey = array();
  2565. $theKey['Table'] = $tableName;
  2566. $theKey['Non_unique'] = 0;
  2567. $theKey['Key_name'] = 'PRIMARY';
  2568. // the following are probably not needed anyway...
  2569. $theKey['Collation'] = '';
  2570. $theKey['Cardinality'] = '';
  2571. $theKey['Sub_part'] = '';
  2572. $theKey['Packed'] = '';
  2573. $theKey['Null'] = '';
  2574. $theKey['Index_type'] = '';
  2575. $theKey['Comment'] = '';
  2576. // now map multiple fields into multiple rows (we mimic MySQL, remember...)
  2577. if ($priKeyRow !== FALSE) {
  2578. while (list($c, $theCol) = each($priKeyRow)) {
  2579. $theKey['Seq_in_index'] = $c + 1;
  2580. $theKey['Column_name'] = $theCol;
  2581. $output[] = $theKey;
  2582. }
  2583. }
  2584. break;
  2585. case 'userdefined':
  2586. $output = $this->handlerInstance[$this->lastHandlerKey]->admin_get_keys($tableName);
  2587. break;
  2588. }
  2589. // mapping should be done:
  2590. if (is_array($tableArray) && is_array($this->mapping[$ORIG_tableName]['mapFieldNames'])) {
  2591. $revFields = array_flip($this->mapping[$ORIG_tableName]['mapFieldNames']);
  2592. $newOutput = array();
  2593. foreach ($output as $kN => $kInfo) {
  2594. // Table:
  2595. $kInfo['Table'] = $ORIG_tableName;
  2596. // Column
  2597. if (isset($revFields[$kInfo['Column_name']])) {
  2598. $kInfo['Column_name'] = $revFields[$kInfo['Column_name']];
  2599. }
  2600. // Write it back:
  2601. $newOutput[$kN] = $kInfo;
  2602. }
  2603. $output = $newOutput;
  2604. }
  2605. return $output;
  2606. }
  2607. /**
  2608. * mysql() wrapper function, used by the Install Tool.
  2609. *
  2610. * @return array
  2611. */
  2612. public function admin_get_charsets() {
  2613. return array();
  2614. }
  2615. /**
  2616. * mysql() wrapper function, used by the Install Tool and EM for all queries regarding management of the database!
  2617. *
  2618. * @param string Query to execute
  2619. * @return pointer Result pointer
  2620. */
  2621. public function admin_query($query) {
  2622. $parsedQuery = $this->SQLparser->parseSQL($query);
  2623. $ORIG_table = $parsedQuery['TABLE'];
  2624. if (is_array($parsedQuery)) {
  2625. // Process query based on type:
  2626. switch ($parsedQuery['type']) {
  2627. case 'CREATETABLE':
  2628. case 'ALTERTABLE':
  2629. case 'DROPTABLE':
  2630. if (file_exists(PATH_typo3conf . 'temp_fieldInfo.php')) unlink(PATH_typo3conf . 'temp_fieldInfo.php');
  2631. $this->map_genericQueryParsed($parsedQuery);
  2632. break;
  2633. case 'INSERT':
  2634. case 'TRUNCATETABLE':
  2635. $this->map_genericQueryParsed($parsedQuery);
  2636. break;
  2637. case 'CREATEDATABASE':
  2638. die('Creating a database with DBAL is not supported. Did you really read the manual?');
  2639. break;
  2640. default:
  2641. die('ERROR: Invalid Query type (' . $parsedQuery['type'] . ') for ->admin_query() function!: "' . htmlspecialchars($query) . '"');
  2642. break;
  2643. }
  2644. // Setting query array (for other applications to access if needed)
  2645. $this->lastParsedAndMappedQueryArray = $parsedQuery;
  2646. // Execute query (based on handler derived from the TABLE name which we actually know for once!)
  2647. $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_table);
  2648. switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
  2649. case 'native':
  2650. // Compiling query:
  2651. $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
  2652. //if ($this->lastParsedAndMappedQueryArray['type'] == 'INSERT') {
  2653. // return mysql_query($compiledQuery, $this->link);
  2654. //}
  2655. return mysql_query($compiledQuery, $this->link);
  2656. break;
  2657. case 'adodb':
  2658. // Compiling query:
  2659. $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
  2660. switch ($this->lastParsedAndMappedQueryArray['type']) {
  2661. case 'INSERT':
  2662. return $this->exec_INSERTquery($this->lastParsedAndMappedQueryArray['TABLE'], $compiledQuery);
  2663. case 'TRUNCATETABLE':
  2664. return $this->exec_TRUNCATEquery($this->lastParsedAndMappedQueryArray['TABLE']);
  2665. }
  2666. return $this->handlerInstance[$this->lastHandlerKey]->DataDictionary->ExecuteSQLArray($compiledQuery);
  2667. break;
  2668. case 'userdefined':
  2669. // Compiling query:
  2670. $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
  2671. return $this->handlerInstance[$this->lastHandlerKey]->admin_query($compiledQuery);
  2672. break;
  2673. }
  2674. } else die('ERROR: Query could not be parsed: "' . htmlspecialchars($parsedQuery) . '". Query: "' . htmlspecialchars($query) . '"');
  2675. }
  2676. /************************************
  2677. *
  2678. * Handler management
  2679. *
  2680. **************************************/
  2681. /**
  2682. * Return the handler key pointing to an appropriate database handler as found in $this->handlerCfg array
  2683. * Notice: TWO or more tables in the table list MUST use the SAME handler key - otherwise a fatal error is thrown! (Logically, no database can possibly join two tables from separate sources!)
  2684. *
  2685. * @param string Table list, eg. "pages" or "pages, tt_content" or "pages AS A, tt_content AS B"
  2686. * @return string Handler key (see $this->handlerCfg array) for table
  2687. */
  2688. public function handler_getFromTableList($tableList) {
  2689. $key = $tableList;
  2690. if (!isset($this->cache_handlerKeyFromTableList[$key])) {
  2691. // Get tables separated:
  2692. $_tableList = $tableList;
  2693. $tableArray = $this->SQLparser->parseFromTables($_tableList);
  2694. // If success, traverse the tables:
  2695. if (is_array($tableArray) && count($tableArray)) {
  2696. $outputHandlerKey = '';
  2697. foreach ($tableArray as $vArray) {
  2698. // Find handler key, select "_DEFAULT" if none is specifically configured:
  2699. $handlerKey = $this->table2handlerKeys[$vArray['table']] ? $this->table2handlerKeys[$vArray['table']] : '_DEFAULT';
  2700. // In case of separate handler keys for joined tables:
  2701. if ($outputHandlerKey && $handlerKey != $outputHandlerKey) {
  2702. die('DBAL fatal error: Tables in this list "' . $tableList . '" didn\'t use the same DB handler!');
  2703. }
  2704. $outputHandlerKey = $handlerKey;
  2705. }
  2706. // Check initialized state; if handler is NOT initialized (connected) then we will connect it!
  2707. if (!isset($this->handlerInstance[$outputHandlerKey])) {
  2708. $this->handler_init($outputHandlerKey);
  2709. }
  2710. // Return handler key:
  2711. $this->cache_handlerKeyFromTableList[$key] = $outputHandlerKey;
  2712. } else {
  2713. die('DBAL fatal error: No handler found in handler_getFromTableList() for: "' . $tableList . '" (' . $tableArray . ')');
  2714. }
  2715. }
  2716. return $this->cache_handlerKeyFromTableList[$key];
  2717. }
  2718. /**
  2719. * Initialize handler (connecting to database)
  2720. *
  2721. * @param string Handler key
  2722. * @return boolean If connection went well, return TRUE
  2723. * @see handler_getFromTableList()
  2724. */
  2725. public function handler_init($handlerKey) {
  2726. // Find handler configuration:
  2727. $cfgArray = $this->handlerCfg[$handlerKey];
  2728. $handlerType = (string) $cfgArray['type'];
  2729. $output = FALSE;
  2730. if (is_array($cfgArray)) {
  2731. if (!$cfgArray['config']['database']) {
  2732. // Configuration is incomplete
  2733. return;
  2734. }
  2735. switch ($handlerType) {
  2736. case 'native':
  2737. if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect']) {
  2738. $link = mysql_connect($cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password'], TRUE);
  2739. } else {
  2740. $link = mysql_pconnect($cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password']);
  2741. }
  2742. // Set handler instance:
  2743. $this->handlerInstance[$handlerKey] = array('handlerType' => 'native', 'link' => $link);
  2744. // If link succeeded:
  2745. if ($link) {
  2746. // For default, set ->link (see t3lib_DB)
  2747. if ($handlerKey == '_DEFAULT') {
  2748. $this->link = $link;
  2749. }
  2750. // Select database as well:
  2751. if (mysql_select_db($cfgArray['config']['database'], $link)) {
  2752. $output = TRUE;
  2753. }
  2754. $setDBinit = t3lib_div::trimExplode(LF, str_replace("' . LF . '", LF, $GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit']), TRUE);
  2755. foreach ($setDBinit as $v) {
  2756. if (mysql_query($v, $link) === FALSE) {
  2757. t3lib_div::sysLog('Could not initialize DB connection with query "' . $v . '".', 'Core', 3);
  2758. }
  2759. }
  2760. } else {
  2761. t3lib_div::sysLog('Could not connect to MySQL server ' . $cfgArray['config']['host'] . ' with user ' . $cfgArray['config']['username'] . '.', 'Core', 4);
  2762. }
  2763. break;
  2764. case 'adodb':
  2765. $output = TRUE;
  2766. require_once(t3lib_extMgm::extPath('adodb') . 'adodb/adodb.inc.php');
  2767. if (!defined('ADODB_FORCE_NULLS')) define('ADODB_FORCE_NULLS', 1);
  2768. $GLOBALS['ADODB_FORCE_TYPE'] = ADODB_FORCE_VALUE;
  2769. $GLOBALS['ADODB_FETCH_MODE'] = ADODB_FETCH_BOTH;
  2770. $this->handlerInstance[$handlerKey] = &ADONewConnection($cfgArray['config']['driver']);
  2771. // Set driver-specific options
  2772. if (isset($cfgArray['config']['driverOptions'])) {
  2773. foreach ($cfgArray['config']['driverOptions'] as $optionName => $optionValue) {
  2774. $optionSetterName = 'set' . ucfirst($optionName);
  2775. if (method_exists($this->handlerInstance[$handlerKey], $optionSetterName)) {
  2776. $this->handlerInstance[$handlerKey]->$optionSetterName($optionValue);
  2777. } else {
  2778. $this->handlerInstance[$handlerKey]->$optionName = $optionValue;
  2779. }
  2780. }
  2781. }
  2782. if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect']) {
  2783. $this->handlerInstance[$handlerKey]->Connect($cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password'], $cfgArray['config']['database']);
  2784. } else {
  2785. $this->handlerInstance[$handlerKey]->PConnect($cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password'], $cfgArray['config']['database']);
  2786. }
  2787. if (!$this->handlerInstance[$handlerKey]->isConnected()) {
  2788. $dsn = $cfgArray['config']['driver'] . '://' . $cfgArray['config']['username'] .
  2789. (strlen($cfgArray['config']['password']) ? ':XXXX@' : '') .
  2790. $cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : '') . '/' . $cfgArray['config']['database'] .
  2791. ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect'] ? '' : '?persistent=1');
  2792. t3lib_div::sysLog('Could not connect to DB server using ADOdb on ' . $cfgArray['config']['host'] . ' with user ' . $cfgArray['config']['username'] . '.', 'Core', 4);
  2793. error_log('DBAL error: Connection to ' . $dsn . ' failed. Maybe PHP doesn\'t support the database?');
  2794. $output = FALSE;
  2795. } else {
  2796. $this->handlerInstance[$handlerKey]->DataDictionary = NewDataDictionary($this->handlerInstance[$handlerKey]);
  2797. $this->handlerInstance[$handlerKey]->last_insert_id = 0;
  2798. if (isset($cfgArray['config']['sequenceStart'])) {
  2799. $this->handlerInstance[$handlerKey]->sequenceStart = $cfgArray['config']['sequenceStart'];
  2800. } else {
  2801. $this->handlerInstance[$handlerKey]->sequenceStart = 1;
  2802. }
  2803. }
  2804. break;
  2805. case 'userdefined':
  2806. // Find class file:
  2807. $fileName = t3lib_div::getFileAbsFileName($cfgArray['config']['classFile']);
  2808. if (@is_file($fileName)) {
  2809. require_once($fileName);
  2810. } else die('DBAL error: "' . $fileName . '" was not a file to include.');
  2811. // Initialize:
  2812. $this->handlerInstance[$handlerKey] = t3lib_div::makeInstance($cfgArray['config']['class']);
  2813. $this->handlerInstance[$handlerKey]->init($cfgArray, $this);
  2814. if (is_object($this->handlerInstance[$handlerKey])) {
  2815. $output = TRUE;
  2816. }
  2817. break;
  2818. default:
  2819. die('ERROR: Invalid handler type: "' . $cfgArray['type'] . '"');
  2820. break;
  2821. }
  2822. return $output;
  2823. } else die('ERROR: No handler for key "' . $handlerKey . '"');
  2824. }
  2825. /**
  2826. * Checks if database is connected.
  2827. *
  2828. * @return boolean
  2829. */
  2830. public function isConnected() {
  2831. $result = FALSE;
  2832. switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
  2833. case 'native':
  2834. $result = is_resource($this->link);
  2835. break;
  2836. case 'adodb':
  2837. case 'userdefined':
  2838. $result = is_object($this->handlerInstance[$this->lastHandlerKey]) && $this->handlerInstance[$this->lastHandlerKey]->isConnected();
  2839. break;
  2840. }
  2841. return $result;
  2842. }
  2843. /**
  2844. * Checks whether the DBAL is currently inside an operation running on the "native" DB handler (i.e. MySQL)
  2845. *
  2846. * @return boolean True if running on "native" DB handler (i.e. MySQL)
  2847. */
  2848. public function runningNative() {
  2849. return ((string) $this->handlerCfg[$this->lastHandlerKey]['type']==='native');
  2850. }
  2851. /**
  2852. * Checks whether the ADOdb handler is running with a driver that contains the argument
  2853. *
  2854. * @param string $driver Driver name, matched with strstr().
  2855. * @return boolean True if running with the given driver
  2856. */
  2857. public function runningADOdbDriver($driver) {
  2858. return strstr($this->handlerCfg[$this->lastHandlerKey]['config']['driver'], $driver);
  2859. }
  2860. /************************************
  2861. *
  2862. * Table/Field mapping
  2863. *
  2864. **************************************/
  2865. /**
  2866. * Checks if mapping is needed for a table(list)
  2867. *
  2868. * @param string List of tables in query
  2869. * @param boolean If TRUE, it will check only if FIELDs are configured and ignore the mapped table name if any.
  2870. * @param array Parsed list of tables, should be passed as reference to be reused and prevent double parsing
  2871. * @return mixed Returns an array of table names (parsed version of input table) if mapping is needed, otherwise just FALSE.
  2872. */
  2873. protected function map_needMapping($tableList, $fieldMappingOnly = FALSE, array &$parsedTableList = array()) {
  2874. $key = $tableList . '|' . $fieldMappingOnly;
  2875. if (!isset($this->cache_mappingFromTableList[$key])) {
  2876. $this->cache_mappingFromTableList[$key] = FALSE; // Default:
  2877. $tables = $this->SQLparser->parseFromTables($tableList);
  2878. if (is_array($tables)) {
  2879. $parsedTableList = $tables;
  2880. foreach ($tables as $tableCfg) {
  2881. if ($fieldMappingOnly) {
  2882. if (is_array($this->mapping[$tableCfg['table']]['mapFieldNames'])) {
  2883. $this->cache_mappingFromTableList[$key] = $tables;
  2884. } elseif (is_array($tableCfg['JOIN'])) {
  2885. foreach ($tableCfg['JOIN'] as $join) {
  2886. if (is_array($this->mapping[$join['withTable']]['mapFieldNames'])) {
  2887. $this->cache_mappingFromTableList[$key] = $tables;
  2888. break;
  2889. }
  2890. }
  2891. }
  2892. } else {
  2893. if (is_array($this->mapping[$tableCfg['table']])) {
  2894. $this->cache_mappingFromTableList[$key] = $tables;
  2895. } elseif (is_array($tableCfg['JOIN'])) {
  2896. foreach ($tableCfg['JOIN'] as $join) {
  2897. if (is_array($this->mapping[$join['withTable']])) {
  2898. $this->cache_mappingFromTableList[$key] = $tables;
  2899. break;
  2900. }
  2901. }
  2902. }
  2903. }
  2904. }
  2905. }
  2906. }
  2907. return $this->cache_mappingFromTableList[$key];
  2908. }
  2909. /**
  2910. * Takes an associated array with field => value pairs and remaps the field names if configured for this table in $this->mapping array.
  2911. * Be careful not to map a field name to another existing fields name (although you can use this to swap fieldnames of course...:-)
  2912. * Observe mapping problems with join-results (more than one table): Joined queries should always prefix the table name to avoid problems with this.
  2913. * Observe that alias fields are not mapped of course (should not be a problem though)
  2914. *
  2915. * @param array Input array, associative keys
  2916. * @param array Array of tables from the query. Normally just one table; many tables in case of a join. NOTICE: for multiple tables (with joins) there MIGHT occur trouble with fields of the same name in the two tables: This function traverses the mapping information for BOTH tables and applies mapping without checking from which table the field really came!
  2917. * @param boolean If TRUE, reverse direction. Default direction is to map an array going INTO the database (thus mapping TYPO3 fieldnames to PHYSICAL field names!)
  2918. * @return array Output array, with mapped associative keys.
  2919. */
  2920. protected function map_assocArray($input, $tables, $rev = FALSE) {
  2921. // Traverse tables from query (hopefully only one table):
  2922. foreach ($tables as $tableCfg) {
  2923. $tableKey = $this->getMappingKey($tableCfg['table']);
  2924. if (is_array($this->mapping[$tableKey]['mapFieldNames'])) {
  2925. // Get the map (reversed if needed):
  2926. if ($rev) {
  2927. $theMap = array_flip($this->mapping[$tableKey]['mapFieldNames']);
  2928. } else {
  2929. $theMap = $this->mapping[$tableKey]['mapFieldNames'];
  2930. }
  2931. // Traverse selected record, map fieldnames:
  2932. $output = array();
  2933. foreach ($input as $fN => $value) {
  2934. // Set the field name, change it if found in mapping array:
  2935. if ($theMap[$fN]) {
  2936. $newKey = $theMap[$fN];
  2937. } else {
  2938. $newKey = $fN;
  2939. }
  2940. // Set value to fieldname:
  2941. $output[$newKey] = $value;
  2942. }
  2943. // When done, override the $input array with the result:
  2944. $input = $output;
  2945. }
  2946. }
  2947. // Return input array (which might have been altered in the mean time)
  2948. return $input;
  2949. }
  2950. /**
  2951. * Remaps table/field names in a SELECT query's parts
  2952. *
  2953. * @param mixed Either parsed list of tables (SQLparser->parseFromTables()) or list of fields to select from the table. This is what comes right after "SELECT ...". Required value.
  2954. * @param string Table(s) from which to select. This is what comes right after "FROM ...". Require value.
  2955. * @param string Where clause. This is what comes right after "WHERE ...". Can be blank.
  2956. * @param string Group by field(s)
  2957. * @param string Order by field(s)
  2958. * @return void
  2959. * @see exec_SELECTquery()
  2960. */
  2961. protected function map_remapSELECTQueryParts($select_fields, $from_table, $where_clause, $groupBy, $orderBy) {
  2962. // Backup current mapping as it may be altered if aliases on mapped tables are found
  2963. $backupMapping = $this->mapping;
  2964. // Tables:
  2965. $tables = is_array($from_table) ? $from_table : $this->SQLparser->parseFromTables($from_table);
  2966. $defaultTable = $tables[0]['table'];
  2967. // Prepare mapping for aliased tables. This will copy the definition of the original table name.
  2968. // The alias is prefixed with a database-incompatible character to prevent naming clash with real table name
  2969. // Further access to $this->mapping should be made through $this->getMappingKey() method
  2970. foreach ($tables as $k => $v) {
  2971. if ($v['as'] && is_array($this->mapping[$v['table']]['mapFieldNames'])) {
  2972. $mappingKey = $this->getFreeMappingKey($v['as']);
  2973. $this->mapping[$mappingKey]['mapFieldNames'] =& $this->mapping[$v['table']]['mapFieldNames'];
  2974. }
  2975. if (is_array($v['JOIN'])) {
  2976. foreach ($v['JOIN'] as $joinCnt => $join) {
  2977. if ($join['as'] && is_array($this->mapping[$join['withTable']]['mapFieldNames'])) {
  2978. $mappingKey = $this->getFreeMappingKey($join['as']);
  2979. $this->mapping[$mappingKey]['mapFieldNames'] =& $this->mapping[$join['withTable']]['mapFieldNames'];
  2980. }
  2981. }
  2982. }
  2983. }
  2984. foreach ($tables as $k => $v) {
  2985. $tableKey = $this->getMappingKey($v['table']);
  2986. if ($this->mapping[$tableKey]['mapTableName']) {
  2987. $tables[$k]['table'] = $this->mapping[$tableKey]['mapTableName'];
  2988. }
  2989. // Mapping JOINS
  2990. if (is_array($v['JOIN'])) {
  2991. foreach ($v['JOIN'] as $joinCnt => $join) {
  2992. // Mapping withTable of the JOIN
  2993. $withTableKey = $this->getMappingKey($join['withTable']);
  2994. if ($this->mapping[$withTableKey]['mapTableName']) {
  2995. $tables[$k]['JOIN'][$joinCnt]['withTable'] = $this->mapping[$withTableKey]['mapTableName'];
  2996. }
  2997. $onPartsArray = array();
  2998. // Mapping ON parts of the JOIN
  2999. if (is_array($tables[$k]['JOIN'][$joinCnt]['ON'])) {
  3000. foreach ($tables[$k]['JOIN'][$joinCnt]['ON'] as &$condition) {
  3001. // Left side of the comparator
  3002. $leftTableKey = $this->getMappingKey($condition['left']['table']);
  3003. if (isset($this->mapping[$leftTableKey]['mapFieldNames'][$condition['left']['field']])) {
  3004. $condition['left']['field'] = $this->mapping[$leftTableKey]['mapFieldNames'][$condition['left']['field']];
  3005. }
  3006. if (isset($this->mapping[$leftTableKey]['mapTableName'])) {
  3007. $condition['left']['table'] = $this->mapping[$leftTableKey]['mapTableName'];
  3008. }
  3009. // Right side of the comparator
  3010. $rightTableKey = $this->getMappingKey($condition['right']['table']);
  3011. if (isset($this->mapping[$rightTableKey]['mapFieldNames'][$condition['right']['field']])) {
  3012. $condition['right']['field'] = $this->mapping[$rightTableKey]['mapFieldNames'][$condition['right']['field']];
  3013. }
  3014. if (isset($this->mapping[$rightTableKey]['mapTableName'])) {
  3015. $condition['right']['table'] = $this->mapping[$rightTableKey]['mapTableName'];
  3016. }
  3017. }
  3018. }
  3019. }
  3020. }
  3021. }
  3022. $fromParts = $tables;
  3023. // Where clause:
  3024. $parameterReferences = array();
  3025. $whereParts = $this->SQLparser->parseWhereClause($where_clause, '', $parameterReferences);
  3026. $this->map_sqlParts($whereParts, $defaultTable);
  3027. // Select fields:
  3028. $selectParts = $this->SQLparser->parseFieldList($select_fields);
  3029. $this->map_sqlParts($selectParts, $defaultTable);
  3030. // Group By fields
  3031. $groupByParts = $this->SQLparser->parseFieldList($groupBy);
  3032. $this->map_sqlParts($groupByParts, $defaultTable);
  3033. // Order By fields
  3034. $orderByParts = $this->SQLparser->parseFieldList($orderBy);
  3035. $this->map_sqlParts($orderByParts, $defaultTable);
  3036. // Restore the original mapping
  3037. $this->mapping = $backupMapping;
  3038. return array($selectParts, $fromParts, $whereParts, $groupByParts, $orderByParts, $parameterReferences);
  3039. }
  3040. /**
  3041. * Returns the key to be used when retrieving information from $this->mapping. This ensures
  3042. * that mapping from aliased tables is properly retrieved.
  3043. *
  3044. * @param string $tableName
  3045. * @return string
  3046. */
  3047. protected function getMappingKey($tableName) {
  3048. // Search deepest alias mapping
  3049. while (isset($this->mapping['*' . $tableName])) {
  3050. $tableName = '*' . $tableName;
  3051. }
  3052. return $tableName;
  3053. }
  3054. /**
  3055. * Returns a free key to be used to store mapping information in $this->mapping.
  3056. *
  3057. * @param string $tableName
  3058. * @return string
  3059. */
  3060. protected function getFreeMappingKey($tableName) {
  3061. while (isset($this->mapping[$tableName])) {
  3062. $tableName = '*' . $tableName;
  3063. }
  3064. return $tableName;
  3065. }
  3066. /**
  3067. * Generic mapping of table/field names arrays (as parsed by tx_dbal_sqlengine)
  3068. *
  3069. * @param array Array with parsed SQL parts; Takes both fields, tables, where-parts, group and order-by. Passed by reference.
  3070. * @param string Default table name to assume if no table is found in $sqlPartArray
  3071. * @return void
  3072. * @access private
  3073. * @see map_remapSELECTQueryParts()
  3074. */
  3075. protected function map_sqlParts(&$sqlPartArray, $defaultTable) {
  3076. $defaultTableKey = $this->getMappingKey($defaultTable);
  3077. // Traverse sql Part array:
  3078. if (is_array($sqlPartArray)) {
  3079. foreach ($sqlPartArray as $k => $v) {
  3080. if (isset($sqlPartArray[$k]['type'])) {
  3081. switch ($sqlPartArray[$k]['type']) {
  3082. case 'flow-control':
  3083. $temp = array($sqlPartArray[$k]['flow-control']);
  3084. $this->map_sqlParts($temp, $defaultTable); // Call recursively!
  3085. $sqlPartArray[$k]['flow-control'] = $temp[0];
  3086. break;
  3087. case 'CASE':
  3088. if (isset($sqlPartArray[$k]['case_field'])) {
  3089. $fieldArray = explode('.', $sqlPartArray[$k]['case_field']);
  3090. if (count($fieldArray) == 1 && is_array($this->mapping[$defaultTableKey]['mapFieldNames']) && isset($this->mapping[$defaultTableKey]['mapFieldNames'][$fieldArray[0]])) {
  3091. $sqlPartArray[$k]['case_field'] = $this->mapping[$defaultTableKey]['mapFieldNames'][$fieldArray[0]];
  3092. }
  3093. elseif (count($fieldArray) == 2) {
  3094. // Map the external table
  3095. $table = $fieldArray[0];
  3096. $tableKey = $this->getMappingKey($table);
  3097. if (isset($this->mapping[$tableKey]['mapTableName'])) {
  3098. $table = $this->mapping[$tableKey]['mapTableName'];
  3099. }
  3100. // Map the field itself
  3101. $field = $fieldArray[1];
  3102. if (is_array($this->mapping[$tableKey]['mapFieldNames']) && isset($this->mapping[$tableKey]['mapFieldNames'][$fieldArray[1]])) {
  3103. $field = $this->mapping[$tableKey]['mapFieldNames'][$fieldArray[1]];
  3104. }
  3105. $sqlPartArray[$k]['case_field'] = $table . '.' . $field;
  3106. }
  3107. }
  3108. foreach ($sqlPartArray[$k]['when'] as $key => $when) {
  3109. $this->map_sqlParts($sqlPartArray[$k]['when'][$key]['when_value'], $defaultTable);
  3110. }
  3111. break;
  3112. }
  3113. }
  3114. // Look for sublevel (WHERE parts only)
  3115. if (is_array($sqlPartArray[$k]['sub'])) {
  3116. $this->map_sqlParts($sqlPartArray[$k]['sub'], $defaultTable); // Call recursively!
  3117. } elseif (isset($sqlPartArray[$k]['func'])) {
  3118. switch ($sqlPartArray[$k]['func']['type']) {
  3119. case 'EXISTS':
  3120. $this->map_subquery($sqlPartArray[$k]['func']['subquery']);
  3121. break;
  3122. case 'FIND_IN_SET':
  3123. case 'IFNULL':
  3124. case 'LOCATE':
  3125. // For the field, look for table mapping (generic):
  3126. $t = $sqlPartArray[$k]['func']['table'] ? $sqlPartArray[$k]['func']['table'] : $defaultTable;
  3127. $t = $this->getMappingKey($t);
  3128. if (is_array($this->mapping[$t]['mapFieldNames']) && $this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['func']['field']]) {
  3129. $sqlPartArray[$k]['func']['field'] = $this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['func']['field']];
  3130. }
  3131. if ($this->mapping[$t]['mapTableName']) {
  3132. $sqlPartArray[$k]['func']['table'] = $this->mapping[$t]['mapTableName'];
  3133. }
  3134. break;
  3135. }
  3136. } else {
  3137. // For the field, look for table mapping (generic):
  3138. $t = $sqlPartArray[$k]['table'] ? $sqlPartArray[$k]['table'] : $defaultTable;
  3139. $t = $this->getMappingKey($t);
  3140. // Mapping field name, if set:
  3141. if (is_array($this->mapping[$t]['mapFieldNames']) && isset($this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['field']])) {
  3142. $sqlPartArray[$k]['field'] = $this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['field']];
  3143. }
  3144. // Mapping field name in SQL-functions like MIN(), MAX() or SUM()
  3145. if ($this->mapping[$t]['mapFieldNames']) {
  3146. $fieldArray = explode('.', $sqlPartArray[$k]['func_content']);
  3147. if (count($fieldArray) == 1 && is_array($this->mapping[$t]['mapFieldNames']) && isset($this->mapping[$t]['mapFieldNames'][$fieldArray[0]])) {
  3148. $sqlPartArray[$k]['func_content.'][0]['func_content'] = $this->mapping[$t]['mapFieldNames'][$fieldArray[0]];
  3149. $sqlPartArray[$k]['func_content'] = $this->mapping[$t]['mapFieldNames'][$fieldArray[0]];
  3150. }
  3151. elseif (count($fieldArray) == 2) {
  3152. // Map the external table
  3153. $table = $fieldArray[0];
  3154. $tableKey = $this->getMappingKey($table);
  3155. if (isset($this->mapping[$tableKey]['mapTableName'])) {
  3156. $table = $this->mapping[$tableKey]['mapTableName'];
  3157. }
  3158. // Map the field itself
  3159. $field = $fieldArray[1];
  3160. if (is_array($this->mapping[$tableKey]['mapFieldNames']) && isset($this->mapping[$tableKey]['mapFieldNames'][$fieldArray[1]])) {
  3161. $field = $this->mapping[$tableKey]['mapFieldNames'][$fieldArray[1]];
  3162. }
  3163. $sqlPartArray[$k]['func_content.'][0]['func_content'] = $table . '.' . $field;
  3164. $sqlPartArray[$k]['func_content'] = $table . '.' . $field;
  3165. }
  3166. // Mapping flow-control statements
  3167. if (isset($sqlPartArray[$k]['flow-control'])) {
  3168. if (isset($sqlPartArray[$k]['flow-control']['type'])) {
  3169. $temp = array($sqlPartArray[$k]['flow-control']);
  3170. $this->map_sqlParts($temp, $t); // Call recursively!
  3171. $sqlPartArray[$k]['flow-control'] = $temp[0];
  3172. }
  3173. }
  3174. }
  3175. // Do we have a function (e.g., CONCAT)
  3176. if (isset($v['value']['operator'])) {
  3177. foreach ($sqlPartArray[$k]['value']['args'] as $argK => $fieldDef) {
  3178. $tableKey = $this->getMappingKey($fieldDef['table']);
  3179. if (isset($this->mapping[$tableKey]['mapTableName'])) {
  3180. $sqlPartArray[$k]['value']['args'][$argK]['table'] = $this->mapping[$tableKey]['mapTableName'];
  3181. }
  3182. if (is_array($this->mapping[$tableKey]['mapFieldNames']) && isset($this->mapping[$tableKey]['mapFieldNames'][$fieldDef['field']])) {
  3183. $sqlPartArray[$k]['value']['args'][$argK]['field'] = $this->mapping[$tableKey]['mapFieldNames'][$fieldDef['field']];
  3184. }
  3185. }
  3186. }
  3187. // Do we have a subquery (WHERE parts only)?
  3188. if (isset($sqlPartArray[$k]['subquery'])) {
  3189. $this->map_subquery($sqlPartArray[$k]['subquery']);
  3190. }
  3191. // do we have a field name in the value?
  3192. // this is a very simplistic check, beware
  3193. if (!is_numeric($sqlPartArray[$k]['value'][0]) && !isset($sqlPartArray[$k]['value'][1])) {
  3194. $fieldArray = explode('.', $sqlPartArray[$k]['value'][0]);
  3195. if (count($fieldArray) == 1 && is_array($this->mapping[$t]['mapFieldNames']) && isset($this->mapping[$t]['mapFieldNames'][$fieldArray[0]])) {
  3196. $sqlPartArray[$k]['value'][0] = $this->mapping[$t]['mapFieldNames'][$fieldArray[0]];
  3197. } elseif (count($fieldArray) == 2) {
  3198. // Map the external table
  3199. $table = $fieldArray[0];
  3200. $tableKey = $this->getMappingKey($table);
  3201. if (isset($this->mapping[$tableKey]['mapTableName'])) {
  3202. $table = $this->mapping[$tableKey]['mapTableName'];
  3203. }
  3204. // Map the field itself
  3205. $field = $fieldArray[1];
  3206. if (is_array($this->mapping[$tableKey]['mapFieldNames']) && isset($this->mapping[$tableKey]['mapFieldNames'][$fieldArray[1]])) {
  3207. $field = $this->mapping[$tableKey]['mapFieldNames'][$fieldArray[1]];
  3208. }
  3209. $sqlPartArray[$k]['value'][0] = $table . '.' . $field;
  3210. }
  3211. }
  3212. // Map table?
  3213. $tableKey = $this->getMappingKey($sqlPartArray[$k]['table']);
  3214. if ($sqlPartArray[$k]['table'] && $this->mapping[$tableKey]['mapTableName']) {
  3215. $sqlPartArray[$k]['table'] = $this->mapping[$tableKey]['mapTableName'];
  3216. }
  3217. }
  3218. }
  3219. }
  3220. }
  3221. /**
  3222. * Maps table and field names in a subquery.
  3223. *
  3224. * @param array $parsedQuery
  3225. * @return void
  3226. */
  3227. protected function map_subquery(&$parsedQuery) {
  3228. // Backup current mapping as it may be altered
  3229. $backupMapping = $this->mapping;
  3230. foreach ($parsedQuery['FROM'] as $k => $v) {
  3231. $mappingKey = $v['table'];
  3232. if ($v['as'] && is_array($this->mapping[$v['table']]['mapFieldNames'])) {
  3233. $mappingKey = $this->getFreeMappingKey($v['as']);
  3234. } else {
  3235. // Should ensure that no alias is defined in the external query
  3236. // which would correspond to a real table name in the subquery
  3237. if ($this->getMappingKey($v['table']) !== $v['table']) {
  3238. $mappingKey = $this->getFreeMappingKey($v['table']);
  3239. // This is the only case when 'mapTableName' should be copied
  3240. $this->mapping[$mappingKey]['mapTableName'] =& $this->mapping[$v['table']]['mapTableName'];
  3241. }
  3242. }
  3243. if ($mappingKey !== $v['table']) {
  3244. $this->mapping[$mappingKey]['mapFieldNames'] =& $this->mapping[$v['table']]['mapFieldNames'];
  3245. }
  3246. }
  3247. // Perform subquery's remapping
  3248. $defaultTable = $parsedQuery['FROM'][0]['table'];
  3249. $this->map_sqlParts($parsedQuery['SELECT'], $defaultTable);
  3250. $this->map_sqlParts($parsedQuery['FROM'], $defaultTable);
  3251. $this->map_sqlParts($parsedQuery['WHERE'], $defaultTable);
  3252. // Restore the mapping
  3253. $this->mapping = $backupMapping;
  3254. }
  3255. /**
  3256. * Will do table/field mapping on a general tx_dbal_sqlengine-compliant SQL query
  3257. * (May still not support all query types...)
  3258. *
  3259. * @param array Parsed QUERY as from tx_dbal_sqlengine::parseSQL(). NOTICE: Passed by reference!
  3260. * @return void
  3261. * @see tx_dbal_sqlengine::parseSQL()
  3262. */
  3263. protected function map_genericQueryParsed(&$parsedQuery) {
  3264. // Getting table - same for all:
  3265. $table = $parsedQuery['TABLE'];
  3266. if ($table) {
  3267. // Do field mapping if needed:
  3268. if ($tableArray = $this->map_needMapping($table)) {
  3269. // Table name:
  3270. if ($this->mapping[$table]['mapTableName']) {
  3271. $parsedQuery['TABLE'] = $this->mapping[$table]['mapTableName'];
  3272. }
  3273. // Based on type, do additional changes:
  3274. switch ($parsedQuery['type']) {
  3275. case 'ALTERTABLE':
  3276. // Changing field name:
  3277. $newFieldName = $this->mapping[$table]['mapFieldNames'][$parsedQuery['FIELD']];
  3278. if ($newFieldName) {
  3279. if ($parsedQuery['FIELD'] == $parsedQuery['newField']) {
  3280. $parsedQuery['FIELD'] = $parsedQuery['newField'] = $newFieldName;
  3281. } else $parsedQuery['FIELD'] = $newFieldName;
  3282. }
  3283. // Changing key field names:
  3284. if (is_array($parsedQuery['fields'])) {
  3285. $this->map_fieldNamesInArray($table, $parsedQuery['fields']);
  3286. }
  3287. break;
  3288. case 'CREATETABLE':
  3289. // Remapping fields:
  3290. if (is_array($parsedQuery['FIELDS'])) {
  3291. $newFieldsArray = array();
  3292. foreach ($parsedQuery['FIELDS'] as $fN => $fInfo) {
  3293. if ($this->mapping[$table]['mapFieldNames'][$fN]) {
  3294. $fN = $this->mapping[$table]['mapFieldNames'][$fN];
  3295. }
  3296. $newFieldsArray[$fN] = $fInfo;
  3297. }
  3298. $parsedQuery['FIELDS'] = $newFieldsArray;
  3299. }
  3300. // Remapping keys:
  3301. if (is_array($parsedQuery['KEYS'])) {
  3302. foreach ($parsedQuery['KEYS'] as $kN => $kInfo) {
  3303. $this->map_fieldNamesInArray($table, $parsedQuery['KEYS'][$kN]);
  3304. }
  3305. }
  3306. break;
  3307. /// ... and here support for all other query types should be!
  3308. }
  3309. }
  3310. } else die('ERROR, mapping: No table found in parsed Query array...');
  3311. }
  3312. /**
  3313. * Re-mapping field names in array
  3314. *
  3315. * @param string (TYPO3) Table name for fields.
  3316. * @param array Array of fieldnames to remap. Notice: Passed by reference!
  3317. * @return void
  3318. */
  3319. protected function map_fieldNamesInArray($table, &$fieldArray) {
  3320. if (is_array($this->mapping[$table]['mapFieldNames'])) {
  3321. foreach ($fieldArray as $k => $v) {
  3322. if ($this->mapping[$table]['mapFieldNames'][$v]) {
  3323. $fieldArray[$k] = $this->mapping[$table]['mapFieldNames'][$v];
  3324. }
  3325. }
  3326. }
  3327. }
  3328. /**************************************
  3329. *
  3330. * Debugging
  3331. *
  3332. **************************************/
  3333. /**
  3334. * Debug handler for query execution
  3335. *
  3336. * @param string Function name from which this function is called.
  3337. * @param string Execution time in ms of the query
  3338. * @param array In-data of various kinds.
  3339. * @return void
  3340. * @access private
  3341. */
  3342. public function debugHandler($function, $execTime, $inData) {
  3343. // we don't want to log our own log/debug SQL
  3344. $script = substr(PATH_thisScript, strlen(PATH_site));
  3345. if (substr($script, -strlen('dbal/mod1/index.php')) != 'dbal/mod1/index.php' && !strstr($inData['args'][0], 'tx_dbal_debuglog')) {
  3346. $data = array();
  3347. $errorFlag = 0;
  3348. $joinTable = '';
  3349. if ($this->sql_error()) {
  3350. $data['sqlError'] = $this->sql_error();
  3351. $errorFlag |= 1;
  3352. }
  3353. // if lastQuery is empty (for whatever reason) at least log inData.args
  3354. if (empty($this->lastQuery)) {
  3355. $query = implode(' ', $inData['args']);
  3356. } else {
  3357. $query = $this->lastQuery;
  3358. }
  3359. if ($this->conf['debugOptions']['numberRows']) {
  3360. switch ($function) {
  3361. case 'exec_INSERTquery':
  3362. case 'exec_UPDATEquery':
  3363. case 'exec_DELETEquery':
  3364. $data['numberRows'] = $this->sql_affected_rows();
  3365. break;
  3366. case 'exec_SELECTquery':
  3367. $data['numberRows'] = $inData['numberRows'];
  3368. break;
  3369. }
  3370. }
  3371. if ($this->conf['debugOptions']['backtrace']) {
  3372. $backtrace = debug_backtrace();
  3373. unset($backtrace[0]); // skip this very method :)
  3374. $data['backtrace'] = array_slice($backtrace, 0, $this->conf['debugOptions']['backtrace']);
  3375. }
  3376. switch ($function) {
  3377. case 'exec_INSERTquery':
  3378. case 'exec_UPDATEquery':
  3379. case 'exec_DELETEquery':
  3380. $this->debug_log($query, $execTime, $data, $joinTable, $errorFlag, $script);
  3381. break;
  3382. case 'exec_SELECTquery':
  3383. // Get explain data:
  3384. if ($this->conf['debugOptions']['EXPLAIN'] && t3lib_div::inList('adodb,native', $inData['handlerType'])) {
  3385. $data['EXPLAIN'] = $this->debug_explain($this->lastQuery);
  3386. }
  3387. // Check parsing of Query:
  3388. if ($this->conf['debugOptions']['parseQuery']) {
  3389. $parseResults = array();
  3390. $parseResults['SELECT'] = $this->SQLparser->debug_parseSQLpart('SELECT', $inData['args'][1]);
  3391. $parseResults['FROM'] = $this->SQLparser->debug_parseSQLpart('FROM', $inData['args'][0]);
  3392. $parseResults['WHERE'] = $this->SQLparser->debug_parseSQLpart('WHERE', $inData['args'][2]);
  3393. $parseResults['GROUPBY'] = $this->SQLparser->debug_parseSQLpart('SELECT', $inData['args'][3]); // Using select field list syntax
  3394. $parseResults['ORDERBY'] = $this->SQLparser->debug_parseSQLpart('SELECT', $inData['args'][4]); // Using select field list syntax
  3395. foreach ($parseResults as $k => $v) {
  3396. if (!strlen($parseResults[$k])) unset($parseResults[$k]);
  3397. }
  3398. if (count($parseResults)) {
  3399. $data['parseError'] = $parseResults;
  3400. $errorFlag |= 2;
  3401. }
  3402. }
  3403. // Checking joinTables:
  3404. if ($this->conf['debugOptions']['joinTables']) {
  3405. if (count(explode(',', $inData['ORIG_from_table'])) > 1) {
  3406. $joinTable = $inData['args'][0];
  3407. }
  3408. }
  3409. // Logging it:
  3410. $this->debug_log($query, $execTime, $data, $joinTable, $errorFlag, $script);
  3411. if (!empty($inData['args'][2]))
  3412. $this->debug_WHERE($inData['args'][0], $inData['args'][2], $script);
  3413. break;
  3414. }
  3415. }
  3416. }
  3417. /**
  3418. * Logs the where clause for debugging purposes.
  3419. *
  3420. * @param string $table Table name(s) the query was targeted at
  3421. * @param string $where The WHERE clause to be logged
  3422. * @param string $script The script calling the logging
  3423. * @return void
  3424. */
  3425. public function debug_WHERE($table, $where, $script = '') {
  3426. $insertArray = array(
  3427. 'tstamp' => $GLOBALS['EXEC_TIME'],
  3428. 'beuser_id' => intval($GLOBALS['BE_USER']->user['uid']),
  3429. 'script' => $script,
  3430. 'tablename' => $table,
  3431. 'whereclause' => $where
  3432. );
  3433. $this->exec_INSERTquery('tx_dbal_debuglog_where', $insertArray);
  3434. }
  3435. /**
  3436. * Inserts row in the log table
  3437. *
  3438. * @param string The current query
  3439. * @param integer Execution time of query in milliseconds
  3440. * @param array Data to be stored serialized.
  3441. * @param string Join string if there IS a join.
  3442. * @param integer Error status.
  3443. * @param string $script The script calling the logging
  3444. * @return void
  3445. */
  3446. public function debug_log($query, $ms, $data, $join, $errorFlag, $script = '') {
  3447. if (is_array($query)) {
  3448. $queryToLog = $query[0] . ' -- ';
  3449. if (count($query[1])) {
  3450. $queryToLog .= count($query[1]) . ' BLOB FIELDS: ' . implode(', ', array_keys($query[1]));
  3451. }
  3452. if (count($query[2])) {
  3453. $queryToLog .= count($query[2]) . ' CLOB FIELDS: ' . implode(', ', array_keys($query[2]));
  3454. }
  3455. } else {
  3456. $queryToLog = $query;
  3457. }
  3458. $insertArray = array(
  3459. 'tstamp' => $GLOBALS['EXEC_TIME'],
  3460. 'beuser_id' => intval($GLOBALS['BE_USER']->user['uid']),
  3461. 'script' => $script,
  3462. 'exec_time' => $ms,
  3463. 'table_join' => $join,
  3464. 'serdata' => serialize($data),
  3465. 'query' => $queryToLog,
  3466. 'errorFlag' => $errorFlag
  3467. );
  3468. $this->exec_INSERTquery('tx_dbal_debuglog', $insertArray);
  3469. }
  3470. /**
  3471. * Perform EXPLAIN query on DEFAULT handler!
  3472. *
  3473. * @param string SELECT Query
  3474. * @return array The Explain result rows in an array
  3475. * @todo Not supporting other than the default handler? And what about DBMS of other kinds than MySQL - support for EXPLAIN?
  3476. */
  3477. public function debug_explain($query) {
  3478. $output = array();
  3479. $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
  3480. switch ($hType) {
  3481. case 'native':
  3482. $res = $this->sql_query('EXPLAIN ' . $query);
  3483. while ($row = $this->sql_fetch_assoc($res)) {
  3484. $output[] = $row;
  3485. }
  3486. break;
  3487. case 'adodb':
  3488. switch ($this->handlerCfg['_DEFAULT']['config']['driver']) {
  3489. case 'oci8':
  3490. $res = $this->sql_query('EXPLAIN PLAN ' . $query);
  3491. $output[] = 'EXPLAIN PLAN data logged to default PLAN_TABLE';
  3492. break;
  3493. default:
  3494. $res = $this->sql_query('EXPLAIN ' . $query);
  3495. while ($row = $this->sql_fetch_assoc($res)) {
  3496. $output[] = $row;
  3497. }
  3498. break;
  3499. }
  3500. break;
  3501. }
  3502. return $output;
  3503. }
  3504. }
  3505. if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_db.php'])) {
  3506. include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_db.php']);
  3507. }
  3508. ?>