Ejemplo n.º 1
0
 /**
  * Build a condition to match a table name against a standard information_schema.
  *
  * MySQL uses databases like schemas rather than catalogs so when we build
  * a condition to query the information_schema.tables, we set the default
  * database as the schema unless specified otherwise, and exclude table_catalog
  * from the condition criteria.
  */
 protected function buildTableNameCondition($table_name, $operator = '=', $add_prefix = TRUE)
 {
     $info = $this->connection->getConnectionOptions();
     $table_info = $this->getPrefixInfo($table_name, $add_prefix);
     $condition = new DatabaseCondition('AND');
     $condition->condition('table_schema', $table_info['database']);
     $condition->condition('table_name', $table_info['table'], $operator);
     return $condition;
 }
Ejemplo n.º 2
0
 /**
  * Implements PHP magic __toString method to convert the query to a string.
  *
  * @return string
  *   The prepared statement.
  */
 public function __toString()
 {
     // Create a sanitized comment string to prepend to the query.
     $comments = $this->connection->makeComment($this->comments);
     // Expressions take priority over literal fields, so we process those first
     // and remove any literal fields that conflict.
     $fields = $this->fields;
     $update_fields = array();
     foreach ($this->expressionFields as $field => $data) {
         $update_fields[] = $field . '=' . $data['expression'];
         unset($fields[$field]);
     }
     $max_placeholder = 0;
     foreach ($fields as $field => $value) {
         $update_fields[] = $field . '=:db_update_placeholder_' . $max_placeholder++;
     }
     $query = $comments . 'UPDATE {' . $this->connection->escapeTable($this->table) . '} SET ' . implode(', ', $update_fields);
     if (count($this->condition)) {
         $this->condition->compile($this->connection, $this);
         // There is an implicit string cast on $this->condition.
         $query .= "\nWHERE " . $this->condition;
     }
     return $query;
 }
Ejemplo n.º 3
0
 /**
  * Parses the search query into SQL conditions.
  *
  * Sets up the following variables:
  * - $this->keys
  * - $this->words
  * - $this->conditions
  * - $this->simple
  * - $this->matches
  */
 protected function parseSearchExpression()
 {
     // Matches words optionally prefixed by a - sign. A word in this case is
     // something between two spaces, optionally quoted.
     preg_match_all('/ (-?)("[^"]+"|[^" ]+)/i', ' ' . $this->searchExpression, $keywords, PREG_SET_ORDER);
     if (count($keywords) == 0) {
         return;
     }
     // Classify tokens.
     $or = FALSE;
     $limit_combinations = \Drupal::config('search.settings')->get('and_or_limit');
     // The first search expression does not count as AND.
     $and_count = -1;
     $or_count = 0;
     foreach ($keywords as $match) {
         if ($or_count && $and_count + $or_count >= $limit_combinations) {
             // Ignore all further search expressions to prevent Denial-of-Service
             // attacks using a high number of AND/OR combinations.
             $this->status |= SearchQuery::EXPRESSIONS_IGNORED;
             break;
         }
         $phrase = FALSE;
         // Strip off phrase quotes.
         if ($match[2][0] == '"') {
             $match[2] = substr($match[2], 1, -1);
             $phrase = TRUE;
             $this->simple = FALSE;
         }
         // Simplify keyword according to indexing rules and external
         // preprocessors. Use same process as during search indexing, so it
         // will match search index.
         $words = search_simplify($match[2]);
         // Re-explode in case simplification added more words, except when
         // matching a phrase.
         $words = $phrase ? array($words) : preg_split('/ /', $words, -1, PREG_SPLIT_NO_EMPTY);
         // Negative matches.
         if ($match[1] == '-') {
             $this->keys['negative'] = array_merge($this->keys['negative'], $words);
         } elseif ($match[2] == 'OR' && count($this->keys['positive'])) {
             $last = array_pop($this->keys['positive']);
             // Starting a new OR?
             if (!is_array($last)) {
                 $last = array($last);
             }
             $this->keys['positive'][] = $last;
             $or = TRUE;
             $or_count++;
             continue;
         } elseif ($match[2] == 'AND' || $match[2] == 'and') {
             continue;
         } else {
             if ($match[2] == 'or') {
                 // Lower-case "or" instead of "OR" is a warning condition.
                 $this->status |= SearchQuery::LOWER_CASE_OR;
             }
             if ($or) {
                 // Add to last element (which is an array).
                 $this->keys['positive'][count($this->keys['positive']) - 1] = array_merge($this->keys['positive'][count($this->keys['positive']) - 1], $words);
             } else {
                 $this->keys['positive'] = array_merge($this->keys['positive'], $words);
                 $and_count++;
             }
         }
         $or = FALSE;
     }
     // Convert keywords into SQL statements.
     $simple_and = FALSE;
     $simple_or = FALSE;
     // Positive matches.
     foreach ($this->keys['positive'] as $key) {
         // Group of ORed terms.
         if (is_array($key) && count($key)) {
             $simple_or = TRUE;
             $any = FALSE;
             $queryor = db_or();
             foreach ($key as $or) {
                 list($num_new_scores) = $this->parseWord($or);
                 $any |= $num_new_scores;
                 $queryor->condition('d.data', "% {$or} %", 'LIKE');
             }
             if (count($queryor)) {
                 $this->conditions->condition($queryor);
                 // A group of OR keywords only needs to match once.
                 $this->matches += $any > 0;
             }
         } else {
             $simple_and = TRUE;
             list($num_new_scores, $num_valid_words) = $this->parseWord($key);
             $this->conditions->condition('d.data', "% {$key} %", 'LIKE');
             if (!$num_valid_words) {
                 $this->simple = FALSE;
             }
             // Each AND keyword needs to match at least once.
             $this->matches += $num_new_scores;
         }
     }
     if ($simple_and && $simple_or) {
         $this->simple = FALSE;
     }
     // Negative matches.
     foreach ($this->keys['negative'] as $key) {
         $this->conditions->condition('d.data', "% {$key} %", 'NOT LIKE');
         $this->simple = FALSE;
     }
 }
Ejemplo n.º 4
0
 public function execute()
 {
     if (!empty($this->queryOptions['sqlite_return_matched_rows'])) {
         return parent::execute();
     }
     // Get the fields used in the update query, and remove those that are already
     // in the condition.
     $fields = $this->expressionFields + $this->fields;
     $this->removeFieldsInCondition($fields, $this->condition);
     // Add the inverse of the fields to the condition.
     $condition = new DatabaseCondition('OR');
     foreach ($fields as $field => $data) {
         if (is_array($data)) {
             // The field is an expression.
             $condition->where($field . ' <> ' . $data['expression']);
             $condition->isNull($field);
         } elseif (!isset($data)) {
             // The field will be set to NULL.
             $condition->isNull($field);
         } else {
             $condition->condition($field, $data, '<>');
             $condition->isNull($field);
         }
     }
     if (count($condition)) {
         $condition->compile($this->connection, $this);
         $this->condition->where((string) $condition, $condition->arguments());
     }
     return parent::execute();
 }
 /**
  * {@inheritdoc}
  */
 public function preloadPathAlias($sources, $langcode)
 {
     // VERY IMPORTANT PIECE OF DOCUMENTATION, BECAUSE CORE DOES NOT
     // DOCUMENT IT VERY WELL:
     //  - the query inverse all the orders 'pid' and 'language' compared
     //    to the original ::lookupPathAlias() method
     //  - smart little bitches, it seems they didn't know how to write it
     //    correctly in SQL (and neither do I actually) - so they rely on
     //    the fetchAllKeyed() method, which iterates in order on the rows
     //    making them squashing the previously fetched one
     $query = $this->db->select('url_alias', 'u')->fields('u', ['source', 'alias']);
     $condition = new \DatabaseCondition('OR');
     foreach ($sources as $source) {
         // See the queries above. Use LIKE for case-insensitive matching.
         $condition->condition('u.source', $this->db->escapeLike($source), 'LIKE');
     }
     $query->condition($condition);
     if (LanguageInterface::LANGCODE_NOT_SPECIFIED === $langcode) {
         $langcodeList = [$langcode];
     } else {
         $langcodeList = [$langcode, LanguageInterface::LANGCODE_NOT_SPECIFIED];
         // !!! condition here is inversed from the lookup*() methods
         if (LanguageInterface::LANGCODE_NOT_SPECIFIED > $langcode) {
             $query->orderBy('u.language', 'DESC');
         } else {
             $query->orderBy('u.language', 'ASC');
         }
     }
     return $query->orderBy('u.pid', 'ASC')->condition('u.language', $langcodeList)->execute()->fetchAllKeyed();
 }
