Extract primary keys from an index definition.
This method extracts the names of all primary keys from the index
defintions of a table.

@param array(string=>ezcDbSchemaIndex) $indexes Indices.
@return array(string=>bool) The primary keys.
760074
private function determinePrimaries( $indexes )
    {
        $primaries = array();
        foreach ( $indexes as $index )
        {
            if ( $index->primary )
            {
                foreach ( $index->indexFields as $field => $definiton )
                {
                    $primaries[$field] = true;
                }
            }
        }
        return $primaries;
    }
1172288
private static function normalizePrimaryKeys($primary) : array
    {
        $pks = self::getPrimaryKeys();

        if (!is_array($primary) && count($pks) == 1) {
            $primary = [$pks[0] => $primary];
        } elseif (array_diff(array_keys($primary), $pks)) {
            throw new \Exception('Invalid primary key.');
        }

        return $primary;
    }
691138
private function getIndex(string $indexedFieldName): array
    {
        // build index
        if ($this->index === null) {
            // init empty index
            $this->index = [];

            // get index definition
            $indexedFields = $this->getIndexDefinition();

            // build index for database
            if (!empty($indexedFields)) {
                // init all defined indexes
                foreach ($this->clusterIndex as $entryArray) {
                    $entry = $this->arrayToEntry($entryArray);
                    foreach ($indexedFields as $indexName => $indexDefinition) {
                        if (is_array($indexDefinition)) {
                            // compound index
                            $reference = &$this->index[$indexName];
                            foreach ($indexDefinition as $indexDefinitionPart) {
                                // limited length of field
                                if (is_array($indexDefinitionPart)) {
                                    $indexDefinitionPartValue = substr(
                                        $entryArray[$indexDefinitionPart[0]],
                                        0,
                                        $indexDefinitionPart[1]
                                    );
                                } else {
                                    $indexDefinitionPartValue = $entryArray[$indexDefinitionPart];
                                }
                                if (!isset($reference[$indexDefinitionPartValue])) {
                                    $reference[$indexDefinitionPartValue] = [];
                                }
                                $reference = &$reference[$indexDefinitionPartValue];
                            }

                            $reference = $entry;
                        } else {
                            // single index
                            $indexName = $indexDefinition;
                            // skip empty field
                            if (empty($entryArray[$indexDefinition])) {
                                continue;
                            }
                            // add to index
                            $this->index[$indexName][$entryArray[$indexDefinition]] = $entry;
                        }
                    }
                }
            }
        }

        // get index
        if (!isset($this->index[$indexedFieldName])) {
            throw new \InvalidArgumentException(
                sprintf(
                    'Unknown index "%s" in database "%s"',
                    $indexedFieldName,
                    get_class()
                )
            );
        }

        return $this->index[$indexedFieldName];
    }
156284
public function primary($pkeys) {
        if (empty($pkeys))
            return false;
        if (!is_array($pkeys))
            $pkeys = array($pkeys);
        // single pkey
        $this->increments = $pkeys[0];
        $this->pkeys = $pkeys;
        // drop duplicate pkey definition
        if (array_key_exists($this->increments,$this->columns))
            unset($this->columns[$this->increments]);
        // set flag on new fields
        foreach ($pkeys as $name)
            if(array_key_exists($name,$this->columns))
                $this->columns[$name]->pkey = true;
        // composite key
        if (count($pkeys) > 1) {
            $pkeys_quoted = array_map(array($this->db,'quotekey'), $pkeys);
            $pk_string = implode(', ', $pkeys_quoted);
            if (preg_match('/sqlite2?/', $this->db->driver())) {
                // rebuild table with new primary keys
                $this->rebuild_cmd['pkeys'] = $pkeys;
                return;
            } else {
                $table = $this->db->quotekey($this->name);
                $table_key = $this->db->quotekey($this->name.'_pkey');
                $cmd = array(
                    'odbc' =>
                        "CREATE INDEX $table_key ON $table ( $pk_string );",
                    'mysql' =>
                        "ALTER TABLE $table DROP PRIMARY KEY, ADD PRIMARY KEY ( $pk_string );",
                    'mssql|sybase|dblib|sqlsrv' => array(
                        "ALTER TABLE $table DROP CONSTRAINT PK_".$this->name."_ID;",
                        "ALTER TABLE $table ADD CONSTRAINT $table_key PRIMARY KEY ( $pk_string );",
                    ),
                    'pgsql' => array(
                        "ALTER TABLE $table DROP CONSTRAINT $table_key;",
                        "ALTER TABLE $table ADD CONSTRAINT $table_key PRIMARY KEY ( $pk_string );",
                    ),
                );
                $query = $this->findQuery($cmd);
                if (!is_array($query))
                    $query = array($query);
                foreach ($query as $q)
                    $this->queries[] = $q;
            }
        }
    }
