[Postgres] GROUP BY uses field names instead of aliases
| Project: | Views |
| Version: | 6.x-2.x-dev |
| Component: | Code |
| Category: | bug report |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | needs review |
| Issue tags: | PostgreSQL Code Sprint |
From the Postgres manual (at the bottom in the 'Namespace Available to GROUP BY and ORDER BY' section):
PostgreSQL also allows [GROUP BY] to specify arbitrary expressions. Note that names appearing in an expression will always be taken as input-column names, not as result-column names.
The problem with this is that Views 2 builds its queries with the alias of the base table's unique ID being the same as the field name. For example: a View with a base table of {users} will include users.uid AS uid in its SELECT statement. Instead of doing this, Views should generate an alias with the same form of other fields, table_field. For example: users.uid AS users_uid.
To reproduce, using a clean checkout of Drupal 6/Views 2.6:
- Ensure you Drupal/Views are setup to use a Postgres database ;)
- import the following View:
<?php
$view = new view;
$view->name = 'postgres_test_02';
$view->description = '';
$view->tag = '';
$view->view_php = '';
$view->base_table = 'node';
$view->is_cacheable = FALSE;
$view->api_version = 2;
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
$handler = $view->new_display('default', 'Defaults', 'default');
$handler->override_option('fields', array(
'nid' => array(
'label' => 'Nid',
'alter' => array(
'alter_text' => 0,
'text' => '',
'make_link' => 0,
'path' => '',
'link_class' => '',
'alt' => '',
'prefix' => '',
'suffix' => '',
'help' => '',
'trim' => 0,
'max_length' => '',
'word_boundary' => 1,
'ellipsis' => 1,
'strip_tags' => 0,
'html' => 0,
),
'link_to_node' => 0,
'exclude' => 0,
'id' => 'nid',
'table' => 'node',
'field' => 'nid',
'relationship' => 'nid',
),
'body' => array(
'label' => 'Body',
'alter' => array(
'alter_text' => 0,
'text' => '',
'make_link' => 0,
'path' => '',
'link_class' => '',
'alt' => '',
'prefix' => '',
'suffix' => '',
'help' => '',
'trim' => 0,
'max_length' => '',
'word_boundary' => 1,
'ellipsis' => 1,
'strip_tags' => 0,
'html' => 0,
),
'exclude' => 0,
'id' => 'body',
'table' => 'node_revisions',
'field' => 'body',
'relationship' => 'none',
),
));
$handler->override_option('filters', array(
'keys' => array(
'operator' => 'optional',
'value' => '',
'group' => '0',
'exposed' => TRUE,
'expose' => array(
'use_operator' => 0,
'operator' => 'keys_op',
'identifier' => 'keys',
'label' => 'Search: Search Terms',
'optional' => 1,
'remember' => 0,
),
'id' => 'keys',
'table' => 'search_index',
'field' => 'keys',
'relationship' => 'none',
),
));
$handler->override_option('access', array(
'type' => 'none',
));
$handler->override_option('cache', array(
'type' => 'none',
));
$handler->override_option('distinct', 0);
$handler->override_option('style_plugin', 'table');
$handler->override_option('style_options', array(
'grouping' => 'nid',
'override' => 1,
'sticky' => 0,
'order' => 'asc',
'columns' => array(
'nid' => 'nid',
'name' => 'name',
'name_1' => 'name_1',
'body' => 'body',
'last_comment_name' => 'last_comment_name',
),
'info' => array(
'nid' => array(
'sortable' => 0,
'separator' => '',
),
'name' => array(
'sortable' => 0,
'separator' => '',
),
'name_1' => array(
'sortable' => 0,
'separator' => '',
),
'body' => array(
'separator' => '',
),
'last_comment_name' => array(
'sortable' => 0,
'separator' => '',
),
),
'default' => '-1',
));
$handler->override_option('row_options', array(
'inline' => array(),
'separator' => '',
));
?> - Save and go back to the Views list, select 'Edit' on 'postgres_test_02'
- Press 'Preview' on the edit page
- Enter some text into the search box, 'test' will do
- Press 'Apply'
- See this error:
warning: pg_query() [function.pg-query]: Query failed: ERROR: column reference "nid" is ambiguous LINE 10: GROUP BY search_index.sid, nid, node_revisions_body, node_r... ^ in /home/liam/public_html/drupal6/includes/database.pgsql.inc on line 139.
The SQL generated by Views is:
SELECT node.nid AS nid,
SUM(search_index.score * search_total.count) AS score,
node_revisions.body AS node_revisions_body,
node_revisions.format AS node_revisions_format
FROM node node
LEFT JOIN search_index search_index ON node.nid = search_index.sid
LEFT JOIN search_total search_total ON search_index.word = search_total.word
LEFT JOIN node_revisions node_revisions ON node.vid = node_revisions.vid
WHERE (search_index.word = 'test') AND (search_index.type = 'node')
GROUP BY search_index.sid, nid, node_revisions_body, node_revisions_format
HAVING COUNT(*) >= 1Notice the first line: SELECT node.nid AS nid, then where Postgres gets confused because it believes 'nid' refers to the field, and finds two of them: GROUP BY [...] nid, [...]

#1
tagging for next Postgres Code Spring
#2
Subscribing
#3
Hi two questions:
1. Does anyone know when the next code sprint for postgres will be? This bug is breaking a large portion of my views, so i'd like to make some plans around what to do. :-)
2. Does anyone know if this bug is also present in 3.x / 2.5 ? I could just upgrade / downgrade if not.
Thanks!
Patrick
#4
@phayes the New Zealand based team will likely have another mini-code sprint a couple weeks after Drupalcon.
#5
I can confirm that this error also exists for 2.7 ... i assume its also in the current 2.x-dev version.
#6
With the help of Damz (via irc) and fuerst we where able to fix the problem. Patch attached!
#7
#6: That patch only works if the field is a real field. If it is a formula, I think that patch will cause errors. Try a date field, for example.
#8
I extended the above view with a date field (field_event_date) and got the below listed query. At least there is no error. Is there a way to check if it's a formula or a real field? Shouldn't be $field['table'] (line 969) and $this->base_table (line 907) be empty, if it is a formula?
SELECT node.nid AS nid,
SUM(search_index.score * search_total.count) AS score,
node_revisions.body AS node_revisions_body,
node_revisions.format AS node_revisions_format,
node_data_field_event_date.field_event_date_value AS node_data_field_event_date_field_event_date_value,
node.type AS node_type,
node.vid AS node_vid
FROM node node
LEFT JOIN search_index search_index ON node.nid = search_index.sid
LEFT JOIN search_total search_total ON search_index.word = search_total.word
LEFT JOIN node_revisions node_revisions ON node.vid = node_revisions.vid
LEFT JOIN content_type_event node_data_field_event_date ON node.vid = node_data_field_event_date.vid
WHERE (search_index.word = 'lorem') AND (search_index.type = 'node')
GROUP BY search_index.sid, node.nid, node_revisions.body, node_revisions.format, node_data_field_event_date.field_event_date_value, node.type, node.vid
HAVING COUNT(*) >= 1
#9
DamZ said " the first hunk is fine" and he suggested to check $field['table'] like:
<?php$non_aggregates[] = (!empty($field['table']) ? $field['table'] . '.' : '') . $field['field'];
?>
Patch changed.