Ejemplo n.º 6
0
 public function condition($field, $value = null, $operator = null)
 {
     Internal\condition_hook($field, $value, $operator);
     return parent::condition($field, $value, $operator);
 }
Ejemplo n.º 7
0
 public function __toString()
 {
     // Create a comments string to prepend to the query.
     $comments = !empty($this->comments) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
     // SELECT
     $query = $comments . 'SELECT ';
     if ($this->distinct) {
         $query .= 'DISTINCT ';
     }
     // FIELDS and EXPRESSIONS
     $fields = array();
     foreach ($this->tables as $alias => $table) {
         if (!empty($table['all_fields'])) {
             $fields[] = $this->connection->escapeTable($alias) . '.*';
         }
     }
     foreach ($this->fields as $alias => $field) {
         // Always use the AS keyword for field aliases, as some
         // databases require it (e.g., PostgreSQL).
         $fields[] = (isset($field['table']) ? $this->connection->escapeTable($field['table']) . '.' : '') . $this->connection->escapeField($field['field']) . ' AS ' . $this->connection->escapeAlias($field['alias']);
     }
     foreach ($this->expressions as $alias => $expression) {
         $fields[] = $expression['expression'] . ' AS ' . $this->connection->escapeAlias($expression['alias']);
     }
     $query .= implode(', ', $fields);
     // FROM - We presume all queries have a FROM, as any query that doesn't won't need the query builder anyway.
     $query .= "\nFROM ";
     foreach ($this->tables as $alias => $table) {
         $query .= "\n";
         if (isset($table['join type'])) {
             $query .= $table['join type'] . ' JOIN ';
         }
         // If the table is a subquery, compile it and integrate it into this query.
         if ($table['table'] instanceof SelectQueryInterface) {
             // Run preparation steps on this sub-query before converting to string.
             $subquery = $table['table'];
             $subquery->preExecute();
             $table_string = '(' . (string) $subquery . ')';
         } else {
             $table_string = '{' . $this->connection->escapeTable($table['table']) . '}';
         }
         // Don't use the AS keyword for table aliases, as some
         // databases don't support it (e.g., Oracle).
         $query .= $table_string . ' ' . $this->connection->escapeTable($table['alias']);
         if (!empty($table['condition'])) {
             $query .= ' ON ' . $table['condition'];
         }
     }
     // WHERE
     if (count($this->where)) {
         // The following line will not generate placeholders correctly if there
         // is a subquery. Fortunately, it is also called from getArguments() first
         // so it's not a problem in practice... unless you try to call __toString()
         // before calling getArguments().  That is a problem that we will have to
         // fix in Drupal 8, because it requires more refactoring than we are
         // able to do in Drupal 7.
         // @todo Move away from __toString() For SelectQuery compilation at least.
         $this->where->compile($this->connection, $this);
         // There is an implicit string cast on $this->condition.
         $query .= "\nWHERE " . $this->where;
     }
     // GROUP BY
     if ($this->group) {
         $query .= "\nGROUP BY " . implode(', ', $this->group);
     }
     // HAVING
     if (count($this->having)) {
         $this->having->compile($this->connection, $this);
         // There is an implicit string cast on $this->having.
         $query .= "\nHAVING " . $this->having;
     }
     // ORDER BY
     if ($this->order) {
         $query .= "\nORDER BY ";
         $fields = array();
         foreach ($this->order as $field => $direction) {
             $fields[] = $field . ' ' . $direction;
         }
         $query .= implode(', ', $fields);
     }
     // RANGE
     // There is no universal SQL standard for handling range or limit clauses.
     // Fortunately, all core-supported databases use the same range syntax.
     // Databases that need a different syntax can override this method and
     // do whatever alternate logic they need to.
     if (!empty($this->range)) {
         $query .= "\nLIMIT " . (int) $this->range['length'] . " OFFSET " . (int) $this->range['start'];
     }
     // UNION is a little odd, as the select queries to combine are passed into
     // this query, but syntactically they all end up on the same level.
     if ($this->union) {
         foreach ($this->union as $union) {
             $query .= ' ' . $union['type'] . ' ' . (string) $union['query'];
         }
     }
     if ($this->forUpdate) {
         $query .= ' FOR UPDATE';
     }
     return $query;
 }