diff --git a/core/lib/Drupal/Core/Database/Connection.php b/core/lib/Drupal/Core/Database/Connection.php index b39a836..6237dc5 100644 --- a/core/lib/Drupal/Core/Database/Connection.php +++ b/core/lib/Drupal/Core/Database/Connection.php @@ -564,7 +564,7 @@ public function query($query, array $args = array(), $options = array()) { catch (\PDOException $e) { $handled = $this->handleMissingTable($e, $query, $args, $options); if (isset($handled)) { - return $handled; + return reset($handled); } if ($options['throw_exception']) { // Wrap the exception in another exception, because PHP does not allow @@ -601,19 +601,17 @@ protected function handleMissingTable($e, $query, $args, $options) { // This is a SELECT on a missing table. Creating the table and // re-runing the query will result in an empty result so return that // early instead. - return new StatementEmpty(); + return array(new StatementEmpty()); } if (is_string($options['create_missing_table'])) { $table = $options['create_missing_table']; - foreach (debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT) as $bt) { - if (isset($bt['object']) && $bt['object'] instanceof SchemaProviderInterface && ($schema = $bt['object']->getSchema($table))) { - if ($this->schema()->ensureTableExists($table, $schema)) { - // Theoretically the table must exist at this point so this - // should not matter but still, databases. This makes sure - // no infinite recursion happens. - $options['create_missing_table'] = FALSE; - return $this->query($query, $args, $options); - } + if ($schema = $this->getTableSchemaFromBacktrace($table)) { + if ($this->schema()->ensureTableExists($table, $schema)) { + // Theoretically the table must exist at this point so this + // should not matter but still, databases. This makes sure + // no infinite recursion happens. + $options['create_missing_table'] = FALSE; + return array($this->query($query, $args, $options)); } } } @@ -623,6 +621,14 @@ protected function handleMissingTable($e, $query, $args, $options) { } } + public function getTableSchemaFromBacktrace($table) { + foreach (debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT) as $bt) { + if (isset($bt['object']) && $bt['object'] instanceof SchemaProviderInterface && ($schema = $bt['object']->getSchema($table))) { + return $schema; + } + } + } + /** * Expands out shorthand placeholders. * diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php index b584cd4..8d54757 100644 --- a/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php +++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php @@ -143,9 +143,11 @@ public function query($query, array $args = array(), $options = array()) { } } catch (\PDOException $e) { + $this->rollbackSavepoint(); $handled = $this->handleMissingTable($e, $query, $args, $options); if (isset($handled)) { - return $handled; + $this->releaseSavepoint(); + return reset($handled); } if ($options['throw_exception']) { // Match all SQLSTATE 23xxx errors. diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Insert.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Insert.php index fba74da..4253722 100644 --- a/core/lib/Drupal/Core/Database/Driver/pgsql/Insert.php +++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Insert.php @@ -9,6 +9,7 @@ use Drupal\Core\Database\Database; use Drupal\Core\Database\Query\Insert as QueryInsert; +use Drupal\Core\Database\SchemaObjectDoesNotExistException; /** * @ingroup database @@ -25,7 +26,23 @@ public function execute() { $stmt = $this->connection->prepareQuery((string) $this); // Fetch the list of blobs and sequences used on that table. - $table_information = $this->connection->schema()->queryTableInformation($this->table); + try { + $table_information = $this->connection->schema()->queryTableInformation($this->table); + } + catch (SchemaObjectDoesNotExistException $e) { + if (($schema = $this->connection->getTableSchemaFromBacktrace($this->table)) && $this->connection->schema()->ensureTableExists($this->table, $schema)) { + // We can now safely query 'information_schema' again since we know that + // the table exists. + $table_information = $this->connection->schema()->queryTableInformation($this->table); + + } + else { + // The table could not be created for some reason so we cannot insert + // into it. + // @todo This probably needs a better exception class. + throw new SchemaObjectDoesNotExistException(sprintf('Table %s does not exist.', $this->table)); + } + } $max_placeholder = 0; $blobs = array(); diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php index 2190ee5..5024cf7 100644 --- a/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php +++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php @@ -7,10 +7,7 @@ namespace Drupal\Core\Database\Driver\pgsql; -use Drupal\Component\Utility\String; use Drupal\Component\Utility\Unicode; -use Drupal\Core\Database\Database; -use Drupal\Core\Database\Query\Condition; use Drupal\Core\Database\SchemaObjectExistsException; use Drupal\Core\Database\SchemaObjectDoesNotExistException; use Drupal\Core\Database\Schema as DatabaseSchema; @@ -92,6 +89,11 @@ protected function ensureIdentifiersLength($identifier) { * - 'sequences' that lists the sequences used in that table. */ public function queryTableInformation($table) { + // Bail out early if the table doesn't exist. + if (!$this->tableExists($table)) { + throw new SchemaObjectDoesNotExistException(sprintf('Table %s does not exist.', $table)); + } + // Generate a key to reference this table's information on. $key = $this->connection->prefixTables('{' . $table . '}'); if (!strpos($key, '.')) { @@ -106,20 +108,11 @@ public function queryTableInformation($table) { 'sequences' => array(), ); // Don't use {} around information_schema.columns table. - $this->connection->addSavepoint(); - - try { - $result = $this->connection->query("SELECT column_name, data_type, column_default FROM information_schema.columns WHERE table_schema = :schema AND table_name = :table AND (data_type = 'bytea' OR (numeric_precision IS NOT NULL AND column_default LIKE :default))", array( - ':schema' => $schema, - ':table' => $table_name, - ':default' => '%nextval%', - )); - } - catch (\Exception $e) { - $this->connection->rollbackSavepoint(); - throw $e; - } - $this->connection->releaseSavepoint(); + $result = $this->connection->query("SELECT column_name, data_type, column_default FROM information_schema.columns WHERE table_schema = :schema AND table_name = :table AND (data_type = 'bytea' OR (numeric_precision IS NOT NULL AND column_default LIKE :default))", array( + ':schema' => $schema, + ':table' => $table_name, + ':default' => '%nextval%', + )); foreach ($result as $column) { if ($column->data_type == 'bytea') { diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Update.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Update.php index 1bee32d..8c5a623 100644 --- a/core/lib/Drupal/Core/Database/Driver/pgsql/Update.php +++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Update.php @@ -23,7 +23,23 @@ public function execute() { $stmt = $this->connection->prepareQuery((string) $this); // Fetch the list of blobs and sequences used on that table. - $table_information = $this->connection->schema()->queryTableInformation($this->table); + try { + $table_information = $this->connection->schema()->queryTableInformation($this->table); + } + catch (SchemaObjectDoesNotExistException $e) { + if (($schema = $this->connection->getTableSchemaFromBacktrace($this->table)) && $this->connection->schema()->ensureTableExists($this->table, $schema)) { + // We can now safely query 'information_schema' again since we know that + // the table exists. + $table_information = $this->connection->schema()->queryTableInformation($this->table); + + } + else { + // The table could not be created for some reason so we cannot insert + // into it. + // @todo This probably needs a better exception class. + throw new SchemaObjectDoesNotExistException(sprintf('Table %s does not exist.', $this->table)); + } + } // Expressions take priority over literal fields, so we process those first // and remove any literal fields that conflict. @@ -74,17 +90,7 @@ public function execute() { $options = $this->queryOptions; $options['already_prepared'] = TRUE; $options['return'] = Database::RETURN_AFFECTED; - - $this->connection->addSavepoint(); - try { - $result = $this->connection->query($stmt, array(), $options); - $this->connection->releaseSavepoint(); - return $result; - } - catch (\Exception $e) { - $this->connection->rollbackSavepoint(); - throw $e; - } + return $this->connection->query($stmt, array(), $options); } }