/**
  * 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;
 }