/** * Returns information about each field in the $table (quering the DBMS) * In a DBAL this should look up the right handler for the table and return compatible information * 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. * * @param string $tableName Table name * @return array Field information in an associative array with fieldname => field row */ public function admin_get_fields($tableName) { $output = array(); // Do field mapping if needed: $ORIG_tableName = $tableName; if ($tableArray = $this->map_needMapping($tableName)) { // Table name: if ($this->mapping[$tableName]['mapTableName']) { $tableName = $this->mapping[$tableName]['mapTableName']; } } // Find columns $this->lastHandlerKey = $this->handler_getFromTableList($tableName); switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) { case 'native': /** @var \mysqli_result $columns_res */ $columns_res = $this->query('SHOW columns FROM ' . $tableName); while ($fieldRow = $columns_res->fetch_assoc()) { $output[$fieldRow['Field']] = $fieldRow; } $columns_res->free(); break; case 'adodb': $fieldRows = $this->handlerInstance[$this->lastHandlerKey]->MetaColumns($tableName, FALSE); if (is_array($fieldRows)) { foreach ($fieldRows as $k => $fieldRow) { settype($fieldRow, 'array'); $metaType = $this->getMetadata($fieldRow['type'], $tableName, $fieldRow['name']); $output[$fieldRow['name']] = $this->dbmsSpecifics->transformFieldRowToMySQL($fieldRow, $metaType); } } break; case 'userdefined': $output = $this->handlerInstance[$this->lastHandlerKey]->admin_get_fields($tableName); break; } // mapping should be done: if (is_array($tableArray) && is_array($this->mapping[$ORIG_tableName]['mapFieldNames'])) { $revFields = array_flip($this->mapping[$ORIG_tableName]['mapFieldNames']); $newOutput = array(); foreach ($output as $fN => $fInfo) { if (isset($revFields[$fN])) { $fN = $revFields[$fN]; $fInfo['Field'] = $fN; } $newOutput[$fN] = $fInfo; } $output = $newOutput; } return $output; }
/** * @test * @param string $fieldType * @param int $maxLength * @param string $expected * @dataProvider determineNativeFieldLengthProvider */ public function determineNativeFieldLength($fieldType, $maxLength, $expected) { $result = $this->subject->getNativeFieldLength($fieldType, $maxLength); $this->assertSame($expected, $result); }
/** * Create a mapping for each table and field if required. * * @param array $parsedQuery The parsed query * @return void */ protected function createMappingsIfRequired($parsedQuery) { if (!$this->dbmsSpecifics->specificExists(Specifics\AbstractSpecifics::TABLE_MAXLENGTH) && !$this->dbmsSpecifics->specificExists(Specifics\AbstractSpecifics::FIELD_MAXLENGTH)) { return; } $mappingConfiguration = array(); $table = $parsedQuery['TABLE']; if (!isset($this->mapping[$table])) { $truncatedTable = $this->dbmsSpecifics->truncateIdentifier($table, Specifics\AbstractSpecifics::TABLE_MAXLENGTH); if ($table !== $truncatedTable) { $mappingConfiguration['mapTableName'] = $truncatedTable; } } foreach ($parsedQuery['FIELDS'] as $field => $_) { if (!isset($this->mapping[$table]['mapFieldNames'][$field])) { $truncatedField = $this->dbmsSpecifics->truncateIdentifier($field, Specifics\AbstractSpecifics::FIELD_MAXLENGTH); if ($field !== $truncatedField) { $mappingConfiguration['mapFieldNames'][$field] = $truncatedField; } } } if (!empty($mappingConfiguration)) { /** @var \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager */ $objectManager = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class); /** @var \TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager */ $configurationManager = $objectManager->get(\TYPO3\CMS\Core\Configuration\ConfigurationManager::class); $configurationManager->setLocalConfigurationValueByPath('EXTCONF/dbal/mapping/' . $table, $mappingConfiguration); // renew mapping information $this->mapping = array_merge($this->mapping, array($table => $mappingConfiguration)); } }
/** * Quotes field names in a SQL WHERE clause according to DB rules * * @param array $where_clause The parsed WHERE clause to quote * @return array * @see quoteWhereClause() */ protected function _quoteWhereClause(array $where_clause) { foreach ($where_clause as $k => $v) { // Look for sublevel: if (is_array($where_clause[$k]['sub'])) { $where_clause[$k]['sub'] = $this->_quoteWhereClause($where_clause[$k]['sub']); } elseif (isset($v['func'])) { switch ($where_clause[$k]['func']['type']) { case 'EXISTS': $where_clause[$k]['func']['subquery'] = $this->quoteSELECTsubquery($v['func']['subquery']); break; case 'FIND_IN_SET': // quoteStr that will be used for Oracle $pattern = str_replace($where_clause[$k]['func']['str'][1], '\\' . $where_clause[$k]['func']['str'][1], $where_clause[$k]['func']['str'][0]); // table is not really needed and may in fact be empty in real statements // but it's not overridden from \TYPO3\CMS\Core\Database\DatabaseConnection at the moment... $patternForLike = $this->escapeStrForLike($pattern, $where_clause[$k]['func']['table']); $where_clause[$k]['func']['str_like'] = $patternForLike; if ($where_clause[$k]['func']['table'] !== '') { $where_clause[$k]['func']['table'] = $this->quoteName($v['func']['table']); } if ($where_clause[$k]['func']['field'] !== '') { if (!empty($this->dbmsSpecifics) && $this->dbmsSpecifics->getSpecific(Specifics\AbstractSpecifics::CAST_FIND_IN_SET)) { $where_clause[$k]['func']['field'] = 'CAST(' . $this->quoteName($v['func']['field']) . ' AS CHAR)'; } else { $where_clause[$k]['func']['field'] = $this->quoteName($v['func']['field']); } } break; case 'IFNULL': // Intentional fallthrough // Intentional fallthrough case 'LOCATE': if ($where_clause[$k]['func']['table'] != '') { $where_clause[$k]['func']['table'] = $this->quoteName($v['func']['table']); } if ($where_clause[$k]['func']['field'] != '') { $where_clause[$k]['func']['field'] = $this->quoteName($v['func']['field']); } break; } } else { if ($where_clause[$k]['table'] != '') { $where_clause[$k]['table'] = $this->quoteName($where_clause[$k]['table']); } if (!is_numeric($where_clause[$k]['field'])) { $where_clause[$k]['field'] = $this->quoteName($where_clause[$k]['field']); } if (isset($where_clause[$k]['calc_table'])) { if ($where_clause[$k]['calc_table'] != '') { $where_clause[$k]['calc_table'] = $this->quoteName($where_clause[$k]['calc_table']); } if ($where_clause[$k]['calc_field'] != '') { $where_clause[$k]['calc_field'] = $this->quoteName($where_clause[$k]['calc_field']); } } } if ($where_clause[$k]['comparator']) { if (isset($v['value']['operator'])) { foreach ($where_clause[$k]['value']['args'] as $argK => $fieldDef) { $where_clause[$k]['value']['args'][$argK]['table'] = $this->quoteName($fieldDef['table']); $where_clause[$k]['value']['args'][$argK]['field'] = $this->quoteName($fieldDef['field']); } } else { // Detecting value type; list or plain: if (GeneralUtility::inList('NOTIN,IN', strtoupper(str_replace(array(' ', LF, CR, TAB), '', $where_clause[$k]['comparator'])))) { if (isset($v['subquery'])) { $where_clause[$k]['subquery'] = $this->quoteSELECTsubquery($v['subquery']); } } else { 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], '.')) { $where_clause[$k]['value'][0] = $this->quoteFieldNames($where_clause[$k]['value'][0]); } elseif ($this->runningADOdbDriver('mssql')) { $where_clause[$k]['value'][0] = substr($this->handlerInstance[$this->lastHandlerKey]->qstr($where_clause[$k]['value'][0]), 1, -1); } } } } } return $where_clause; }