[long] Win32 / ODBC failure

From: Date: Wed, 09 Aug 2000 11:25:01 +0000
Subject: [long] Win32 / ODBC failure
Groups: php.dev 
Request: Send a blank email to php-dev+get-28239@lists.php.net to get a copy of this message
Hi, I'm developing a site for a customer using PHP4. It will reside on an NT server using an ODBC connection to a MS SQL datasource. I'm testing it on NT, with a connection to a local Access database (using ODBC) and a connection to a MySQL datasource on another box (again using ODBC). I'm having problems with SQL queries that have parameters. Using Access I get nowhere at all: Warning: SQL error: [Microsoft][ODBC Microsoft Access Driver]COUNT field incorrect , SQL state 07001 in SQLExecute in C:\InetPub\wwwroot\testsql.php on line 79 using MySQL I get a different error: FATAL: emalloc(): Unable to allocate 268665117 bytes (followed by a dump of locations where it allocated memory) (the number of bytes is always the same) The test script is very simple, I've attached it to this message. I think there are problems in ext/odbc/php_odbc.c - there is no return checking in the function PHP_FUNCTION(odbc_execute). Here is the problem (as I see it). It helps if you look at this ODBC dump from the NT box: [snip] editclient c4:ab ENTER SQLDescribeParam HSTMT 0x00a61a50 UWORD 1 SWORD * 0x0012ec2c UDWORD * 0x0012ec28 SWORD * 0x0012ec24 SWORD * 0x0012ec32 editclient c4:ab EXIT SQLDescribeParam with return code -1 (SQL_ERROR) HSTMT 0x00a61a50 UWORD 1 SWORD * 0x0012ec2c UDWORD * 0x0012ec28 SWORD * 0x0012ec24 SWORD * 0x0012ec32 DIAG [IM001] [Microsoft][ODBC Driver Manager] Driver does not support this function (0) editclient c4:ab ENTER SQLBindParameter HSTMT 0x00a61a50 UWORD 1 SWORD 1 <SQL_PARAM_INPUT> SWORD 1 <SQL_C_CHAR> SWORD 30592 <unknown> UDWORD 108 SWORD 0 PTR 0x00569ff0 SDWORD 0 SDWORD * 0x0056f6a0 editclient c4:ab EXIT SQLBindParameter with return code -1 (SQL_ERROR) HSTMT 0x00a61a50 UWORD 1 SWORD 1 <SQL_PARAM_INPUT> SWORD 1 <SQL_C_CHAR> SWORD 30592 <unknown> UDWORD 108 SWORD 0 PTR 0x00569ff0 SDWORD 0 SDWORD * 0x0056f6a0 DIAG [S1004] [Microsoft][ODBC Microsoft Access Driver]Invalid SQL data type (67) [snip] I think that the code ignores the error from SQLDescribeParam, then passes uninitialised variables to SQLBindParameter. If this is the case, the following should work around this error: --- php_odbc.c.orig Wed Aug 9 12:07:51 2000 +++ php_odbc.c Wed Aug 9 12:13:03 2000 @@ -825,8 +825,13 @@ RETURN_FALSE; } - SQLDescribeParam(result->stmt, (UWORD)i, &sqltype, &precision, + rc = SQLDescribeParam(result->stmt, (UWORD)i, &sqltype, &precision, &scale, &nullable); + if (rc=SQL_ERROR){ + /* work around servers that don't support SQLDescribeParam */ + scale=0; + sqltype=SQL_CHAR; //assume char + } params[i-1].vallen = (*tmp)->value.str.len; params[i-1].fp = -1; I would like to do more testing myself, but I can't get the source to compile on NT. Is there an NT compilation HOWTO anywhere? I could work with someone who can compile it if that would be alright, I could debug and code, someone else could code and compile. The error message I got from odbc->mysql leads me to believe that a similar thing is happening there, an error return is being ignored and an emalloc is attempted with a huge bogus size due to an uninitialised variable, or an error code. Jon. -- Jon Evans / Red Internet Ltd. / +44 1869 337977

<?php // SQL server test script // Jon Evans <jevans@red-net.co.uk> // creates a table called redtesttable // adds some data to it // reads the data back from it // deletes the table // The name of the ODBC data source for the SQL server: $sqlserver = "test"; // The username and password to access the above server: $username = ""; $password = ""; // The name of the test table to create // WARNING the table will be dropped when the script finishes running $testtablename = "redtesttable"; // =================================== echo "<p>making connection to ODBC data source '$sqlserver':"; $conn = odbc_connect($sqlserver, $username, $password); if (!$conn){ echo "<p>failed to connect!"; exit; } //======================================= // Errors ignored for this one as it will fail // anyway if the table doesn't already exist echo "<p>dropping table '$testtablename'"; $sql = "drop table $testtablename;"; @$ret = odbc_exec($conn, $sql); if (!$ret) { echo "<p>failed to drop test table, carrying on anyway..."; } //======================================= echo "<p>creating a table '$testtablename'"; $sql = "create table $testtablename (ID int not null, "; $sql .= "test_a varchar(255), test_b varchar(255), test_c int);"; $ret = odbc_exec($conn, $sql); if (!$ret) { echo "<p>failed to make test table!"; exit; } //======================================= echo "<p>inserting data into table '$testtablename'<p>"; $sql = "insert into $testtablename (test_a, test_b, test_c) values (?, ?, ?);"; $sth = odbc_prepare($conn, $sql); if (!$sth) { echo "<p>failed to prepare query!"; exit; } for ($i =0; $i<30; $i++){ $a = "Test data $i"; $b = "$i test data"; $array = array($a, $b, $i); $ret = odbc_execute($sth, &$array); if (!$ret) { echo "<p>failed to insert data!"; exit; } } //======================================= echo "<p>reading data from table '$testtablename'"; $sql = "select * from $testtablename;"; $sth = odbc_exec($conn, $sql); if (!$sth) { echo "<p>failed to execute sql!"; exit; } echo odbc_result_all($sth); //======================================= echo "<p>dropping table '$testtablename'"; $sql = "drop table $testtablename;"; $ret = odbc_exec($conn, $sql); if (!$ret) { echo "<p>failed to drop test table!"; exit; }
« previous php.dev (#28239) next »