* warning: pg_query() [function.pg-query]: Query failed: ERREUR: clauses ORDER BY multiples non autorisées in /home/html/test/includes/database.pgsql.inc on line 139.
    * user warning: query: (SELECT thread FROM comments WHERE nid = 63743 AND status = 0 ORDER BY timestamp DESC LIMIT 136) ORDER BY thread DESC LIMIT 1 in /home/html/test/modules/comment/comment.module on line 366.
    * warning: pg_query() [function.pg-query]: Query failed: ERREUR: clauses ORDER BY multiples non autorisées in /home/html/test/includes/database.pgsql.inc on line 139.
    * user warning: query: (SELECT thread FROM comments WHERE nid = 67329 AND status = 0 ORDER BY timestamp DESC LIMIT 56) ORDER BY thread DESC LIMIT 1 in /home/html/test/modules/comment/comment.module on line 366.
    * warning: pg_query() [function.pg-query]: Query failed: ERREUR: clauses ORDER BY multiples non autorisées in /home/html/test/includes/database.pgsql.inc on line 139.
    * user warning: query: (SELECT thread FROM comments WHERE nid = 49805 AND status = 0 ORDER BY timestamp DESC LIMIT 326) ORDER BY thread DESC LIMIT 1 in /home/html/test/modules/comment/comment.module on line 366.
    * warning: pg_query() [function.pg-query]: Query failed: ERREUR: clauses ORDER BY multiples non autorisées in /home/html/test/includes/database.pgsql.inc on line 139.
    * user warning: query: (SELECT thread FROM comments WHERE nid = 66944 AND status = 0 ORDER BY timestamp DESC LIMIT 125) ORDER BY thread DESC LIMIT 1 in /home/html/test/modules/comment/comment.module on line 366.
    * warning: pg_query() [function.pg-query]: Query failed: ERREUR: clauses ORDER BY multiples non autorisées in /home/html/test/includes/database.pgsql.inc on line 139.
    * user warning: query: (SELECT thread FROM comments WHERE nid = 58110 AND status = 0 ORDER BY timestamp DESC LIMIT 14) ORDER BY thread DESC LIMIT 1 in /home/html/test/modules/comment/comment.module on line 366.
    * warning: pg_query() [function.pg-query]: Query failed: ERREUR: clauses ORDER BY multiples non autorisées in /home/html/test/includes/database.pgsql.inc on line 139.
    * user warning: query: (SELECT thread FROM comments WHERE nid = 66801 AND status = 0 ORDER BY timestamp DESC LIMIT 165) ORDER BY thread DESC LIMIT 1 in /home/html/test/modules/comment/comment.module on line 366.
    * warning: pg_query() [function.pg-query]: Query failed: ERREUR: clauses ORDER BY multiples non autorisées in /home/html/test/includes/database.pgsql.inc on line 139.
    * user warning: query: (SELECT thread FROM comments WHERE nid = 67321 AND status = 0 ORDER BY timestamp DESC LIMIT 58) ORDER BY thread DESC LIMIT 1 in /home/html/test/modules/comment/comment.module on line 366.
<code>

        <code>$result = db_query('(SELECT thread FROM {comments} WHERE nid = %d  AND status = 0 ORDER BY timestamp DESC LIMIT %d) ORDER BY thread DESC LIMIT 1', $node->nid, $new_replies);

Should be:

$result = db_query('SELECT thread FROM {comments} WHERE cid IN (SELECT cid FROM comments WHERE nid = %d AND status = 0 ORDER BY timestamp DESC LIMIT %d) ORDER BY thread DESC LIMIT 1', $node->nid, $new_replies);

The same applies for:

$result = db_query('(SELECT thread FROM {comments} WHERE nid = %d AND status = 0 ORDER BY timestamp DESC LIMIT %d) ORDER BY SUBSTRING(thread, 1, (LENGTH(thread) - 1)) LIMIT 1', $node->nid, $new_replies);

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

grub3’s picture

SEcond query should be:

$result = db_query('(SELECT thread FROM {comments} WHERE cid IN (SELECT cid FROM {comments} WHERE nid = %d AND status = 0 ORDER BY timestamp DESC LIMIT %d) ORDER BY SUBSTRING(thread, 1, (LENGTH(thread) - 1)) LIMIT 1', $node->nid, $new_replies);

grub3’s picture

Priority: Normal » Critical

Update to critical as all forum running under PostgreSQL should have the same problem.

Damien Tournoud’s picture

Could you point us to where this is actually documented?

grub3’s picture

I don't know where this is documented. Actually the message displays "clauses ORDER BY multiples non autorisées", which means "multiple ORDER BY not authorized".

