Index: includes/database/sqlite/query.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/database/sqlite/query.inc,v retrieving revision 1.10 diff -u -p -r1.10 query.inc --- includes/database/sqlite/query.inc 15 May 2010 07:04:21 -0000 1.10 +++ includes/database/sqlite/query.inc 29 Jun 2010 08:12:37 -0000 @@ -12,6 +12,86 @@ */ /** + * SQLite specific implementation of MergeQuery. + * + * SQLite doesn't support "SELECT ... FOR UPDATE" syntax: + * http://www.sqlite.org/cvstrac/wiki?p=UnsupportedSql + */ +class MergeQuery_sqlite extends MergeQuery { + public function execute() { + // If validation fails, simply return NULL. + // Note that validation routines in preExecute() may throw exceptions instead. + if (!$this->preExecute()) { + return NULL; + } + + // Wrap multiple queries in a transaction, if the database supports it. + $transaction = $this->connection->startTransaction(); + + try { + // Manually check if the record already exists. + $select = $this->connection->select($this->table); + $select->addExpression('1'); + foreach ($this->keyFields as $field => $value) { + $select->condition($field, $value); + } + + $sql = (string) $select; + $arguments = $select->getArguments(); + + // If there are no existing records, run an insert query. + if (!$this->connection->query($sql, $arguments)->fetchField()) { + $insert_fields = $this->insertFields + $this->keyFields; + try { + $this->connection->insert($this->table, $this->queryOptions)->fields($insert_fields)->execute(); + return MergeQuery::STATUS_INSERT; + } + catch (Exception $e) { + // The insert query failed, maybe it's because a racing insert query + // beat us in inserting the same row. Retry the select query, if it + // returns a row, ignore the error and continue with the update + // query below. + if (!$this->connection->query($sql, $arguments)->fetchField()) { + throw $e; + } + } + } + + // Proceed with an update query if a row was found. + if ($this->updateFields) { + $update_fields = $this->updateFields; + } + else { + $update_fields = $this->insertFields; + // If there are no exclude fields, this is a no-op. + foreach ($this->excludeFields as $exclude_field) { + unset($update_fields[$exclude_field]); + } + } + if ($update_fields || $this->expressionFields) { + // Only run the update if there are fields or expressions to update. + $update = $this->connection->update($this->table, $this->queryOptions)->fields($update_fields); + foreach ($this->keyFields as $field => $value) { + $update->condition($field, $value); + } + foreach ($this->expressionFields as $field => $expression) { + $update->expression($field, $expression['expression'], $expression['arguments']); + } + $update->execute(); + return MergeQuery::STATUS_UPDATE; + } + } + catch (Exception $e) { + // Something really wrong happened here, bubble up the exception to the + // caller. + $transaction->rollback(); + throw $e; + } + // Transaction commits here where $transaction looses scope. + } +} + +/** * SQLite specific implementation of InsertQuery. * * We ignore all the default fields and use the clever SQLite syntax: