The module is broken under PostgreSQL. The reason is that it contains code that compares date types with integer types using non SQL99-compliant implicit casting. See for example http://drupal.org/node/555536 and http://www.postgresql.org/docs/8.3/static/release-8-3.html (E.12.2.1). This results in errors like the following:

warning: pg_query() [function.pg-query]: Query failed: ERROR: operator does not exist: date >= integer LINE 6: FROM statspro WHERE day >= 20100731 ^ HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts. in /var/www/drupal/includes/database.pgsql.inc on line 139.
user warning: query: SELECT day, nuser, auser, nnode, cnode, comment, pi, upi, error, uerror, warning, uwarning, emergency, uemergency, alert, ualert, critical, ucritical FROM statspro WHERE day >= 20100731 in /var/www/drupal/sites/all/modules/statspro/statspro.inc on line 193.

Please fix this!

Comments

rsevero’s picture

Assigned: Unassigned » rsevero

First of all let me thank you for the bug report.

Unfortunately I won't be able to pay the adequate attention to it now as I'm really overloaded.

As a way to speed things up, do you know exactly what changes would be necessary in the SQL for PostgreSQL? If you could send me a corrected version of the SQL it would be really helpful.

lifepillar’s picture

As a way to speed things up, do you know exactly what changes would be necessary in the SQL for PostgreSQL?

Unfortunately, no. I know that casting issues are problematic to tackle in an cross-DBMS way. The best would be revising the design to avoid casts entirely, but I guess that this would be too much work.

The module generates many where clauses using the '%s >= %u' pattern. I know that enclosing the integer between single quotes (that is, '%s >= \'%u\') would work in both MySQL and PostgreSQL. I have tried to make such changes, but I still get query errors (or, maybe, I have generated different errors). I will try to look into the code further (I'd really need the module to work), but I cannot guarantee a patch.

rsevero’s picture

See what you can do.

If you manage to produce a working SQL command (both in MySQL and PostgreSQL) it would be great. This way I could make the patch.

lifepillar’s picture

Status: Active » Patch (to be ported)
StatusFileSize
new10.23 KB

Eventually, it was not too difficult to circumvent implicit casts: I just had to add more checks based on the value of $use_timestamp. Attached you find a patch, which I have tested with PostgreSQL 8.4 and it works for me. I have not tested it with MySQL, but I see no reason why it shouldn't work there as well.

In a couple of places, I have also changed dates of the form YYYY-MM-00 to YYYY-MM-01, because the former is not a valid date value in PostgreSQL. I have no idea whether this change would cause wrong ranges to be generated.

rsevero’s picture

Status: Patch (to be ported) » Postponed (maintainer needs more info)

Thanks for the patch. It will be of great help.

The first thing that attracted my attention is the places were you changed YYYY-MM-00 to YYYY-MM-01. In my quick look, YYYY-MM-00 was used as a parameter to strtotime. It produces a timestamp with which a parameter for SQL is created. It's not a parameter used directly in SQL so I believe this shouldn't be a problem for PostgreSQL.

I also believe these specific changes will produce wrong ranges.

Have the use of YYYY-MM-00 generated errors for you?

lifepillar’s picture

No, I did not get errors: that was precautionary :)

I do not understand the logic of get_last_day_of_* functions, actually. Say, get_last_day_of_month_from_reference contains the following conditional:

if ($use_timestamp) {
      $last = ($month == 12) ?
        ($year + 1) . '-01-01' :
        sprintf('%04u-%02u-01', $year, $month + 1);
    }
    else {
      $last = ($month == 12) ?
        $year . '-12-31' :
        sprintf('%04u-%02u-00', $year, $month + 1);
    }
    $last = strtotime($last);
    if (!$use_timestamp) {
      $last = date('Ymd', $last);
    }
    return $last;

As far as I can see, if $use_timestamp is false, that function returns a date in YYYYMMDD format. The latter is obtained by converting the $last timestamp, which, unless the month is December, has been obtained from a string YYYY-MM-00. Wouldn't this result in an invalid date? Or am I missing something?

rsevero’s picture

The catch is the use of "strtotime". It supports some rather exotic syntaxs and options that I took advantage of. Take a look at http://www.php.net/manual/en/datetime.formats.date.php

lifepillar’s picture

Ah, ok, date(strtotime('YYYY-MM-00')) yields a correct date. I agree, then, that there is no need to change the day to 01.

lifepillar’s picture

Status: Postponed (maintainer needs more info) » Patch (to be ported)
StatusFileSize
new9.79 KB

Here is the updated patch.

rsevero’s picture

Status: Patch (to be ported) » Fixed

Applied with http://drupal.org/cvs?commit=442696.

Thanks for your help and sorry for the long delay.

Status: Fixed » Closed (fixed)

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