includes/database/database.inc | 13 +++++++ includes/database/pgsql/query.inc | 52 ++++++++++++++++++++++++++++ includes/database/select.inc | 4 +- modules/search/search.extender.inc | 9 +++-- modules/simpletest/tests/entity_query.test | 12 ++++-- 5 files changed, 80 insertions(+), 10 deletions(-) diff --git includes/database/database.inc includes/database/database.inc index 933ceb2..8e25f6e 100644 --- includes/database/database.inc +++ includes/database/database.inc @@ -810,6 +810,19 @@ abstract class DatabaseConnection extends PDO { } /** + * Escapes a alias name string. + * + * Force all alias names to be strictly alphanumeric-plus-underscore. In + * contrast to escapeField()/Table, this doesn't allow the point. + * + * @return + * The sanitized field name string. + */ + public function escapeAlias($field) { + return preg_replace('/[^A-Za-z0-9_]+/', '', $field); + } + + /** * Escapes characters that work as wildcard characters in a LIKE pattern. * * The wildcard characters "%" and "_" as well as backslash are prefixed with diff --git includes/database/pgsql/query.inc includes/database/pgsql/query.inc index 8825229..d2d155b 100644 --- includes/database/pgsql/query.inc +++ includes/database/pgsql/query.inc @@ -189,4 +189,56 @@ class SelectQuery_pgsql extends SelectQuery { return $this; } + /** + * Overrides SelectQuery::orderBy(). + * + * Automatically adds columns that are ordered on as fields. + */ + public function orderBy($field, $direction = 'ASC') { + $return = parent::orderBy($field, $direction); + // If there is a table alias specified, split it up. + if (strpos($field, '.') !== FALSE) { + list($table, $table_field) = explode('.', $field); + } + // Figure out if the field has already been added. + foreach ($this->fields as $existing_field) { + if (!empty($table)) { + // If table alias is given, check if field and table exists. + if ($existing_field['table'] == $table && $existing_field['field'] == $table_field) { + return $return; + } + } + else { + if ($existing_field['alias'] == $field) { + return $return; + } + } + } + + // The field could also be an alias for an expression. + foreach ($this->expressions as $expression) { + if ($expression['alias'] == $field) { + return $return; + } + } + + // If there is a table which loads all fields, we can't do this because we + // might produce illegal aliases. + foreach ($this->tables as $table) { + if (!empty($table['all_fields'])) { + return $return; + } + } + + // If the field is actually an expression, it can not be added either. + if ($this->connection->escapeField($field) != $field) { + return $return; + } + + // This is a case that can be handled automatically, add the field. + $this->addField(NULL, $field); + return $return; + } + + } diff --git includes/database/select.inc includes/database/select.inc index 893e162..5de5d8c 100644 --- includes/database/select.inc +++ includes/database/select.inc @@ -1373,10 +1373,10 @@ class SelectQuery extends Query implements SelectQueryInterface { 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->escapeField($field['alias']); + $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 ' . $expression['alias']; + $fields[] = $expression['expression'] . ' AS ' . $this->connection->escapeAlias($expression['alias']); } $query .= implode(', ', $fields); diff --git modules/search/search.extender.inc modules/search/search.extender.inc index ebab182..f6468ec 100644 --- modules/search/search.extender.inc +++ modules/search/search.extender.inc @@ -415,10 +415,6 @@ class SearchQuery extends SelectQueryExtender { // Add default score. $this->addScore('i.relevance'); } - if (count($this->getOrderBy()) == 0) { - // Add default order. - $this->orderBy('calculated_score', 'DESC'); - } if (count($this->multiply)) { // Add the total multiplicator as many times as requested to maintain @@ -436,6 +432,11 @@ class SearchQuery extends SelectQueryExtender { // Convert scores to an expression. $this->addExpression('SUM(' . implode(' + ', $this->scores) . ')', 'calculated_score', $this->scoresArguments); + if (count($this->getOrderBy()) == 0) { + // Add default order after adding the expression. + $this->orderBy('calculated_score', 'DESC'); + } + // Add tag and useful metadata. $this ->addTag('search_' . $this->type) diff --git modules/simpletest/tests/entity_query.test modules/simpletest/tests/entity_query.test index f1c9e64..5890cb7 100644 --- modules/simpletest/tests/entity_query.test +++ modules/simpletest/tests/entity_query.test @@ -501,16 +501,20 @@ class EntityFieldQueryTestCase extends DrupalWebTestCase { $query = new EntityFieldQuery(); $query ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', 1, 'CONTAINS'); + ->propertyCondition('fttype', 'und', 'CONTAINS'); $this->assertEntityFieldQuery($query, array( array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), ), t('Test the "contains" operation on a property.')); $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[0], 'value', 3, 'CONTAINS'); + $query->fieldCondition($this->fields[1], 'shape', 'uar', 'CONTAINS'); $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 3), - array('test_entity', 3), + array('test_entity_bundle', 5), ), t('Test the "contains" operation on a field.')); $query = new EntityFieldQuery();