52293
public function get_from_ids(array $ids) {
        $alias = $this->get_table_alias();
        list($insql, $params) = $this->get_db()->get_in_or_equal($ids);
        $wheresql = $alias . '.id ' . $insql;
        $sql = $this->generate_get_records_sql($wheresql);
        $records = $this->get_db()->get_records_sql($sql, $params);

        return $this->transform_db_records_to_entities($records);
    }
1110903
private function _keys($exclude_primary_key = false, $escape_keys = false)
	{
		$keys = [];

		foreach($this->storage as $key => $value) {
			if ($exclude_primary_key) {
				if ($key != static::$primary_key) {
					$keys[] = $escape_keys ? $this->db->quote_column($key) : $key;
				}
			} else {
				$keys[] = $escape_keys ? $this->db->quote_column($key) : $key;
			}
		}

		return $keys;
	}
545852
protected function getIndexSqlDefinition(Index $index, $tableName)
    {
        if (is_string($index->getName())) {
            $indexName = $index->getName();
        } else {
            $columnNames = $index->getColumns();
            $indexName = sprintf('%s_%s', $tableName, implode('_', $columnNames));
        }
        $def = sprintf(
            "CREATE %s INDEX %s ON %s (%s);",
            ($index->getType() === Index::UNIQUE ? 'UNIQUE' : ''),
            $indexName,
            $this->quoteTableName($tableName),
            '[' . implode('],[', $index->getColumns()) . ']'
        );

        return $def;
    }
525403
protected function getIndexSqlDefinition(Index $index)
    {
        $def = '';
        $limit = '';
        if ($index->getLimit()) {
            $limit = '(' . $index->getLimit() . ')';
        }

        if ($index->getType() == Index::UNIQUE) {
            $def .= ' UNIQUE';
        }

        if ($index->getType() == Index::FULLTEXT) {
            $def .= ' FULLTEXT';
        }

        $def .= ' KEY';

        if (is_string($index->getName())) {
            $def .= ' `' . $index->getName() . '`';
        }

        $def .= ' (`' . implode('`,`', $index->getColumns()) . '`' . $limit . ')';

        return $def;
    }
1082572
public function getIndexes( $includeParents = true )
    {

        // lazy load indexes
        if( !isset( $this->indexes ) ) {

            $this->indexes = $this->catalog->pgIndexes->findByIndrelid( $this->oid );

            // are we inheriting off another table
            if( $parent = $this->getParent() ) {

                foreach( $parent->getIndexes() as $parentIndex ) {

                    $data = $parentIndex->all();
                    $data['inherited'] = true;
                    $data['columns'] = [];

                    foreach( $parentIndex->indkey as $indkey ) {
                        $columns[] = sprintf( "%s.%s", $this->oid, $indkey );
                    }

                    $this->indexes->add(
                        new PgIndex( $this->catalog, $data )
                    );

                }

            }

        }

        // include parent indexes
        if( $includeParents ) {
            return $this->indexes->copy();
        } else {
            return $this->indexes->copy()->removeByInherited( true );
        }

    }
1190603
public function setPrimaryKey(array $columnNames, $indexName = false)
    {
        $this->_addIndex($this->_createIndex($columnNames, $indexName ?: 'primary', true, true));

        foreach ($columnNames as $columnName) {
            $column = $this->getColumn($columnName);
            $column->setNotnull(true);
        }

        return $this;
    }
