public function execute() { if (!count($this->condition)) { throw new InvalidMergeQueryException(t('Invalid merge query: no conditions')); } // Keep a reference to the blobs. $blobs = array(); // Fetch the list of blobs and sequences used on that table. $columnInformation = $this->connection->schema()->queryColumnInformation($this->table); // Find out if there is an identity field set in this insert. $this->setIdentity = !empty($columnInformation['identity']) && in_array($columnInformation['identity'], array_keys($this->insertFields)); // Initialize placeholder count. $max_placeholder = 0; // Build the query. $stmt = $this->connection->prepareQuery((string)$this); // Build the arguments: 1. condition. $arguments = $this->condition->arguments(); DatabaseUtils::BindArguments($stmt, $arguments); // 2. When matched part. $fields = $this->updateFields; DatabaseUtils::BindExpressions($stmt, $this->expressionFields, $fields); DatabaseUtils::BindValues($stmt, $fields, $blobs, ':db_merge_placeholder_', $columnInformation, $max_placeholder); // 3. When not matched part. DatabaseUtils::BindValues($stmt, $this->insertFields, $blobs, ':db_merge_placeholder_', $columnInformation, $max_placeholder); // 4. Run the query, this will return UPDATE or INSERT $stmt->execute(); $result = NULL; foreach ($stmt as $value) { $result = $value->{'$action'}; } switch($result) { case 'UPDATE': return static::STATUS_UPDATE; case 'INSERT': return static::STATUS_INSERT; default: throw new InvalidMergeQueryException(t('Invalid merge query: no results.')); } }
public function execute() { // Fetch the list of blobs and sequences used on that table. $columnInformation = $this->connection->schema()->queryColumnInformation($this->table); // MySQL is a pretty s**t that swallows everything thrown at it, // like trying to update an identity field... if (isset($columnInformation['identity']) && isset($this->fields[$columnInformation['identity']])) { unset($this->fields[$columnInformation['identity']]); } // Because we filter $fields the same way here and in __toString(), the // placeholders will all match up properly. $stmt = $this->connection->prepareQuery((string)$this); // Expressions take priority over literal fields, so we process those first // and remove any literal fields that conflict. $fields = $this->fields; DatabaseUtils::BindExpressions($stmt, $this->expressionFields, $fields); // We use this array to store references to the blob handles. // This is necessary because the PDO will otherwise messes up with references. $blobs = array(); DatabaseUtils::BindValues($stmt, $fields, $blobs, ':db_update_placeholder_', $columnInformation); // Add conditions. if (count($this->condition)) { $this->condition->compile($this->connection, $this); $arguments = $this->condition->arguments(); DatabaseUtils::BindArguments($stmt, $arguments); } $options = $this->queryOptions; $options['already_prepared'] = TRUE; $stmt->execute(); return $stmt->rowCount(); }
public function execute() { if (!$this->preExecute()) { return NULL; } // Fetch the list of blobs and sequences used on that table. $columnInformation = $this->connection->schema()->queryColumnInformation($this->table); // Find out if there is an identity field set in this insert. $this->setIdentity = !empty($columnInformation['identity']) && in_array($columnInformation['identity'], $this->insertFields); $identity = !empty($columnInformation['identity']) ? $columnInformation['identity'] : NULL; #region Select Based Insert if (!empty($this->fromQuery)) { // Re-initialize the values array so that we can re-use this query. $this->insertValues = array(); $stmt = $this->connection->prepareQuery((string) $this); // Handle the case of SELECT-based INSERT queries first. $arguments = $this->fromQuery->getArguments(); DatabaseUtils::BindArguments($stmt, $arguments); $stmt->execute(); // We can only have 1 identity column per table (or none, where fetchColumn will fail) try { return $stmt->fetchColumn(0); } catch(\PDOException $e) { return NULL; } } #endregion #region Inserts with no values (full defaults) // Handle the case of full-default queries. if (empty($this->fromQuery) && (empty($this->insertFields) || empty($this->insertValues))) { // Re-initialize the values array so that we can re-use this query. $this->insertValues = array(); $stmt = $this->connection->prepareQuery((string) $this); $stmt->execute(); // We can only have 1 identity column per table (or none, where fetchColumn will fail) try { return $stmt->fetchColumn(0); } catch(\PDOException $e) { return NULL; } } #endregion #region Regular Inserts // Each insert happens in its own query. However, we wrap it in a transaction // so that it is atomic where possible. $transaction = NULL; $batch_size = 200; // At most we can process in batches of 250 elements. $batch = array_splice($this->insertValues, 0, $batch_size); // If we are going to need more than one batch for this... start a transaction. if (empty($this->queryOptions['sqlsrv_skip_transactions']) && !empty($this->insertValues)) { $transaction = $this->connection->startTransaction('', DatabaseTransactionSettings::GetBetterDefaults()); } while (!empty($batch)) { // Give me a query with the amount of batch inserts. $query = (string) $this->__toString2(count($batch)); // Prepare the query. $stmt = $this->connection->prepareQuery($query); // We use this array to store references to the blob handles. // This is necessary because the PDO will otherwise messes up with references. $blobs = array(); $max_placeholder = 0; foreach ($batch as $insert_index => $insert_values) { $values = array_combine($this->insertFields, $insert_values); DatabaseUtils::BindValues($stmt, $values, $blobs, ':db_insert', $columnInformation, $max_placeholder, $insert_index); } $stmt->execute(array(), array('fetch' => PDO::FETCH_ASSOC)); // We can only have 1 identity column per table (or none, where fetchColumn will fail) // When the column does not have an identity column, no results are thrown back. foreach($stmt as $insert) { try { $this->inserted_keys[] = $insert[$identity]; } catch(\Exception $e) { $this->inserted_keys[] = NULL; } } // Fetch the next batch. $batch = array_splice($this->insertValues, 0, $batch_size); } // If we started a transaction, commit it. if ($transaction) { $transaction->commit(); } // Re-initialize the values array so that we can re-use this query. $this->insertValues = array(); // Return the last inserted key. return empty($this->inserted_keys) ? NULL : end($this->inserted_keys); #endregion }
/** * Internal function: prepare a query by calling PDO directly. * * This function has to be public because it is called by other parts of the * database layer, but do not call it directly, as you risk locking down the * PHP process. */ public function PDOPrepare($query, array $options = array()) { // Preprocess the query. if (!$this->bypassQueryPreprocess) { $query = $this->preprocessQuery($query); } // You can set the MSSQL_APPEND_CALLSTACK_COMMENT to TRUE // to append to each query, in the form of comments, the current // backtrace plus other details that aid in debugging deadlocks // or long standing locks. Use in combination with MSSQL profiler. global $conf; if (DatabaseUtils::GetConfigBoolean('MSSQL_APPEND_CALLSTACK_COMMENT') == TRUE) { global $user; $trim = strlen(DRUPAL_ROOT); $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); static $request_id; if (empty($request_id)) { $request_id = uniqid('', TRUE); } // Remove las item (it's alwasy PDOPrepare) $trace = array_splice($trace, 1); $comment = PHP_EOL . PHP_EOL; $comment .= '-- uid:' . (empty($user) ? 'null' : $user->uid) . PHP_EOL; $uri = (isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : 'none') ; $uri = preg_replace("/[^a-zA-Z0-9]/i", "_", $uri); $comment .= '-- url:' . $uri . PHP_EOL; //$comment .= '-- request_id:' . $request_id . PHP_EOL; foreach ($trace as $t) { $function = isset($t['function']) ? $t['function'] : ''; $file = ''; if(isset($t['file'])) { $len = strlen($t['file']); if ($len > $trim) { $file = substr($t['file'], $trim, $len - $trim) . " [{$t['line']}]"; } } $comment .= '-- ' . str_pad($function, 35) . ' ' . $file . PHP_EOL; } $query = $comment . PHP_EOL . $query; } return parent::prepare($query, $options); }
/** * Get the SQL expression for a default value. * * @param mixed $table * @param mixed $field * @param mixed $default */ private function defaultValueExpression($sqlsr_type, $default) { // The actual expression depends on the target data type as it might require conversions. $result = is_string($default) ? "'" . addslashes($default) . "'" : $default; if (DatabaseUtils::GetMSSQLType($sqlsr_type) == 'varbinary') { $default = addslashes($default); $result = "CONVERT({$sqlsr_type}, '{$default}')"; } return $result; }