Background - if you use Views and activate the default 'archive' page it produces the following error:
'Exception: SELECT AS created_year_month, COUNT(node.nid) AS num_records
FROM
{node} node
WHERE (( (node.status = :db_condition_placeholder_0) ))
GROUP BY created_year_month
ORDER BY created_year_month DESC (prepared: SELECT AS created_year_month, COUNT(node.nid) AS num_records
FROM
"NODE" node
WHERE (( (node.status = :db_condition_placeholder_0) ))
GROUP BY created_year_month
ORDER BY created_year_month DESC ) e: SQLSTATE[HY000]: General error: 936 OCIStmtExecute: ORA-00936: missing expression
(/usr/share/php5/PDO_OCI-1.0/oci_statement.c:142) args: Array
(
[:db_condition_placeholder_0] => 1
)
'I have a test environment (same versions and all) that uses MySQL and looking at the query used for the archive page in Devel I see:
SELECT DATE_FORMAT((DATE_ADD('19700101', INTERVAL node.created SECOND) + INTERVAL -18000 SECOND), '%Y%m') AS created_year_month, COUNT(node.nid) AS num_records FROM node node WHERE (( (node.status = :db_condition_placeholder_0) )) GROUP BY created_year_month ORDER BY created_year_month DESC
Looking at the debug output produced by the Views module we clearly see that the "DATE_FORMAT((DATE_ADD('19700101', INTERVAL node.created SECOND) + INTERVAL -18000 SECOND), '%Y%m')" expression is being dropped. That's the first issue.
In MySQL the output of the query looks like:
mysql> SELECT DATE_FORMAT((DATE_ADD('19700101', INTERVAL node.created SECOND) + m_records FROM node node WHERE (( (node.status = 1) )) GROUP BY created_year_mon
+--------------------+-------------+
| created_year_month | num_records |
+--------------------+-------------+
| 201108 | 3 |
| 201107 | 2 |
+--------------------+-------------+
2 rows in set (0.00 sec) If you run the above query through the Oracle module's translator it doesn't do anything to "DATE_FORMAT((DATE_ADD('19700101', ........'%Y%m')" expression. I'm no expert but reading Oracle documentation, I don't see complementary DATE_FORMAT & DATE_ADD functions. Perhaps it's being dropped because it can't be translated properly.
I haven't looked at the drivers code closely enough to see how it handles Unix timestamp dates. I image it does something though. Just as a test I used a function I got from a website that formatted the Unix time called unixts_to_date(can post if needed) - it basically formats into (i.e. 17-JUL-11) format. The date is one thing, but the major issue I see in translation is that Oracle doesn't allow 'group by' with aliases - which is what the MySQL query does.
I had to use a nested query to get the same output as the MySQL in Oracle:
select created_year_month, COUNT(num_records) AS num_records FROM (
SELECT TO_CHAR(unixts_to_date(node.created), 'YYYYMM') AS created_year_month, node.nid AS num_records
from node where node.status = 1)
GROUP BY created_year_month
ORDER BY created_year_month DESCIs this something that can be fixed in the driver? I'm willing to contribute a patch but may need a little direction as to where to put things.
Thanks!
| Comment | File | Size | Author |
|---|---|---|---|
| #4 | views.patch | 2.01 KB | oshelot |
Comments
Comment #1
aaaristo commentedI think the date issue is in the date module.. Do you use it? I've patched it often in my envs... But i've not submitted it because often the contrib modules does not want to support non official core databases.
May be i can give you a working copy of the date module.
About the group by there is actually a function in the driver that handles it... but sometimes it fails. Probably the simplest solution in your case is to use the oracle_exception_queries setting (see http://drupal.org/node/860342#comment-3330524).
Comment #2
aaaristo commentedsorry i've seen now you was speaking about 7.x.. going to look at it
Comment #3
aaaristo commentedThe first issue is caused by this kind of code:
# find ./ -type f | xargs -n 10 grep 'pgsql'
./includes/handlers.inc: if (in_array(db_driver(), array('mysql', 'mysqli', 'pgsql'))) {
./includes/handlers.inc: if (db_driver() == 'pgsql') {
./includes/handlers.inc: case 'pgsql':
./includes/handlers.inc: case 'pgsql':
./includes/handlers.inc: case('pgsql'):
./includes/handlers.inc: case('pgsql'):
./includes/handlers.inc: case('pgsql'):
./views.install: if (db_driver() == 'pgsql') {
./views.install: if (db_driver() == 'pgsql') {
./views.install: if (db_driver() == 'pgsql') {
./plugins/views_plugin_query_default.inc: // $string = db_driver() == 'pgsql' ? "FIRST($string)" : $string;
./CHANGELOG.txt:#1029534 by bojanz: Fix like for pgsql by using db_like correct.
in the views module... Using case and if statements on the driver type is a known issue. They simply exclude oracle. So you can implement the oracle case and try to submit it (but i think they will not accept it cause oracle is not one of the core drivers).
Comment #4
oshelot commentedOk, I attached a views.patch to implement case/switch for oracle driver in views. Perhaps someone could review and tell me if I'm way off or something. I think much of Postgre was similar to Oracle so I was able to use it.
Yes, there was an issue with the module supporting Oracle, but the prepared statement being passed to the driver won't work in its current form. Let's compare MySQL/Oracle queries shall we:
MySQL =>
Oracle => (From Debug log)
BTW - the unixts_to_date function is simply (if something in the driver handles dates please tell me):
When the oracle query above runs it still throws the General error: 904 OCIStmtExecute: ORA-00904: "CREATED_YEAR_MONTH": invalid identifier since we are not explicitly selecting the 'group by' alias.
I guess the real question is whether this should be considered a driver bug or a defect with the module?
Thoughts?
Comment #5
oshelot commentedMissed the part about oracle_exception_queries in the first response. I will try to get that working in D7.
Comment #6
aaaristo commenteddrupal_timestamp.todate is the PL/SQL function you are looking for instead of unixts_to_date.
the group by is a known problem... i'm still evaluating the best way to solve it:
1. regular expression: is the way 6.x driver implement it, but often it fails...
2. you can use the oracle_exception_queries global variable in the settings.php to translate single statements (see http://drupal.org/node/860342#comment-3330524 the array.. )
3. write a SQL parser :( (like http://drupal.org/project/sql_parser)
Probably we should first try to enhance 1. And sooner or later go for 3 if duellj goes ahead...
About views, yes it is a views issue, that they don't want to fix:
http://drupal.org/node/758186
http://drupal.org/node/759276
Comment #7
aaaristo commentedmay be you can implement the solution they suggested (in the previous links)..
or even this http://drupal.org/node/858118
Comment #8
oshelot commentedWell, I got things working but I'm not at all proud at how I did it. Its a pretty nasty hack..but it works for what I want to do. Just in case anyone runs into the issue I'll give a brief overview.
I did try to use the oracle_exception_queries as discussed here http://drupal.org/node/860342#comment-3330524 but I couldn't get it to work. So I moved my focus to directly overriding the query in Views.
Where you do this is views/plugins/views_plugin_query_default.inc - You basically have to match a couple of conditions and then override. Where I modified (hacked) everything was in the function execute(&$view) - right after the queries begin building
I override with this:
I had to add in the preg_match after I got the basic count query stuff working. Why? Because if you use the default View code the base "archive" page doesn't work but the (for example) "archive/201108" does work (because it isn't counting anything) . So you have to force it to only override where the GROUP BY on the alias takes place. For these queries you also have to bypass {addMetaData, addTag, module_invoke_all, preExecute} with something like:
And finally, the default "$query->execute()" won't work (think because its not a PreparedStatement) with the override query so you have to execute with "db_query()". I did the following:
Not looking forward to any upgrades with the Views module! IMO, I don't think the driver should be expected to translate this type of query. I do wish Views had a better way to manage this stuff.
We can go ahead and close this issue.
Comment #9
aaaristo commentedThanks for the doc oshman.
Comment #10
cmurph commentedIf you're having a problem with the view in Oracle, and the following error coming back, see my post on the views issue tracker where I created a solution: http://drupal.org/node/1307658