1279809
protected function collectIndexedColumns($indexName, $columns, &$collectedIndexes)
	{
		/**
		 * "If the table has a multiple-column index, any leftmost prefix of the
		 * index can be used by the optimizer to find rows. For example, if you
		 * have a three-column index on (col1, col2, col3), you have indexed search
		 * capabilities on (col1), (col1, col2), and (col1, col2, col3)."
		 * @link http://dev.mysql.com/doc/refman/5.5/en/mysql-indexes.html
		*/
		$indexedColumns = array();
		foreach ($columns as $column) {
			$indexedColumns[] = $column;
			$indexedColumnsHash = $this->getColumnList($indexedColumns);
			if (!array_key_exists($indexedColumnsHash, $collectedIndexes)) {
				$collectedIndexes[$indexedColumnsHash] = array();
			}
			$collectedIndexes[$indexedColumnsHash][] = $indexName;
		}
	}
118006
public function getPrimaryKeys(): array
    {
        $primaryColumns = [];
        foreach ($this->getColumns() as $column) {
            if ($column->getAbstractType() == 'primary' || $column->getAbstractType() == 'bigPrimary') {
                if (!in_array($column->getName(), $this->primaryKeys)) {
                    //Only columns not listed as primary keys already
                    $primaryColumns[] = $column->getName();
                }
            }
        }

        return array_unique(array_merge($this->primaryKeys, $primaryColumns));
    }
830882
public function withIndexes(array $indexes) : Table
    {
        return new self($this->name, $this->columns, $indexes, $this->foreignKeys);
    }
833014
private function extractValues(array $rows)
    {
        $result = array();

        foreach ($rows as $row) {
            foreach ($row as $column => $value) {
                array_push($result, $value);
            }
        }

        return $result;
    }
84753
protected function findColumns($index)
    {
        $sql = 'DESCRIBE ' . $this->quoteSimpleIndexName($index->name);
        try {
            $columns = $this->db->createCommand($sql)->queryAll();
        } catch (\Exception $e) {
            $previous = $e->getPrevious();
            if ($previous instanceof \PDOException && strpos($previous->getMessage(), 'SQLSTATE[42S02') !== false) {
                // index does not exist
                // https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html#error_er_bad_table_error
                return false;
            }
            throw $e;
        }

        if (empty($columns[0]['Agent'])) {
            foreach ($columns as $info) {
                $column = $this->loadColumnSchema($info);
                if (isset($index->columns[$column->name])) {
                    $column = $this->mergeColumnSchema($index->columns[$column->name], $column);
                }
                $index->columns[$column->name] = $column;
                if ($column->isPrimaryKey) {
                    $index->primaryKey = $column->name;
                }
            }

            return true;
        }

        // Distributed index :
        foreach ($columns as $column) {
            if (!empty($column['Type']) && strcasecmp('local', $column['Type']) !== 0) {
                // skip type 'agent'
                continue;
            }

            $agent = $this->getIndexSchema($column['Agent']);
            if ($agent !== null) {
                $index->columns = $agent->columns;
                $index->primaryKey = $agent->primaryKey;
                return true;
            }
        }

        $this->applyDefaultColumns($index);

        return true;
    }
1046712
protected function getKeyLookup($keys)
	{
		// First pass, create a lookup of the keys.
		$lookup = array();

		foreach ($keys as $key)
		{
			if ($key instanceof \SimpleXMLElement)
			{
				$kName = (string) $key['Index'];
			}
			else
			{
				$kName = $key->Index;
			}

			if (empty($lookup[$kName]))
			{
				$lookup[$kName] = array();
			}

			$lookup[$kName][] = $key;
		}

		return $lookup;
	}
1207072
public static function getLastIndexName(array $indexNames)
    {
        usort($indexNames, function ($a, $b) {
            $aYear = self::getYearFromIndexName($a);
            $bYear = self::getYearFromIndexName($b);
            if ($aYear == $bYear) {
                $aVersion = self::getVersionFromIndexName($a);
                $bVersion = self::getVersionFromIndexName($b);
                if ($aVersion == $bVersion) {
                    return 0;
                }
                return ($aVersion < $bVersion) ? -1 : 1;
            }
            return ($aYear < $bYear) ? -1 : 1;
        });
        return array_pop($indexNames);
    }