Weblinks does not work for PostgreSQL anymore, at all. (After my previous patch, I was able to upgrade stuff to the latest version. But not use it :) )
It came down to redoing a lot of the code in _weblinks_get_query().
1)
The reason this started out with, is 'the standard one'. In Postgres (and other SQL92 compatible systems?) one:
- should always specify all non-aggregated fields of an aggregate query in the GROUP BY clause. (See the modification to weblinks_block.module in the patch)
- cannot do a query like 'SELECT DISCTINCT(n.x) FROM n ORDER BY n.y'. A 'distinct' query is also a kind of aggregate query and you cannot 'just' order on an unspecified field. That should also be mentioned in a GROUP BY. => it usually becomes something like 'SELECT n.x FROM n GROUP BY n.y, n.x ORDER BY n.y'.
2)
So I started out doing that, and discovered I could not just use $query. I split stuff out into $cols, $join, $where, ... to manipulate those separately, and see/test what the code was doing in all those cases, and in which cases I should add a GROUP BY clause.
3)
...and while testing, I discovered I never needed to group fields. I could just get rid of the DISTINCT altogether (because the queries would never return duplicate rows) if I just got rid of unnecessary join clauses.
I left the code block 'if ($groupby)' in just for your overview (so you can see if it ever comes in handy in the future) but it is not necessary now because $groupby is never set.
I removed the join on node_revisions fully, by the way, because it wasn't doing anything useful. And while typing this, I realise that we can also get rid of the join on 'weblinks' (except when $sort=='popular') if we just always include "n.type = 'weblinks'" in $where.
Patch is included, but I added the full changed code here for overview.
I tested this by creating some weblinks (unpublished ones, ones with zero, single and multiple categories, by multiple users). The weblinks overview page and all blocks work on mysql as well as postgres, and there is no visible 'before/after' change when testing mysql.
function _weblinks_get_query($tid = 0, $sort = 'title', $limit = 0) {
if ($tid === 'unpublished') {
$where = 'WHERE n.status = 0 ';
}
else {
$where = 'WHERE n.status = 1 ';
}
$join = 'INNER JOIN {weblinks} bw ON n.vid = bw.vid '; // acts as filter on {node}
// In some cases we need a join on term_node; in some we don't. We decide later according to $sort
if (function_exists('taxonomy_get_term')) {
if ($tid == 0) {
$join_tn = 'LEFT JOIN {term_node} tn ON tn.nid=n.nid AND tn.vid=n.vid ';
$where_tn = 'AND tn.nid IS NULL ';
}
else {
$join_tn = 'INNER JOIN {term_node} tn ON tn.nid=n.nid AND tn.vid=n.vid ';
$where_tn = 'AND tn.tid IN (%s) ';
}
}
else {
$join_tn = '';
$where_tn = '';
}
$groupby = FALSE;
$xgrpcols = '';
switch ($sort) {
case 'standard':
$cols = 'n.nid, n.sticky, n.created';
$join .= $join_tn;
$where .= $where_tn;
// $groupby = ($join_tn != '');
$order = 'ORDER BY n.sticky DESC, n.created ASC';
break;
case 'title':
$cols = 'n.nid, n.title';
$join .= $join_tn;
$where .= $where_tn;
// $groupby = ($join_tn != '');
// $xgrpcols = 'n.sticky'; // otherwise you can't order on it (at least not on pgsql)
$order .= 'ORDER BY n.sticky DESC, n.title ASC';
break;
case 'popular':
$cols = 'n.nid, bw.click_count, bw.last_click';
$where .= 'AND bw.click_count>0 ';
$order .= 'ORDER BY bw.click_count DESC, bw.last_click DESC';
break;
case 'user':
$cols = 'n.nid, n.sticky, n.created';
$where .= 'AND n.uid=%s ';
$order .= 'ORDER BY n.sticky, n.created';
break;
case 'recent':
$cols = 'n.nid, n.changed, n.title';
if ($tid != 0) {
$join .= $join_tn;
$where .= $where_tn;
// $groupby = ($join_tn != '');
}
$order .= 'ORDER BY n.changed DESC, n.title ASC';
break;
case 'random':
$cols = 'n.nid';
if ($tid != 0) {
$join .= $join_tn;
$where .= $where_tn;
}
$order .= 'ORDER BY RAND()';
break;
case 'count':
$cols = 'COUNT(n.nid)';
if ($tid !== 'unpublished') {
$join .= $join_tn;
$where .= $where_tn;
}
$order = '';
break;
}
if ($groupby) {
$groupby = 'GROUP BY ' . $cols;
if ($xgrpcols != '') {
$groupby .= ', ' . $xgrpcols;
}
$groupby .= ' ';
}
else {
$groupby = '';
}
$query = 'SELECT ' . $cols . ' FROM {node} n ' . $join . $where . $groupby . $order;
$query = db_rewrite_sql($query);
...
| Comment | File | Size | Author |
|---|---|---|---|
| weblinks-psql.patch | 5.7 KB | roderik |
Comments
Comment #1
rmiddle commentedThat join comes into effect when you have revisions turned on. You don't so there will be no duplicate entries and no revisions to worry about. But is some does have it turned on your cold wont work.
Thanks
Robert
Comment #2
roderikThe queries used to be built as follows, as you can see in the code (or in the deleted lines in my patch):
SELECT [ something ] from node n
INNER JOIN {node_revisions} nr ON nr.vid = n.vid
INNER JOIN {weblinks} bw ON bw.vid = nr.vid
Since the join to node_revisions was on vid (and not on nid), you might as well join node to weblinks directly. It really would not matter that there were multiple revisions. Older revisions are never selected anyway. (node.vid is always the vid of the latest revision. Right?)
(Logically I also fail to see why we would need to look into older revisions. Unless there was specific support in queries for that. But there isn't.)
Now,
- is there something I don't understand?
- was your code itself buggy? if so, please tell me what your intent was. Why / where would you want to do something with data in {node_revisions}?
- or does my code not actually need work?
Comment #3
roderikI don't know if this is somehow reassuring, but: I tested by making a new revision. I see the old revision in the database. It does not show up in lists.
Comment #4
nancydruThis is one of the "problems" of updating modules while trying to keep them backwards compatible (and we know Drupal's policy regarding backwards compatibility). Once upon a time, the query returned much more than just the nid, so node_revisions was needed. We simply didn't rethink whether it was still needed or not, so things just got added on.
We have had occasions to completely throw away some of the code and start from scratch, but the query has been there a "long" time without being rewritten. Perhaps it is time to do so, with the help of your patch.
I had a similar occasion just this morning in another module to realize that node_revisions was not important any more. Further, it was in regards to the D7 upgrade, so the ideas that I might think about are more towards being prepared to do that upgrade. That will entail splitting wheres, groups, etc out into separate specifications.
Comment #5
nancydruSee also #519040: PostgreSQL weblinks.install fixes
Comment #6
nancydruThank you for the patch. Please don't hesitate to let us know about Postgres issues, because neither Robert nor I have Postgres.
Committed.
Comment #7
roderikSee also #524198: last_click wrongly filled (no status change for this issue, just for archive-browsing sake)
Comment #8
nancydruIncluded in 6.x-2.1.