#40417 [Bgs->Opn]: Suddenly binding as many vars as there are *identical* prepared tokens
ID: 40417 Updated by: [EMAIL PROTECTED] Reported By: exaton at free dot fr -Status: Bogus +Status: Open Bug Type: PDO related Operating System: Windows XP Pro SP2 PHP Version: 5.2.1 New Comment: This is really annoying issue, which forces me to rewrite some of the code I've done in the past. Perhaps the bindno shouldn't be incremented if the named placeholder already exists in the placeholders struct? Would it break something else? Previous Comments: [2007-02-24 08:47:52] exaton at free dot fr Wow. I'm flabbergasted. Mr Alshanetsky, I am, as they say, and until further notice, disappointed in you. No update of the CVS code. Not even a note in the manual to reflect this spec change. I guess this is going to have to wait until someone else reports it. It's got to be relatively common, especially in not too complex search engine implementations. Until then, therefore... [2007-02-24 03:19:49] [EMAIL PROTECTED] Thank you for taking the time to write to us, but this is not a bug. Please double-check the documentation available at http://www.php.net/manual/ and the instructions on how to report a bug at http://bugs.php.net/how-to-report.php . [2007-02-16 11:26:30] exaton at free dot fr Hey again people, I don't mean to be annoying, but I've just done a bit more research, so I thought I'd share it with you. Iliaa, I found the code change where you added the infamous spec-altering error check that I'm going on about : PHP_5_2 : http://cvs.php.net/viewcvs.cgi/php-src/ext/pdo/pdo_sql_parser.c?r1=1.35.2.6.2.3&r2=1.35.2.6.2.4 Also applied to MAIN, with both times the comment : "Added missing check for mismatching number of tokens & bound params in prepared statement emulation." That perfectly matches my error conditions. The problem is, the bindno variable contains the number of individual tokens. However, multiple tokens may have the same name ; but each token name can only be bound once ! So comparing bindno to the number of bindings is incorrect. It introduces the following specification : "multiple tokens may not have the same name in a prepared statement". The workaround is still the same : binding enough bogus tokens to match the number of individual tokens used in the prepared statement, when some share the same name. Oh, did I mention that this prevented anyone with prepared statements containing multiple tokens sharing the same name from upgrading to PHP 5.2.1 ? :-) [2007-02-10 17:18:20] exaton at free dot fr OK, I've taken a look at the source code to try and lend a hand in clearing up this issue. My first time though, so here's hoping I'm not too far off the mark. Diffing ext/pdo/ and ext/pdo_pgsql/ files between PHP 5.2.0 and 5.2.1, I find that the error message I am encountering is due to a new paragraph having been *added* to the much remangled ext/pdo/pdo_sql_parser.c (line 262) : if (params && bindno != zend_hash_num_elements(params) && stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) { pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "number of bound variables does not match number of tokens" TSRMLS_CC); ret = -1; goto clean_up; } Somehow I'm trigerring the error condition, here. I'm guessing that my bindno is different from the number of elements in the params hash table. bindno is incremented on line 214. I could be wrong, but I'm under the impression that it is *incremented with each _placeholder_*, which in turn I take to be the "token *instances*" we were talking about before. Now, I think we both agree that we only have to bind as many values/vars as there are *different* tokens in the statement. That is in any case how things worked up to PHP 5.2.0. With the new error detection that has been added (the above paragraph of code), and if I'm right about the way bindno is counted, then we are expected to bind as many values/vars as there are *placeholders* in the statement, even if there are 2 or more placeholders for the same token name. That would be very coherent with the new error I am getting. It would also be coherent with my workaround, in which one just had to bind extra, bogus values/vars (thus artificially filling up the params hash table, with params = stmt -> bound_params) in order to not get this error. So : 1) The new error detection breaks existing scripts that worked with 5.2.0. 2) I think we agree that the specification introduced by this new error detection is incorrect. One may, as far as I know, use several times the same placeholder for bound values/vars in a statement. It is only possible to bind a given token once (because that binding fills a hash table, which will of cou
#40417 [Bgs->Opn]: Suddenly binding as many vars as there are *identical* prepared tokens
ID: 40417 User updated by: exaton at free dot fr Reported By: exaton at free dot fr -Status: Bogus +Status: Open Bug Type: PDO related Operating System: Windows XP Pro SP2 PHP Version: 5.2.1 New Comment: I'm sorry, but I don't understand your reply. Perhaps my use of the word "token" is wrong. The multiple instances "count[ing] as one token, since they reference the same bound parameter" is exactly the behaviour I expect, and had been counting on *and getting* up to now. However, Re. my initial example and test case, *several bindings* are required, *as many as there are _instances_*, not just tokens. This is what is happening in PHP 5.2.1. 1) It differs from what I believe we both understand to be the correct behaviour. 2) Even if "binding as many times as there are *instances* of tokens" were the correct behaviour, we would have to conclude that the implementation was flawed up to PHP 5.2.0, because *existing code* breaks with the upgrade to PHP 5.2.1. My apologies again for insisting, but I think we're both on the same track here, with PHP 5.2.1 having introduced an incoherence on this point (maybe the code in pdo_pgsql.c compares the number of effective bindings to the number of ":" instances instead of the number of effectively different tokens...). Previous Comments: [2007-02-10 16:07:29] [EMAIL PROTECTED] Thank you for taking the time to write to us, but this is not a bug. Please double-check the documentation available at http://www.php.net/manual/ and the instructions on how to report a bug at http://bugs.php.net/how-to-report.php When you have multiple instances of :id they count as one token since they reference the same bound parameter. [2007-02-09 17:25:31] exaton at free dot fr All right, here you go, but it's really because I love you guys :) So, still comparing PHP 5.2.0 and PHP 5.2.1 on Windows XP Pro SP2 with a PostgreSQL 8.1.5 backend. >From phpinfo() concerning pdo_pgsql : PHP 5.2.0 : PostgreSQL(libpq) Version 8.1.4 Module version 1.0.2 Revision$Id: pdo_pgsql.c,v 1.7.2.11 2006/03/14 10:49:18 edink Exp $ PHP 5.2.1 : PostgreSQL(libpq) Version 8.1.4 Module version 1.0.2 Revision$Id: pdo_pgsql.c,v 1.7.2.11.2.1 2007/01/01 09:36:05 sebastian Exp $ So the difference is just in the revision of pdo_pgsql.c . Now for the test case ; I'll even give you a test table : CREATE TABLE t ( id INTEGER PRIMARY KEY, s TEXTNOT NULL ); INSERT INTO t (id, s) VALUES (1, 'foo'); INSERT INTO t (id, s) VALUES (2, 'bar'); INSERT INTO t (id, s) VALUES (3, 'doh'); INSERT INTO t (id, s) VALUES (4, 'duh'); And here's the PHP code : // Connect to database // Let $DATA be the resulting PDO object $sta = $DATA -> prepare('SELECT id, s FROM t WHERE id = :id OR id = :id'); // notice 2 identical ':id' tokens $sta -> bindValue(':id', 2, PDO :: PARAM_INT); // bind ':id' a single time, of course $sta -> execute(); // this is line #12 $arr = $sta -> fetch(PDO :: FETCH_ASSOC); echo ""; print_r($arr); echo ""; /* Expected (as obtained in PHP 5.2.0) : Array ( [id] => 2 [s] => bar ) */ /* Obtained in PHP 5.2.1 : PDOException thrown at ...\bug.php(12) SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens #0 ...\bug.php(12): PDOStatement->execute() #1 {main} */ Binding an extra token (to make up the 2 tokens in the prepared statement, even though they are identical) will work around the problem : $sta -> bindValue(':xyz', 42, PDO :: PARAM_INT); I think it should complain that the :xyz token is not to be found in the statement in the first place, but anyway (it doesn't make that complaint in PHP 5.2.0 either). By adding that line before the call to execute(), the expected result is obtained. Hope this helps ! [2007-02-09 16:58:09] [EMAIL PROTECTED] Thank you for this bug report. To properly diagnose the problem, we need a short but complete example script to be able to reproduce this bug ourselves. A proper reproducing script starts with , is max. 10-20 lines long and does not require any external resources such as databases, etc. If the script requires a database to demonstrate the issue, please make sure it creates all necessary tables, stored procedures etc. Please avoid embedding huge scripts into the report. [2007-02-09 16:39:14] exaton at free dot fr Description: I have just upgraded from PHP 5.2.0 to PHP 5.2.1, and one of my scripts has broken on the following point (note, the backend database is PostgreSQL 8.1.5) : Consider this prepared statement query, automatically generated