The query I provided is a traditional nested query. I can be executed on any database. MySQL query analyser should rewrite the query as a traditional nested query with some kind of IN. Therefore there is no degradation using the SQL query I provided.

If MySQL has some kind of SQL parser, try looking how MySQL rewrites the query.

grub3’s picture

The idea behind this fix is that when you write this MySQLism, MySQL is going to rewrite the query inside the engine. It will surely not execute like that. So it is better to write the correct SQL directly and there is no time execution loss.

Damien Tournoud’s picture

@jmpoure: you can really not call that query an "MySQLism", especially if you can't point us to where it is documented that you can't have an ORDER in a FROM-based subquery.

grub3’s picture

A database should always know how it should run joins.

(SELECT thread FROM comments WHERE nid = 63743 AND status = 0 ORDER BY timestamp DESC LIMIT 136) ORDER BY thread DESC LIMIT 1
is not a standard query. I can be rewritten internaly in MySQL as a subquery or a join.

To know whether this is a standard query, you can access the analyser in the database and read how the query is rewritten.
MySQL will not execute(SELECT thread FROM comments WHERE nid = 63743 AND status = 0 ORDER BY timestamp DESC LIMIT 136) ORDER BY thread DESC LIMIT 1 directlty. The parser will rewrite it and you wron't see it.

So it is better to write a standard query where you see the JOIN or the SUBQUERY. Anyway PostgreSQL is picky and will not accept this SQL clause, probably because it is not standard. PostgreSQL hackers usualy don't accept non-standard queries. It could take them 5 minutes to modify PostgreSQL core, but if it is not standard, they don't accept it. If you know FFmpeg, the same applies for Video and Audio codecs. If it is not standard, even a simple hack, core hackers do not accept something non-compliant with standards. This is not my fault.

Using MySQL is like using Windows 95. You always run into problems that you don't know how to analyse because you don't see what is "inside".

If this is standard SQL, I apologize in advance, but I doubt.

jaydub’s picture

All comments regarding standard or non-standard aside, the fact that the query fails should be of primary concern. I can verify that the query fails in PostgreSQL. I tried the suggested alternative query in the parent issue and while that -does- work in PostgreSQL, it does not work in MySQL 5:

mysql> SELECT thread FROM comments WHERE cid IN (SELECT cid FROM comments WHERE nid = 307 AND status = 0 ORDER BY timestamp DESC LIMIT 1) ORDER BY thread DESC LIMIT 1;
ERROR 1235 (42000): This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
jaydub’s picture

How about this?

 $result = db_query('SELECT thread FROM {comments} c INNER JOIN (SELECT cid FROM {comments} WHERE nid = %d AND status = 0 ORDER BY timestamp DESC LIMIT %d) c2 ON c.cid = c2.cid ORDER BY thread DESC LIMIT 1', $node->nid, $new_replies);

That at least didn't throw an error both in MySQL and PostgreSQL.

brianV’s picture

Version: 6.10 » 6.x-dev

According to PostgreSQL's documentation,

ORDER BY Clause

The optional ORDER BY clause has this general form:

ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...]

The ORDER BY clause causes the result rows to be sorted according to the specified expression(s). If two rows are equal according to the leftmost expression, they are compared according to the next expression and so on. If they are equal according to all specified expressions, they are returned in an implementation-dependent order.

... snip ...

Note that ordering options apply only to the expression they follow; for example ORDER BY x, y DESC does not mean the same thing as ORDER BY x DESC, y DESC.

So it appears that multiple ORDER BY statements are legitimate.

brianV’s picture

Jay,

You should work off the CVS code. The current CVS for this statement is:

 $result = db_query_range('(SELECT thread
      FROM {comment}
      WHERE nid = :nid
        AND status = 0
      ORDER BY timestamp DESC)
      ORDER BY SUBSTRING(thread, 1, (LENGTH(thread) - 1))', array(':nid' => $node->nid), 0, $new_replies)
      ->fetchField(); 

Actually, can you test if this CVS code gives the same issues under PostgreSQL?

grub3’s picture

Sorry, I feel stupid. It added this code to my SVN drupal installation but don't know in which situation I should test it. What kind of comments does it display? Sorry, I feel lost and stupid.

Damien Tournoud’s picture

In fact, it seems like this is just a syntax issue:

(SELECT thread FROM {comments} WHERE nid = %d  AND status = 0 ORDER BY timestamp DESC LIMIT %d) ORDER BY thread DESC LIMIT 1

... is an implicit FROM subquery. The syntax is apparently valid on MySQL, but not on PostgreSQL, so we should write:

