Skip to content

Commit

Permalink
fix!: spark db:table causes errors w/z table name including speciali …
Browse files Browse the repository at this point in the history
…chars
  • Loading branch information
kenjis committed Apr 11, 2024
1 parent b550dc6 commit fe4d40f
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 38 deletions.
5 changes: 0 additions & 5 deletions phpstan-baseline.php
Original file line number Diff line number Diff line change
Expand Up @@ -2396,11 +2396,6 @@
'count' => 1,
'path' => __DIR__ . '/system/Database/BaseConnection.php',
];
$ignoreErrors[] = [
'message' => '#^Property CodeIgniter\\\\Database\\\\BaseConnection\\:\\:\\$aliasedTables type has no value type specified in iterable type array\\.$#',
'count' => 1,
'path' => __DIR__ . '/system/Database/BaseConnection.php',
];
$ignoreErrors[] = [
'message' => '#^Property CodeIgniter\\\\Database\\\\BaseConnection\\:\\:\\$dataCache type has no value type specified in iterable type array\\.$#',
'count' => 1,
Expand Down
5 changes: 3 additions & 2 deletions system/Commands/Database/ShowTableInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;
use CodeIgniter\Database\BaseConnection;
use CodeIgniter\Database\TableName;
use Config\Database;
use InvalidArgumentException;

Expand Down Expand Up @@ -194,7 +195,7 @@ private function showDataOfTable(string $tableName, int $limitRows, int $limitFi
CLI::newLine();

$this->removeDBPrefix();
$thead = $this->db->getFieldNames($tableName);
$thead = $this->db->getFieldNames(TableName::fromActualName($this->db, $tableName));
$this->restoreDBPrefix();

// If there is a field named `id`, sort by it.
Expand Down Expand Up @@ -253,7 +254,7 @@ private function makeTableRows(
$this->tbody = [];

$this->removeDBPrefix();
$builder = $this->db->table($tableName);
$builder = $this->db->table(TableName::fromActualName($this->db, $tableName));
$builder->limit($limitRows);
if ($sortField !== null) {
$builder->orderBy($sortField, $this->sortDesc ? 'DESC' : 'ASC');
Expand Down
13 changes: 9 additions & 4 deletions system/Database/BaseBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ class BaseBuilder
/**
* Constructor
*
* @param array|string $tableName tablename or tablenames with or without aliases
* @param array|string|TableName $tableName tablename or tablenames with or without aliases
*
* Examples of $tableName: `mytable`, `jobs j`, `jobs j, users u`, `['jobs j','users u']`
*
Expand All @@ -315,15 +315,20 @@ public function __construct($tableName, ConnectionInterface $db, ?array $options
*/
$this->db = $db;

if ($tableName instanceof TableName) {
$this->tableName = $tableName->getTableName();
$this->QBFrom[] = $this->db->escapeIdentifier($tableName);
$this->db->addTableAlias($tableName->getAlias());
}
// If it contains `,`, it has multiple tables
if (is_string($tableName) && ! str_contains($tableName, ',')) {
elseif (is_string($tableName) && ! str_contains($tableName, ',')) {
$this->tableName = $tableName; // @TODO remove alias if exists
$this->from($tableName);
} else {
$this->tableName = '';
$this->from($tableName);
}

$this->from($tableName);

if ($options !== null && $options !== []) {
foreach ($options as $key => $value) {
if (property_exists($this, $key)) {
Expand Down
39 changes: 29 additions & 10 deletions system/Database/BaseConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ abstract protected function _transRollback(): bool;
/**
* Returns a non-shared new instance of the query builder for this connection.
*
* @param array|string $tableName
* @param array|string|TableName $tableName
*
* @return BaseBuilder
*
Expand Down Expand Up @@ -1029,10 +1029,10 @@ public function getConnectDuration(int $decimals = 6): string
* insert the table prefix (if it exists) in the proper position, and escape only
* the correct identifiers.
*
* @param array|int|string $item
* @param bool $prefixSingle Prefix a table name with no segments?
* @param bool $protectIdentifiers Protect table or column names?
* @param bool $fieldExists Supplied $item contains a column name?
* @param array|int|string|TableName $item
* @param bool $prefixSingle Prefix a table name with no segments?
* @param bool $protectIdentifiers Protect table or column names?
* @param bool $fieldExists Supplied $item contains a column name?
*
* @return array|string
* @phpstan-return ($item is array ? array : string)
Expand All @@ -1053,6 +1053,10 @@ public function protectIdentifiers($item, bool $prefixSingle = false, ?bool $pro
return $escapedArray;
}

if ($item instanceof TableName) {
return $this->escapeTableName($item);

Check failure on line 1057 in system/Database/BaseConnection.php

View workflow job for this annotation

GitHub Actions / Psalm Analysis

NoValue

system/Database/BaseConnection.php:1057:43: NoValue: All possible types for this argument were invalidated - This may be dead code (see https://psalm.dev/179)
}

// If you pass `['column1', 'column2']`, `$item` will be int because the array keys are int.
$item = (string) $item;

Expand Down Expand Up @@ -1195,14 +1199,18 @@ private function protectDotItem(string $item, string $alias, bool $protectIdenti
*
* This function escapes single identifier.
*
* @param non-empty-string $item
* @param non-empty-string|TableName $item
*/
public function escapeIdentifier(string $item): string
public function escapeIdentifier($item): string
{
if ($item === '') {
return '';
}

if ($item instanceof TableName) {
return $this->escapeTableName($item);
}

return $this->escapeChar
. str_replace(
$this->escapeChar,
Expand All @@ -1212,6 +1220,11 @@ public function escapeIdentifier(string $item): string
. $this->escapeChar;
}

private function escapeTableName(TableName $tableName): string
{
return $this->escapeIdentifier($tableName->getActualTableName());
}

/**
* Escape the SQL Identifiers
*
Expand Down Expand Up @@ -1513,12 +1526,16 @@ public function tableExists(string $tableName, bool $cached = true): bool
/**
* Fetch Field Names
*
* @param string|TableName $tableName
*
* @return array|false
*
* @throws DatabaseException
*/
public function getFieldNames(string $table)
public function getFieldNames($tableName)
{
$table = ($tableName instanceof TableName) ? $tableName->getTableName() : $tableName;

// Is there a cached result?
if (isset($this->dataCache['field_names'][$table])) {
return $this->dataCache['field_names'][$table];
Expand All @@ -1528,7 +1545,7 @@ public function getFieldNames(string $table)
$this->initialize();
}

if (false === ($sql = $this->_listColumns($table))) {
if (false === ($sql = $this->_listColumns($tableName))) {
if ($this->DBDebug) {
throw new DatabaseException('This feature is not available for the database you are using.');
}
Expand Down Expand Up @@ -1744,9 +1761,11 @@ abstract protected function _listTables(bool $constrainByPrefix = false, ?string
/**
* Generates a platform-specific query string so that the column names can be fetched.
*
* @param string|TableName $table
*
* @return false|string
*/
abstract protected function _listColumns(string $table = '');
abstract protected function _listColumns($table = '');

/**
* Platform-specific field data information.
Expand Down
14 changes: 12 additions & 2 deletions system/Database/MySQLi/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use CodeIgniter\Database\BaseConnection;
use CodeIgniter\Database\Exceptions\DatabaseException;
use CodeIgniter\Database\TableName;
use LogicException;
use mysqli;
use mysqli_result;
Expand Down Expand Up @@ -404,10 +405,19 @@ protected function _listTables(bool $prefixLimit = false, ?string $tableName = n

/**
* Generates a platform-specific query string so that the column names can be fetched.
*
* @param string|TableName $table
*/
protected function _listColumns(string $table = ''): string
protected function _listColumns($table = ''): string
{
return 'SHOW COLUMNS FROM ' . $this->protectIdentifiers($table, true, null, false);
$tableName = $this->protectIdentifiers(
$table,
true,
null,
false
);

return 'SHOW COLUMNS FROM ' . $tableName;
}

/**
Expand Down
18 changes: 13 additions & 5 deletions system/Database/OCI8/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use CodeIgniter\Database\BaseConnection;
use CodeIgniter\Database\Exceptions\DatabaseException;
use CodeIgniter\Database\Query;
use CodeIgniter\Database\TableName;
use ErrorException;
use stdClass;

Expand Down Expand Up @@ -266,18 +267,25 @@ protected function _listTables(bool $prefixLimit = false, ?string $tableName = n

/**
* Generates a platform-specific query string so that the column names can be fetched.
*
* @param string|TableName $table
*/
protected function _listColumns(string $table = ''): string
protected function _listColumns($table = ''): string
{
if (str_contains($table, '.')) {
sscanf($table, '%[^.].%s', $owner, $table);
if ($table instanceof TableName) {
$tableName = $this->escape(strtoupper($table->getActualTableName()));
$owner = $this->username;
} elseif (str_contains($table, '.')) {
sscanf($table, '%[^.].%s', $owner, $tableName);
$tableName = $this->escape(strtoupper($this->DBPrefix . $tableName));
} else {
$owner = $this->username;
$owner = $this->username;
$tableName = $this->escape(strtoupper($this->DBPrefix . $table));
}

return 'SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS
WHERE UPPER(OWNER) = ' . $this->escape(strtoupper($owner)) . '
AND UPPER(TABLE_NAME) = ' . $this->escape(strtoupper($this->DBPrefix . $table));
AND UPPER(TABLE_NAME) = ' . $tableName;
}

/**
Expand Down
14 changes: 11 additions & 3 deletions system/Database/Postgre/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use CodeIgniter\Database\BaseConnection;
use CodeIgniter\Database\Exceptions\DatabaseException;
use CodeIgniter\Database\RawSql;
use CodeIgniter\Database\TableName;
use ErrorException;
use PgSql\Connection as PgSqlConnection;
use PgSql\Result as PgSqlResult;
Expand Down Expand Up @@ -286,13 +287,20 @@ protected function _listTables(bool $prefixLimit = false, ?string $tableName = n

/**
* Generates a platform-specific query string so that the column names can be fetched.
*
* @param string|TableName $table
*/
protected function _listColumns(string $table = ''): string
protected function _listColumns($table = ''): string
{
if ($table instanceof TableName) {
$tableName = $this->escape($table->getActualTableName());
} else {
$tableName = $this->escape($this->DBPrefix . strtolower($table));
}

return 'SELECT "column_name"
FROM "information_schema"."columns"
WHERE LOWER("table_name") = '
. $this->escape($this->DBPrefix . strtolower($table))
WHERE LOWER("table_name") = ' . $tableName
. ' ORDER BY "ordinal_position"';
}

Expand Down
13 changes: 11 additions & 2 deletions system/Database/SQLSRV/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use CodeIgniter\Database\BaseConnection;
use CodeIgniter\Database\Exceptions\DatabaseException;
use CodeIgniter\Database\TableName;
use stdClass;

/**
Expand Down Expand Up @@ -221,12 +222,20 @@ protected function _listTables(bool $prefixLimit = false, ?string $tableName = n

/**
* Generates a platform-specific query string so that the column names can be fetched.
*
* @param string|TableName $table
*/
protected function _listColumns(string $table = ''): string
protected function _listColumns($table = ''): string
{
if ($table instanceof TableName) {
$tableName = $this->escape(strtolower($table->getActualTableName()));
} else {
$tableName = $this->escape($this->DBPrefix . strtolower($table));
}

return 'SELECT [COLUMN_NAME] '
. ' FROM [INFORMATION_SCHEMA].[COLUMNS]'
. ' WHERE [TABLE_NAME] = ' . $this->escape($this->DBPrefix . $table)
. ' WHERE [TABLE_NAME] = ' . $tableName
. ' AND [TABLE_SCHEMA] = ' . $this->escape($this->schema);
}

Expand Down
21 changes: 17 additions & 4 deletions system/Database/SQLite3/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use CodeIgniter\Database\BaseConnection;
use CodeIgniter\Database\Exceptions\DatabaseException;
use CodeIgniter\Database\TableName;
use Exception;
use SQLite3;
use SQLite3Result;
Expand Down Expand Up @@ -202,19 +203,31 @@ protected function _listTables(bool $prefixLimit = false, ?string $tableName = n

/**
* Generates a platform-specific query string so that the column names can be fetched.
*
* @param string|TableName $table
*/
protected function _listColumns(string $table = ''): string
protected function _listColumns($table = ''): string
{
return 'PRAGMA TABLE_INFO(' . $this->protectIdentifiers($table, true, null, false) . ')';
if ($table instanceof TableName) {
$tableName = $this->escapeIdentifier($table);
} else {
$tableName = $this->protectIdentifiers($table, true, null, false);
}

return 'PRAGMA TABLE_INFO(' . $tableName . ')';
}

/**
* @param string|TableName $tableName
*
* @return array|false
*
* @throws DatabaseException
*/
public function getFieldNames(string $table)
public function getFieldNames($tableName)
{
$table = ($tableName instanceof TableName) ? $tableName->getTableName() : $tableName;

// Is there a cached result?
if (isset($this->dataCache['field_names'][$table])) {
return $this->dataCache['field_names'][$table];
Expand All @@ -224,7 +237,7 @@ public function getFieldNames(string $table)
$this->initialize();
}

$sql = $this->_listColumns($table);
$sql = $this->_listColumns($tableName);

$query = $this->query($sql);
$this->dataCache['field_names'][$table] = [];
Expand Down
5 changes: 4 additions & 1 deletion system/Test/Mock/MockConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use CodeIgniter\Database\BaseConnection;
use CodeIgniter\Database\BaseResult;
use CodeIgniter\Database\Query;
use CodeIgniter\Database\TableName;

/**
* @extends BaseConnection<object|resource, object|resource>
Expand Down Expand Up @@ -197,8 +198,10 @@ protected function _listTables(bool $constrainByPrefix = false, ?string $tableNa

/**
* Generates a platform-specific query string so that the column names can be fetched.
*
* @param string|TableName $table
*/
protected function _listColumns(string $table = ''): string
protected function _listColumns($table = ''): string
{
return '';
}
Expand Down

0 comments on commit fe4d40f

Please sign in to comment.