SELECT thread FROM (SELECT thread FROM {comments} WHERE nid = %d  AND status = 0 ORDER BY timestamp DESC LIMIT %d) ORDER BY thread DESC LIMIT 1
Norbert Poellmann’s picture

No, I don't agree to multiple ORDER BY statements in postgres.
http://www.postgresql.org/docs/8.3/interactive/sql-select.html
talks about The ORDER BY clause (not clauses) and the syntax shows only
one (optional) ORDER BY clause per SELECT statement.:

The optional ORDER BY clause has this general form:
ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...]

That means: you can have one or more specified expression(s)
(indicated by [, ...]), but only one ORDER BY clause

Instead of:

(SELECT thread FROM comments WHERE nid = 63743 AND status = 0 ORDER BY timestamp DESC LIMIT 136) ORDER BY thread DESC LIMIT 1 ;

it should simply say:
SELECT thread FROM comments WHERE nid = 63743 AND status = 0
ORDER BY timestamp DESC , thread DESC LIMIT 1 ;

Damien Tournoud’s picture

@Norbert: see my comment #13, it's nothing more then a syntax issue: MySQL read the query as an implicit sub-query on FROM, which is what we want. Making the subquery explicit should solve the issue.

Instead of:
(SELECT thread FROM comments WHERE nid = 63743 AND status = 0 ORDER BY timestamp DESC LIMIT 136) ORDER BY thread DESC LIMIT 1 ;

it should simply say:
SELECT thread FROM comments WHERE nid = 63743 AND status = 0
ORDER BY timestamp DESC , thread DESC LIMIT 1 ;

No, those are not the same queries (see the difference in the LIMIT clauses).

Damien Tournoud’s picture

Version: 6.x-dev » 7.x-dev

Bumping to D7 to quick fix that there (and add a test for that...), before backporting.

Damien Tournoud’s picture

Alex_Tutubalin’s picture

Folks!
(i'm author of bugreport and patch #237509 which is duplicate to this bug)

As I can see

1. PosgreSQL does not supports multiple ORDER BY
2. MySQL does not supports LIMIT within subquery
3. comment.module really needs two ORDER BYs (first select N latest comments, than select highest thread id in them)

The only way is to use
if ( $GLOBALS['db_type']=='pgsql')
{
pgsql query
}
else
{ mysql query.

So, patch is trivial, just combine my patch from http://drupal.org/node/462270 to these ugly if-s

Damien Tournoud’s picture

@Alex Tutubalin:

MySQL does support LIMIT inside sub-queries (of course... the current code, that is an implicit subquery works). The only thing left to do is to roll a patch according to my suggestion in #13.

Alex_Tutubalin’s picture

@Damien

This is different queries.
First one selects Top N threads by timestamp, than maximum thread ID in these N top-timestamp;
Second one will effectively selects latest (by timestamp).

Again, my solution is
- Left MySQL query as is (assuming that two order-by-s is doing right thing)
- Make special PgSQL query (subselect with Order-by/Limit)
Select between two queries at PHP level by GLOBALS[pg_type]

This should work, althought not beautiful solution.

Damien Tournoud’s picture

@Alex_Tutubalin: Please read carefully. This query is what we want and it should work the same on both PostgreSQL and MySQL:

SELECT thread FROM (SELECT thread FROM {comments} WHERE nid = %d  AND status = 0 ORDER BY timestamp DESC LIMIT %d) ORDER BY thread DESC LIMIT 1
Alex_Tutubalin’s picture

Have you check it on MySQL ?

Also, on PgSQL 8.3 you should use slightly different syntax
SELECT column FROM (SELECT ....) AS column ORDER BY... LIMIT...

Damien Tournoud’s picture

SELECT thread FROM (SELECT thread FROM {comments} WHERE nid = %d AND status = 0 ORDER BY timestamp DESC LIMIT %d) AS last_threads ORDER BY thread DESC LIMIT 1

works perfectly on MySQL.

Alex_Tutubalin’s picture

So, my patch from http://drupal.org/node/462270 should work.

andypost’s picture

Josh Waihi’s picture

Issue tags: +PostgreSQL Code Sprint

tagging properly

Shiny’s picture

Assigned: Unassigned » Shiny
Status: Active » Needs review
Issue tags: -PostgreSQL Code Sprint
FileSize
1.68 KB

attaching patch by Alex_Tutubalin, which i am testing at the Postres Code Sprint

Status: Needs review » Needs work

The last submitted patch failed testing.

Shiny’s picture

Status: Needs work » Needs review

So far i can't replicate this error - i've tried in D6 and D7
Can someone please add the steps to make this error occur? Then i can verify it is fixed by the patch.
(otherwise the patch looks very sane and safe for D6 - needs re-rolling for D7).

andypost’s picture

FileSize
1.07 KB

#27 was for drupal6

Now patch for D7

But suppose reply for comments are broken in d7

Status: Needs review » Needs work

The last submitted patch failed testing.

deekayen’s picture

Status: Needs work » Needs review

misbehaving bot

andypost’s picture

Bot passed all tests

Damien Tournoud’s picture

Status: Needs review » Reviewed & tested by the community

Makes total sense, and the bot is happy.

Damien Tournoud’s picture

Title: PostgreSQL does not allow multiple ORDER BY clauses » Fix syntax of comment ordering subquery

There have been a lot of back and forth in this issue, so here is some clarification for the core committers.

The issue here is that we have a query that has an invalid syntax:

(SELECT thread FROM {comments} WHERE nid = %d  AND status = 0 ORDER BY timestamp DESC LIMIT %d) ORDER BY thread DESC LIMIT 1

It is an implicit FROM-based subquery (we first get the threads of the latest comments, then we order them by thread).

MySQL happily deals with this query, even if it is invalid, but PostgreSQL ignore the parenthesis and return a cryptic "Multiple ORDER BY clauses are not allowed).

The patch simply transforms this query into:

SELECT thread FROM (SELECT thread FROM {comments} WHERE nid = %d  AND status = 0 ORDER BY timestamp DESC LIMIT %d) AS thread ORDER BY thread DESC LIMIT 1
andypost’s picture

I post new issue related to comment ordering #529374: Reply on comment is broken
Maybe this one should be fixed first

Status: Reviewed & tested by the community » Needs work

The last submitted patch failed testing.

andypost’s picture

Status: Needs work » Needs review

Let's re-test

andypost’s picture

Status: Needs review » Reviewed & tested by the community

Looks like bot was broken so rtbc

webchick’s picture

Status: Reviewed & tested by the community » Fixed

Committed to HEAD. Thanks!

Damien Tournoud’s picture

Version: 7.x-dev » 6.x-dev
Assigned: Shiny » Unassigned
Status: Fixed » Patch (to be ported)

We need to backport this.

andypost’s picture

Status: Patch (to be ported) » Needs review
FileSize
1.96 KB

Reroll #27

grub3’s picture

Thanks. Will review shorly as I am back from holidays. Sorry for the delay.

grub3’s picture

The patch works as expected. I tested on my D6 forums.
Hope this can be applied ASAP.
It seems straightforward and will not break anything.

Thanks!

grub3’s picture

Please inform us when it is committed to CVS.

Dave Reid’s picture

Status: Needs review » Needs work

Extra space in the SQL.

@jmpoure: Please read http://drupal.org/node/317.

andypost’s picture

FileSize
1.96 KB

So here reroll without extra space

andypost’s picture

Status: Needs work » Needs review

And status change... sorry

grub3’s picture

Thank you Andy and Damien.

In Guidelines for writing MySQL and PostgreSQL compliant SQL
read MySQLism: avoid nested ORDER BY, use nested queries

This describes the SQL-99 standard and how to rewrite nested ORDER BY.

So you can apply the patch safely.
The query will execute very well under PostgreSQL and MySQL.

We hope that the quide will improve Drupal conformance to SQL-99.

andypost’s picture

Need another review to rtbc this!

lambic’s picture

Status: Needs review » Reviewed & tested by the community

looks good

Gábor Hojtsy’s picture

Who tested this on an actual Drupal 6 setup on MySQL? I'm seeing people tested the standalone query which was formed into the patch and people also tested the patch on PostgreSQL, but nobody tested the patch on MySQL, right?

Dave Reid’s picture

Status: Reviewed & tested by the community » Needs work

I don't get the same result between the new and old queries. New query also didn't pass the SQL-99 validator (http://developer.mimer.com/validator/parser99/index.tml)

andypost’s picture

@Dave I found no difference betwen old and new query on mysql 5.0.51a (debian). Please provide more info about your env

bellHead’s picture

Status: Needs work » Reviewed & tested by the community

I've applied the patch to a D6 on both Postgres and mysql. The Postgres instance worked after the patch and not before. Mysql instance works either way.

The two queries return exactly the same results against mysql on a 50000 node generated test set with up to 150 comments per node and a random new_replies between 3 and 10.

The validator at mimer doesn't seem to like the ORDER BY or LIMIT in the subquery. I can't find anything in the spec forbidding them though.

Gábor Hojtsy’s picture

Status: Reviewed & tested by the community » Fixed

Thanks, committed to Drupal 6 as well.

Status: Fixed » Closed (fixed)
Issue tags: -PostgreSQL Surge

Automatically closed -- issue fixed for 2 weeks with no activity.