From Kmillard@pumatech.com Fri May 4 19:01:44 2001 Received: from postgresql.org.org (webmail.postgresql.org [216.126.85.28]) by postgresql.org (8.11.3/8.11.1) with SMTP id f44J1iA00672 for ; Fri, 4 May 2001 15:01:44 -0400 (EDT) (envelope-from pgsql-interfaces-owner@postgresql.org) Received: from smtp01.pumatech.com (smtp01.pumatech.com [207.88.93.2]) by postgresql.org (8.11.3/8.11.1) with ESMTP id f423UBd61411 for ; Tue, 1 May 2001 23:30:12 -0400 (EDT) (envelope-from Kmillard@pumatech.com) Received: by smtp01.pumatech.com with Internet Mail Service (5.5.2653.19) id ; Tue, 1 May 2001 06:38:31 -0700 Message-ID: From: Keith Millard To: "'pgsql-interfaces@postgresql.org'" Subject: Postgres odbc driver bug Date: Tue, 1 May 2001 06:36:36 -0700 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2653.19) Content-Type: multipart/mixed; boundary="----_=_NextPart_000_01C0D243.BE782300" X-Archive-Number: 200105/21 X-Sequence-Number: 1547 This message is in MIME format. Since your mail reader does not understand this format, some or all of this message may not be legible. ------_=_NextPart_000_01C0D243.BE782300 Content-Type: multipart/alternative; boundary="----_=_NextPart_001_01C0D243.BE782300" ------_=_NextPart_001_01C0D243.BE782300 Content-Type: text/plain; charset="iso-8859-1" We have found a reproducible problem with the Postgres ODBC driver. It has to do with the parameter replacement feature in the driver. Below is a piece of test code that shows the problem. We were able to fix the problem by making a change to execute.c in the ODBC driver code (attached). odbc driver version : Found in both 6.50 and 7.01.0004. postgresql database version : Found with both 7.0.2 and 7.0.3 versions of Postgres. Server Operating System: Windows2000 Client Operation System: Windows2000 Explanation of the odbc driver bug: /***************************************** * ERROR HAPPENS HERE: * If we set the buffer that we binded to column "text1" now, it will FAIL. * The SQLExecute in doQuery() will succeed (finding 0 rows), and the * SQLFetchScroll call will return SQL_NO_DATA_FOUND. * * This is because of a bug in the odbc driver. The call to SQLNumResultCols * will execute the query in the driver, but the buffer that is binded is * empty, so no rows will be found. This of course assumes that the table * doesn't contain any empty records for the "text1" column, which is correct * for our test. Then when we call SQLExcute, the driver will realize it has * already done the query work and will not do it again, even though our * buffer for parameter substitution has changed (next line of code below * this comment). *****************************************/ Zip file is attached. The code is currently set up to fail, but I describe in my comments that you can uncomment the code that sets the buffer before SQLNumResultCols to make things will work. Thanks for your attention, Keith Millard _____ Alex Shore.. Senior Software Engineer.. Pumatech.. tel 603-888-0666 x1017.. .. ashore@pumatech.com.. www.pumatech.com.. ------_=_NextPart_001_01C0D243.BE782300 Content-Type: text/html; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable

We h= ave found a reproducible problem with the Postgres ODBC driver.  It has to do with the parameter replacement feature in the driver.  Below is a piece of test code that shows the problem.  We were able to fix the problem by making a change to execute.c in the ODBC driver code (attached).=

 

odbc driver version : Found in both 6.50 and 7.01.0004.=

post= gresql database version : Found with both 7.0.2 and 7.0.3 versions of Postgres.

Serv= er Operating System: Windows2000

Clie= nt Operation System: Windows2000

 

Explanation of the odbc driver bug:

=  

=  

   /***********************= ******************
    * ERROR HAPPENS HERE:
    * If we set the buffer that we binded to column "text1" now, it will FAIL.
    * The SQLExecute in doQuery() will succeed (finding 0 ro= ws), and the
    * SQLFetchScroll call will return SQL_NO_DATA_FOUND.
    *
    * This is because of a bug in the odbc driver. The call = to SQLNumResultCols
    * will execute the query in the driver, but the buffer t= hat is binded is
    * empty, so no rows will be found.  This of course assumes that the table
    * doesn't contain any empty records for the "text1" column, which is correct
    * for our test.  Then when we call SQLExcute, the driver will realize it has
    * already done the query work and will not do it again, = even though our
    * buffer for parameter substitution has changed (next li= ne of code below
    * this comment).
    *****************************************/
=

=  

=  Zip file is attached.  The code is currently set up to fai= l, but I describe in my comments that you can uncomment the code that sets the buffer before SQLNumResultCols to make things will work.=

 

Than= ks for your attention,

Keith Millard

=  

=  


3D"Keith

3D"Alex
------_=_NextPart_001_01C0D243.BE782300-- ------_=_NextPart_000_01C0D243.BE782300 Content-Type: application/octet-stream; name="pgodbc_test.zip" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="pgodbc_test.zip" UEsDBBQAAAAIAAlcmioKD05ezQkAABgiAAAUAAAAVGVzdFBvc3RHcmVzT0RC Qy5jcHC9GWtz4kbyc7Zq/0PHqfjA0Rp7L7cfNnGuMOA1dRgIknfvzrWlEtKA VREjopHs9T7++3X3zEgCP2AvIaoyhlZPT78fM60WeELl41TlbzKhRt3TzmG4 XMJr6IpZLIWC/FqAkHl2B8s0ljnM0oxhYSpVmggIlsskDoM8TuXh82etFv0B f/QhWEChYjmHAG4EUlDxYolL8mCKn5pQjDsgA4cA5yJDavhH1CORB3GiXjOh boArAiVABgsBJ7AXJOLDHr+6VCIrIQ4sA6Vu0ywCJDtNAvkbI3m8n12M5CMk qNeTwNB1h/SijTRIGfrNS5QwKRZSQSyZJc31CyQgPuTHexDISH9/iRtP0/ya mX/bnnTO2xMHEiGR6KsfjT6eP/sulmFSRAJ+vo1llN6qw+tf6lCVR3F6D5ah +taAYX63FPcXJ/F0Hfh7ch+CDDOQ+HrxAt4k6TRIFCJFbHAYe/7p5Zk/6A3h +OhoBT68vPA7o4ELL1fAKO6w57q+1/cGPdgjX5qjL0EaTUM27p7erbak23M7 k/5pzz/tD7tEEwBarUQEN0L7RFrkDkSp/FsOUgi0Zw55CkoItKwqBBE87w3f wty/FvIGFX30E0LImAihfTXE/XVw3h52ka25r/JFjuDh5WCAb8LrIDtA6FJ9 JPeqXpC6Zsjpg2w+f4aMIlEysVl9WsxmVzXlvP/JIvWHXu9Nb4JokpAGQq7j fSdkFM9oT2ONUZFBkccJzAoZUkihYSjoonSQzmPZaP5U+406qgF+LTDCar87 7L19OUsZyFscvPgzH5TzAIYYVa9BP4sglgwcF9kyVRreW88d6BCAysfcogjZ /sFE5EUmFS86IshmDrZ/DlpaL8Rig74E2Tx0QHsBfr+5et98/uwTbvsNvc1C bcVpmiYwdYswRG7RR/KsEKxM9ldgo/CPjDyubiWExTNoIPzbE3IG373sdDBK YH8fkVdh/ru+d+73h2ejJi/8xJ/4XOCuwVycph8a5J0O7JktYIbZUUSYeNbj z4GLU3/0L8MCccZq5WjAX18q5j00SwC/k9vURaj8aGci8BZfIULNADPMVaJ8 gVIgIMGUkaXF/JpSRMJxsS7roIJWlrLxs0tT4R5/2FbxrGE10Hx8O4Px9Dbf aBVU2/AeKxlGRwFHBhZvkVHZvHr5j1c6rzGYq2y0BsylqqMSnOiqPMgLZWMG 61m4vGtYuo4p3EYD5q2h5NQq8iqC3h/f7zXtTrOGrgQnJ0efP+sSgF+bn8wy 4uEEzdhOkjQ8x8qdiAZZVRcHHyuJQz9JlQbm7GuCpYM0NJVvT2resL//AHDd RSqFr+vCcuWKvCdv2nmeGSmYmbbnTXzqT/y3vYnbHw2dxk0aRwdNejl6y6/+ rtn23L+CzUeUh2w4hu19rfmdMFPGQ8VQJ5VShDqsoaH3dsAQaBRSxXOJvQMn +ab1KqMw5xG00jU34BkfLNUPVbDu1FGMzOQsq3IbEqXntC+9UWd0cdH3ShHw 3XhEXcmEfajC8EdnZ3UCu5bIAGsr76UiTs4mFz2YSKxOurEKtU4a1vtgt5YA rghnmRAPBwOsRMHmNZR9oMo2mxtQbKO4h4m5y8V/P9e7cwT88MNadeL8aJvV +D0VOsp1pbT4RCIRuYCr91DHLCtR1apuYT/TQ9TNZzuqFVPCSp8s3Twb8NRk fLDEuLQoYZbeOtivZcGdtUm9hZfilsPzqhpijAQLsVAib5TIDhw5tVHH1pHN 2c71LjxrYQf29Vixu+zr2lljcTc2GqNvRlbzFq5wUnu/UiIbXJMPmoxN3UFv 0Ot42GXPsnQBZgSGd+e9SQ94nkWK/7Rltm4TbRCkivMsUsWJJAdDm0ivKU7b bpyJJc7CDa0cx/BApHZUGXTA8wR1irM1To8ZzHmw1bxO0ZlFRu2hHd71bH+P c1o9DjLM/7nILP+1IKk9x4/Aifdxe9K+QKbHl94TWB2fTwoeR7BnCQ9jvPrx kRfo2a0W1qo0o3OUMF6gGqJ4HufqYfx6XajC6RHijco5mrUA2oyNvrhvInxH 4VI5QTc1R1RkZEw5s1TPObGc6/ylZ4C1ERl2NQdU+3z9LGDz5pdSQs5+5nwD f1JKrH6t9Aoueq/pKtmRXdsbTEbv/PZk0v6P7/b/i60uk9xpK/k1rLn+Wc/r nPe6/tibOPuc80vedlPb7yWC3gcRFrlNYX9Fd30m8vDaRWGTpEycRJB14Q97 /8ayc7zOyAnv2ZtMRpPPn+ug/vBte9Dvmqr1lFnWaA1Hfrfttf2z0eWwu0lj Hlcf9ZFmNG4YypEQ1DLDUo+0y5cYCpP0VsGMBMU++uTkl+8pEqiVabIbG+nu hVCdxhNxY5iqGpmqZq41N5TfaoVjc4tmq/5GZ/hjfW89IT3Y+wIXBveiPaC0 ChIX1FLfwbaPZvIA+jO4FYCNEadLWyWvg5zAU6yFaCYsmiaP2topqQeLESdO ErhNs98sOToR13k3y7AfB1kspkgwnUFGhmf8qeBUHNOZruRCXUUbhHSYY07U kF7ZSB4ayLZPS+ujZZqhWte3R8ePfPz/YOcyLBYToYoEx6xElWG4T3reXQ74 ertxwMN5ezzuDV2gJu71n2jSs3Z/YDUOHlKpWQhtVlpFYys6d0KijRkSp7ue I7Z20yndwZJaTXLa2EyiFhYr6ccyUfESK77ZEWGAczo5VoAizu0NDV84RFl8 I7JDZpy3QGnXLWsJ8u7CiEYUuEuw5DQlB3e4r0ziQisTv1lyYrHM7zBdpajP VZefpYWMDkFLgGyH6PgoQKBUseA7tiCv7pgq9xeKLkCw6c4D5CmQd3oLVBiG WKTKu7jVrtaB2+s4vCbOTCRaioRPIWdu3FBFEnHpw+iKLU3acGoasEYKkvij IC+5DkoNBgnCozu6qqlrkLIC25+XypSSG60M5iiIA+JGkIr5zJb4sdSMhonN pe3C0cGmKo/zgq5DaGtq6eWcPE6i1JDQlRKrNEITiQS7IUuOb5LCdLEQWGH+ vxyyKYMAlZAtLoyqlE0XJtgD4zxE9Ly7pXggr3e5XUecYZEk5BMljp4GkRv0 46G+0XxkEnRrc3OB2C5az6ac+gnCMZ8gnOhi8sDZgeW4ajIJaJlfgdpt1lBZ mFWYlWsFWs/EXaHCLJ4KpPj0HMYzhtVcE+Kn0FhFOIhU6tuOKCp1G0Qecax9 t8W3inxqQWlHWmGVvP0O2pm2FsCYpiyQAPUrzPjF8fv1IxqA+qGRRqh55cpx TKuFaULpm37dlnEnEJXHeA95A83l5AnwtCvoZ0uH0I+7aRA3z/0huRR288Lt B+b7i8gma+o3iecLf/LAS10rFEsGVL1u5eZsSn2EBwBlx/h4P/o/UEsDBBQA AAAIAA1cmioSaPj8GQQAADURAAAUAAAAVGVzdFBvc3RHcmVzT0RCQy5kc3Dt V21v4jgQ/l6p/2Euex/a1R6wZVXtleMkSAJCW15E6O11dRJynAG8DXFkOy39 9ztJCA2lpb1277QfViJi7Bk/fmbsPI7fQF9wJbWcGXDwGkMZowLPJIGQMFLy K3IDHREi/AYDtsSmNUFtRlKbrkI9dNq2RZ4R41dsjjC8iVA1//jw5+HBm33A XaQ4ZjCAdiLCIJvgHXSkWjIDf6HSQkZwWqnVUpy3b8EZwmA4AdfpTah5eJB2 T1rj7uRy5IL1WUT1EzhafTw9BltGWhLbVhyHgjNDQBbUVrX3tXo6zO50m/cT IP45goN+Mj88+KXvel6r68JkITTQL5IGGFyzUASwZFc4I7YVmEjwM/ImDYvX pUq0iOYw6Lc+ue9KUIlGikNwV7FUBvprFOByuWRRAOmjkqg0omRmaFCdwU7t K0THqjw86lImwFkEOkYuZreUAZfRTMwTlVUFbhYYpXNGG8Klwf4tBMQw86W8 l4zWEqh6QCPTjoJ4KCKqBa0c4Iot4xDPXpRDCr27tbZXxnoYmQZo4ae1XEjB UcOMyGynytRjtB6fcowhMo0WHPn0F6R5P7nRjp+FnCfzUtx887dxLqLi/Uw7 RuPhCFphKG9GqOwsewdjjAKMuKCi1DZBHufTdGD6NoNlbfWfS87CETOLzGGP Rk0eVnCFhwdjz24qntvEptcBsH49olU7tqDZfEYdc97ZTO2W58KFxmm/Y5eI bbqzAk3Pha+Y2uaehQwTEydm6ggF1h16OaIXGVRLDARJzL64CVNzXCPduXaZ 7Se1l88zqOywaDlOzo8WAKqRDOVcQvVzHardv6E6PIGqQ3umN6ifWJk5cNz2 RTe3p/Zw4A3P3XWr37Y9Mi8TS5uAzVaVBbU6DlR5MdF3m2OD6l20J+OWPcmh LwnukqcUtlKj/QTVkJT5Q+13qAabCYqgx/1tz66fNH3NUynON2QJN/MWCW08 253nvcEngiDputoZn/vgClWEYf2kEgo/FW+1NueBWFs3ItKxlGHWIDUMwvna w4JrFhdheoFhgUOv9Z3FElPAJyLIewOfFwFk8njd+LHYbDaLTnx9qw0uz/ha s6p0TCzoQDjr1T+eFmX9WdHvV1FSXvfcc5+vvsXB+WLtff+49hbY+5X3oajX 6O4doT1cnqTxbzR3mWvilx7pYnBfF6cv0N7uF9grwP/xhA/r7/QJ/Z3+1N8f Xy2CdJdviwZU48A3tzGeaYzNT1H+n8qcKvXAIaEuf6/nqpP35J/fz/hsfjL0 TtryWbpKJjFYnkwUx+xqrcsngIMzloRmSg4SSbB4HDd4g69WDcUbdOlrqIYM woagZxF/bfjMlLBLoCmkN7wY226z8s/OpY5QX3FReMUp9/jX570lcen2upVO 3pVVr2gUC5a3Ntetb1BLAQIyCxQAAAAIAAlcmioKD05ezQkAABgiAAAUAAAA AAAAAAEAIAC2gQAAAABUZXN0UG9zdEdyZXNPREJDLmNwcFBLAQIyCxQAAAAI AA1cmioSaPj8GQQAADURAAAUAAAAAAAAAAEAIAC2gf8JAABUZXN0UG9zdEdy ZXNPREJDLmRzcFBLBQYAAAAAAgACAIQAAABKDgAAAAA= ------_=_NextPart_000_01C0D243.BE782300 Content-Type: application/octet-stream; name="execute.c" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="execute.c" /* Module: execute.c * * Description: This module contains routines related to=20 * preparing and executing an SQL statement. * * Classes: n/a * * API functions: SQLPrepare, SQLExecute, SQLExecDirect, SQLTransact, * SQLCancel, SQLNativeSql, SQLParamData, SQLPutData * * Comments: See "notice.txt" for copyright and license information. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "psqlodbc.h" #include #include #ifndef WIN32 #include "iodbc.h" #include "isqlext.h" #else #include #include #endif #include "connection.h" #include "statement.h" #include "qresult.h" #include "convert.h" #include "bind.h" #include "lobj.h" extern GLOBAL_VALUES globals; // Perform a Prepare on the SQL statement RETCODE SQL_API SQLPrepare(HSTMT hstmt, UCHAR FAR *szSqlStr, SDWORD cbSqlStr) { static char *func =3D "SQLPrepare"; StatementClass *self =3D (StatementClass *) hstmt; mylog( "%s: entering...\n", func); if ( ! self) { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } =20=20=20=20 /* According to the ODBC specs it is valid to call SQLPrepare mulitple tim= es. In that case, the bound SQL statement is replaced by the new one=20 */ switch(self->status) { case STMT_PREMATURE: mylog("**** SQLPrepare: STMT_PREMATURE, recycle\n"); SC_recycle_statement(self); /* recycle the statement, but do not remove p= arameter bindings */ break; case STMT_FINISHED: mylog("**** SQLPrepare: STMT_FINISHED, recycle\n"); SC_recycle_statement(self); /* recycle the statement, but do not remove p= arameter bindings */ break; case STMT_ALLOCATED: mylog("**** SQLPrepare: STMT_ALLOCATED, copy\n"); self->status =3D STMT_READY; break; case STMT_READY: mylog("**** SQLPrepare: STMT_READY, change SQL\n"); break; case STMT_EXECUTING: mylog("**** SQLPrepare: STMT_EXECUTING, error!\n"); self->errornumber =3D STMT_SEQUENCE_ERROR; self->errormsg =3D "SQLPrepare(): The handle does not point to a statemen= t that is ready to be executed"; SC_log_error(func, "", self); return SQL_ERROR; default: self->errornumber =3D STMT_INTERNAL_ERROR; self->errormsg =3D "An Internal Error has occured -- Unknown statement st= atus."; SC_log_error(func, "", self); return SQL_ERROR; } if (self->statement) free(self->statement); self->statement =3D make_string(szSqlStr, cbSqlStr, NULL); if ( ! self->statement) { self->errornumber =3D STMT_NO_MEMORY_ERROR; self->errormsg =3D "No memory available to store statement"; SC_log_error(func, "", self); return SQL_ERROR; } self->prepare =3D TRUE; self->statement_type =3D statement_type(self->statement); // Check if connection is onlyread (only selects are allowed) if ( CC_is_onlyread(self->hdbc) && STMT_UPDATE(self)) { self->errornumber =3D STMT_EXEC_ERROR; self->errormsg =3D "Connection is readonly, only select statements are al= lowed."; SC_log_error(func, "", self); return SQL_ERROR; } return SQL_SUCCESS; } // - - - - - - - - - // Performs the equivalent of SQLPrepare, followed by SQLExecute. RETCODE SQL_API SQLExecDirect( HSTMT hstmt, UCHAR FAR *szSqlStr, SDWORD cbSqlStr) { StatementClass *stmt =3D (StatementClass *) hstmt; RETCODE result; static char *func =3D "SQLExecDirect"; mylog( "%s: entering...\n", func); =20=20=20=20 if ( ! stmt) { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } if (stmt->statement) free(stmt->statement); // keep a copy of the un-parametrized statement, in case // they try to execute this statement again stmt->statement =3D make_string(szSqlStr, cbSqlStr, NULL); if ( ! stmt->statement) { stmt->errornumber =3D STMT_NO_MEMORY_ERROR; stmt->errormsg =3D "No memory available to store statement"; SC_log_error(func, "", stmt); return SQL_ERROR; } mylog("**** %s: hstmt=3D%u, statement=3D'%s'\n", func, hstmt, stmt->statem= ent); stmt->prepare =3D FALSE; // If an SQLPrepare was performed prior to this, but was left in=20 // the premature state because an error occurred prior to SQLExecute // then set the statement to finished so it can be recycled. if ( stmt->status =3D=3D STMT_PREMATURE ) stmt->status =3D STMT_FINISHED; stmt->statement_type =3D statement_type(stmt->statement); // Check if connection is onlyread (only selects are allowed) if ( CC_is_onlyread(stmt->hdbc) && STMT_UPDATE(stmt)) { stmt->errornumber =3D STMT_EXEC_ERROR; stmt->errormsg =3D "Connection is readonly, only select statements are al= lowed."; SC_log_error(func, "", stmt); return SQL_ERROR; } =09 mylog("%s: calling SQLExecute...\n", func); result =3D SQLExecute(hstmt); mylog("%s: returned %hd from SQLExecute\n", func, result); return result; } // Execute a prepared SQL statement RETCODE SQL_API SQLExecute( HSTMT hstmt) { static char *func=3D"SQLExecute"; StatementClass *stmt =3D (StatementClass *) hstmt; ConnectionClass *conn; int i, retval; mylog("%s: entering...\n", func); if ( ! stmt) { SC_log_error(func, "", NULL); mylog("%s: NULL statement so return SQL_INVALID_HANDLE\n", func); return SQL_INVALID_HANDLE; } /* If the statement is premature, it means we already executed it from an SQLPrepare/SQLDescribeCol type of scenario. So just return success. */ #if 0 //chuck if ( stmt->prepare && stmt->status =3D=3D STMT_PREMATURE) { stmt->status =3D STMT_FINISHED;=20=20=20=20=20=20=20 if (stmt->errormsg =3D=3D NULL) { mylog("%s: premature statement but return SQL_SUCCESS\n", func); return SQL_SUCCESS; } else { SC_log_error(func, "", stmt); mylog("%s: premature statement so return SQL_ERROR\n", func); return SQL_ERROR; } }=20=20 #endif mylog("%s: clear errors...\n", func); SC_clear_error(stmt); conn =3D SC_get_conn(stmt); if (conn->status =3D=3D CONN_EXECUTING) { stmt->errormsg =3D "Connection is already in use."; stmt->errornumber =3D STMT_SEQUENCE_ERROR; SC_log_error(func, "", stmt); mylog("%s: problem with connection\n", func); return SQL_ERROR; } if ( ! stmt->statement) { stmt->errornumber =3D STMT_NO_STMTSTRING; stmt->errormsg =3D "This handle does not have a SQL statement stored in i= t"; SC_log_error(func, "", stmt); mylog("%s: problem with handle\n", func); return SQL_ERROR; } /* If SQLExecute is being called again, recycle the statement. Note this should have been done by the application in a call to SQLFreeStmt(SQL_CLOSE) or SQLCancel. */ if (stmt->status =3D=3D STMT_FINISHED) { mylog("%s: recycling statement (should have been done by app)...\n", func= ); SC_recycle_statement(stmt); } /* Check if the statement is in the correct state */ //chuck if ((stmt->prepare && stmt->status !=3D STMT_READY) || //chuck (stmt->status !=3D STMT_ALLOCATED && stmt->status !=3D STMT_REA= DY)) { if ((stmt->prepare && (stmt->status !=3D STMT_READY && stmt->status !=3D= STMT_PREMATURE)) || //chuck (stmt->status !=3D STMT_ALLOCATED && stmt->status !=3D STMT_READY && = stmt->status !=3D STMT_PREMATURE)) { //chuck =09=09 stmt->errornumber =3D STMT_STATUS_ERROR; stmt->errormsg =3D "The handle does not point to a statement that is read= y to be executed"; SC_log_error(func, "", stmt); mylog("%s: problem with statement\n", func); return SQL_ERROR; } /* The bound parameters could have possibly changed since the last execute of this statement? Therefore check for params and re-copy. */ mylog("%s: Check for data at execution parameters\n", func); mylog("%s: stmt->parameters_allocated =3D %d\n", func,stmt->parameters_all= ocated); stmt->data_at_exec =3D -1; for (i =3D 0; i < stmt->parameters_allocated; i++) { /* Check for data at execution parameters */ mylog("%s: stmt->parameters[%d].data_at_exec =3D %d\n", func,i,stmt->par= ameters[i].data_at_exec); if ( stmt->parameters[i].data_at_exec =3D=3D TRUE) { if (stmt->data_at_exec < 0) stmt->data_at_exec =3D 1; else stmt->data_at_exec++; } } // If there are some data at execution parameters, return need data // SQLParamData and SQLPutData will be used to send params and execute the= statement. if (stmt->data_at_exec > 0) return SQL_NEED_DATA; mylog("%s: copying statement params: trans_status=3D%d, len=3D%d, stmt=3D'= %s'\n", func, conn->transact_status, strlen(stmt->statement), stmt->stateme= nt); // Create the statement with parameters substituted. retval =3D copy_statement_with_parameters(stmt); if( retval !=3D SQL_SUCCESS) /* error msg passed from above */ return retval; mylog(" stmt_with_params =3D '%s'\n", stmt->stmt_with_params); return SC_execute(stmt); } // - - - - - - - - - RETCODE SQL_API SQLTransact( HENV henv, HDBC hdbc, UWORD fType) { static char *func =3D "SQLTransact"; extern ConnectionClass *conns[]; ConnectionClass *conn; QResultClass *res; char ok, *stmt_string; int lf; mylog("entering %s: hdbc=3D%u, henv=3D%u\n", func, hdbc, henv); if (hdbc =3D=3D SQL_NULL_HDBC && henv =3D=3D SQL_NULL_HENV) { CC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } /* If hdbc is null and henv is valid, it means transact all connections on that henv.=20=20 */ if (hdbc =3D=3D SQL_NULL_HDBC && henv !=3D SQL_NULL_HENV) { for (lf=3D0; lf henv =3D=3D henv) if ( SQLTransact(henv, (HDBC) conn, fType) !=3D SQL_SUCCESS) return SQL_ERROR; } return SQL_SUCCESS;=20=20=20=20=20=20=20 } conn =3D (ConnectionClass *) hdbc; if (fType =3D=3D SQL_COMMIT) { stmt_string =3D "COMMIT"; } else if (fType =3D=3D SQL_ROLLBACK) { stmt_string =3D "ROLLBACK"; } else { conn->errornumber =3D CONN_INVALID_ARGUMENT_NO; conn->errormsg =3D"SQLTransact can only be called with SQL_COMMIT or SQL_= ROLLBACK as parameter"; CC_log_error(func, "", conn); return SQL_ERROR; }=20=20=20=20 /* If manual commit and in transaction, then proceed. */ if ( ! CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) { mylog("SQLTransact: sending on conn %d '%s'\n", conn, stmt_string); res =3D CC_send_query(conn, stmt_string, NULL); CC_set_no_trans(conn); if ( ! res) { // error msg will be in the connection CC_log_error(func, "", conn); return SQL_ERROR; } ok =3D QR_command_successful(res);=20=20=20 QR_Destructor(res); if (!ok) { CC_log_error(func, "", conn); return SQL_ERROR; } }=20=20=20=20 return SQL_SUCCESS; } // - - - - - - - - - RETCODE SQL_API SQLCancel( HSTMT hstmt) // Statement to cancel. { static char *func=3D"SQLCancel"; StatementClass *stmt =3D (StatementClass *) hstmt; RETCODE result; #ifdef WIN32 HMODULE hmodule; FARPROC addr; #endif mylog( "%s: entering...\n", func); // Check if this can handle canceling in the middle of a SQLPutData? if ( ! stmt) { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } // Not in the middle of SQLParamData/SQLPutData so cancel like a close. if (stmt->data_at_exec < 0) { /* MAJOR HACK for Windows to reset the driver manager's cursor state: Because of what seems like a bug in the Odbc driver manager, SQLCancel does not act like a SQLFreeStmt(CLOSE), as many applications depend on this behavior. So, this=20 brute force method calls the driver manager's function on behalf of the application.=20=20 */ #ifdef WIN32 if (globals.cancel_as_freestmt) { hmodule =3D GetModuleHandle("ODBC32"); addr =3D GetProcAddress(hmodule, "SQLFreeStmt"); result =3D addr( (char *) (stmt->phstmt) - 96, SQL_CLOSE); } else { result =3D SQLFreeStmt( hstmt, SQL_CLOSE); } #else result =3D SQLFreeStmt( hstmt, SQL_CLOSE); #endif mylog("SQLCancel: SQLFreeStmt returned %d\n", result); SC_clear_error(hstmt); return SQL_SUCCESS; } // In the middle of SQLParamData/SQLPutData, so cancel that. // Note, any previous data-at-exec buffers will be freed in the recycle // if they call SQLExecDirect or SQLExecute again. stmt->data_at_exec =3D -1; stmt->current_exec_param =3D -1; stmt->put_data =3D FALSE; return SQL_SUCCESS; } // - - - - - - - - - // Returns the SQL string as modified by the driver. // Currently, just copy the input string without modification // observing buffer limits and truncation. RETCODE SQL_API SQLNativeSql( HDBC hdbc, UCHAR FAR *szSqlStrIn, SDWORD cbSqlStrIn, UCHAR FAR *szSqlStr, SDWORD cbSqlStrMax, SDWORD FAR *pcbSqlStr) { static char *func=3D"SQLNativeSql"; int len =3D 0; char *ptr; ConnectionClass *conn =3D (ConnectionClass *) hdbc; RETCODE result; mylog( "%s: entering...cbSqlStrIn=3D%d\n", func, cbSqlStrIn); ptr =3D (cbSqlStrIn =3D=3D 0) ? "" : make_string(szSqlStrIn, cbSqlStrIn, N= ULL); if ( ! ptr) { conn->errornumber =3D CONN_NO_MEMORY_ERROR; conn->errormsg =3D "No memory available to store native sql string"; CC_log_error(func, "", conn); return SQL_ERROR; } result =3D SQL_SUCCESS; len =3D strlen(ptr); if (szSqlStr) { strncpy_null(szSqlStr, ptr, cbSqlStrMax); if (len >=3D cbSqlStrMax) { result =3D SQL_SUCCESS_WITH_INFO; conn->errornumber =3D STMT_TRUNCATED; conn->errormsg =3D "The buffer was too small for the result."; } } if (pcbSqlStr) *pcbSqlStr =3D len; free(ptr); return result; } // - - - - - - - - - // Supplies parameter data at execution time. Used in conjuction = with // SQLPutData. RETCODE SQL_API SQLParamData( HSTMT hstmt, PTR FAR *prgbValue) { static char *func =3D "SQLParamData"; StatementClass *stmt =3D (StatementClass *) hstmt; int i, retval; mylog( "%s: entering...\n", func); if ( ! stmt) { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } mylog("%s: data_at_exec=3D%d, params_alloc=3D%d\n", func, stmt->data_at_ex= ec, stmt->parameters_allocated); if (stmt->data_at_exec < 0) { stmt->errornumber =3D STMT_SEQUENCE_ERROR; stmt->errormsg =3D "No execution-time parameters for this statement"; SC_log_error(func, "", stmt); return SQL_ERROR; } if (stmt->data_at_exec > stmt->parameters_allocated) { stmt->errornumber =3D STMT_SEQUENCE_ERROR; stmt->errormsg =3D "Too many execution-time parameters were present"; SC_log_error(func, "", stmt); return SQL_ERROR; } /* close the large object */ if ( stmt->lobj_fd >=3D 0) { lo_close(stmt->hdbc, stmt->lobj_fd); /* commit transaction if needed */ if (!globals.use_declarefetch && CC_is_in_autocommit(stmt->hdbc)) { QResultClass *res; char ok; res =3D CC_send_query(stmt->hdbc, "COMMIT", NULL); if (!res) { stmt->errormsg =3D "Could not commit (in-line) a transaction"; stmt->errornumber =3D STMT_EXEC_ERROR; SC_log_error(func, "", stmt); return SQL_ERROR; } ok =3D QR_command_successful(res); QR_Destructor(res); if (!ok) { stmt->errormsg =3D "Could not commit (in-line) a transaction"; stmt->errornumber =3D STMT_EXEC_ERROR; SC_log_error(func, "", stmt); return SQL_ERROR; } CC_set_no_trans(stmt->hdbc); } stmt->lobj_fd =3D -1; } /* Done, now copy the params and then execute the statement */ if (stmt->data_at_exec =3D=3D 0) { retval =3D copy_statement_with_parameters(stmt); if (retval !=3D SQL_SUCCESS) return retval; stmt->current_exec_param =3D -1; return SC_execute(stmt); } /* Set beginning param; if first time SQLParamData is called , start at 0. Otherwise, start at the last parameter + 1. */ i =3D stmt->current_exec_param >=3D 0 ? stmt->current_exec_param+1 : 0; /* At least 1 data at execution parameter, so Fill in the token value */ for ( ; i < stmt->parameters_allocated; i++) { if (stmt->parameters[i].data_at_exec =3D=3D TRUE) { stmt->data_at_exec--; stmt->current_exec_param =3D i; stmt->put_data =3D FALSE; *prgbValue =3D stmt->parameters[i].buffer; /* token */ break; } } return SQL_NEED_DATA; } // - - - - - - - - - // Supplies parameter data at execution time. Used in conjunction= with // SQLParamData. RETCODE SQL_API SQLPutData( HSTMT hstmt, PTR rgbValue, SDWORD cbValue) { static char *func =3D "SQLPutData"; StatementClass *stmt =3D (StatementClass *) hstmt; int old_pos, retval; ParameterInfoClass *current_param; char *buffer; mylog( "%s: entering...\n", func); if ( ! stmt) { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } =09 if (stmt->current_exec_param < 0) { stmt->errornumber =3D STMT_SEQUENCE_ERROR; stmt->errormsg =3D "Previous call was not SQLPutData or SQLParamData"; SC_log_error(func, "", stmt); return SQL_ERROR; } current_param =3D &(stmt->parameters[stmt->current_exec_param]); if ( ! stmt->put_data) { /* first call */ mylog("SQLPutData: (1) cbValue =3D %d\n", cbValue); stmt->put_data =3D TRUE; current_param->EXEC_used =3D (SDWORD *) malloc(sizeof(SDWORD)); if ( ! current_param->EXEC_used) { stmt->errornumber =3D STMT_NO_MEMORY_ERROR; stmt->errormsg =3D "Out of memory in SQLPutData (1)"; SC_log_error(func, "", stmt); return SQL_ERROR; } *current_param->EXEC_used =3D cbValue; if (cbValue =3D=3D SQL_NULL_DATA) return SQL_SUCCESS; /* Handle Long Var Binary with Large Objects */ if ( current_param->SQLType =3D=3D SQL_LONGVARBINARY) { /* begin transaction if needed */ if(!CC_is_in_trans(stmt->hdbc)) { QResultClass *res; char ok; res =3D CC_send_query(stmt->hdbc, "BEGIN", NULL); if (!res) { stmt->errormsg =3D "Could not begin (in-line) a transaction"; stmt->errornumber =3D STMT_EXEC_ERROR; SC_log_error(func, "", stmt); return SQL_ERROR; } ok =3D QR_command_successful(res); QR_Destructor(res); if (!ok) { stmt->errormsg =3D "Could not begin (in-line) a transaction"; stmt->errornumber =3D STMT_EXEC_ERROR; SC_log_error(func, "", stmt); return SQL_ERROR; } CC_set_in_trans(stmt->hdbc); } /* store the oid */ current_param->lobj_oid =3D lo_creat(stmt->hdbc, INV_READ | INV_WRITE); if (current_param->lobj_oid =3D=3D 0) { stmt->errornumber =3D STMT_EXEC_ERROR; stmt->errormsg =3D "Couldnt create large object."; SC_log_error(func, "", stmt); return SQL_ERROR; } /* major hack -- to allow convert to see somethings there */ /* have to modify convert to handle this better */ current_param->EXEC_buffer =3D (char *) ¤t_param->lobj_oid; /* store the fd */ stmt->lobj_fd =3D lo_open(stmt->hdbc, current_param->lobj_oid, INV_WRITE= ); if ( stmt->lobj_fd < 0) { stmt->errornumber =3D STMT_EXEC_ERROR; stmt->errormsg =3D "Couldnt open large object for writing."; SC_log_error(func, "", stmt); return SQL_ERROR; } retval =3D lo_write(stmt->hdbc, stmt->lobj_fd, rgbValue, cbValue); mylog("lo_write: cbValue=3D%d, wrote %d bytes\n", cbValue, retval); } else { /* for handling text fields and small binaries */ if (cbValue =3D=3D SQL_NTS) { current_param->EXEC_buffer =3D strdup(rgbValue); if ( ! current_param->EXEC_buffer) { stmt->errornumber =3D STMT_NO_MEMORY_ERROR; stmt->errormsg =3D "Out of memory in SQLPutData (2)"; SC_log_error(func, "", stmt); return SQL_ERROR; } } else { current_param->EXEC_buffer =3D malloc(cbValue + 1); if ( ! current_param->EXEC_buffer) { stmt->errornumber =3D STMT_NO_MEMORY_ERROR; stmt->errormsg =3D "Out of memory in SQLPutData (2)"; SC_log_error(func, "", stmt); return SQL_ERROR; } memcpy(current_param->EXEC_buffer, rgbValue, cbValue); current_param->EXEC_buffer[cbValue] =3D '\0'; } } } else { /* calling SQLPutData more than once */ mylog("SQLPutData: (>1) cbValue =3D %d\n", cbValue); if (current_param->SQLType =3D=3D SQL_LONGVARBINARY) { /* the large object fd is in EXEC_buffer */ retval =3D lo_write(stmt->hdbc, stmt->lobj_fd, rgbValue, cbValue); mylog("lo_write(2): cbValue =3D %d, wrote %d bytes\n", cbValue, retval); *current_param->EXEC_used +=3D cbValue; } else { buffer =3D current_param->EXEC_buffer; if (cbValue =3D=3D SQL_NTS) { buffer =3D realloc(buffer, strlen(buffer) + strlen(rgbValue) + 1); if ( ! buffer) { stmt->errornumber =3D STMT_NO_MEMORY_ERROR; stmt->errormsg =3D "Out of memory in SQLPutData (3)"; SC_log_error(func, "", stmt); return SQL_ERROR; } strcat(buffer, rgbValue); mylog(" cbValue =3D SQL_NTS: strlen(buffer) =3D %d\n", strlen(buf= fer)); *current_param->EXEC_used =3D cbValue; /* reassign buffer incase realloc moved it */ current_param->EXEC_buffer =3D buffer; } else if (cbValue > 0) { old_pos =3D *current_param->EXEC_used; *current_param->EXEC_used +=3D cbValue; mylog(" cbValue =3D %d, old_pos =3D %d, *used =3D %d\n", cbValue= , old_pos, *current_param->EXEC_used); /* dont lose the old pointer in case out of memory */ buffer =3D realloc(current_param->EXEC_buffer, *current_param->EXEC_use= d + 1); if ( ! buffer) { stmt->errornumber =3D STMT_NO_MEMORY_ERROR; stmt->errormsg =3D "Out of memory in SQLPutData (3)"; SC_log_error(func, "", stmt); return SQL_ERROR; } memcpy(&buffer[old_pos], rgbValue, cbValue); buffer[*current_param->EXEC_used] =3D '\0'; /* reassign buffer incase realloc moved it */ current_param->EXEC_buffer =3D buffer; =09=09=09=09 } else { SC_log_error(func, "bad cbValue", stmt); return SQL_ERROR; } } } return SQL_SUCCESS; } ------_=_NextPart_000_01C0D243.BE782300-- From Inoue@tpf.co.jp Sat May 5 03:43:32 2001 Received: from p2272.nsk.ne.jp (p2272.nsk.ne.jp [210.145.18.145]) by postgresql.org (8.11.3/8.11.1) with ESMTP id f453hWA60997 for ; Fri, 4 May 2001 23:43:32 -0400 (EDT) (envelope-from Inoue@tpf.co.jp) Received: from mcadnote1 (ppm154.noc.fukui.nsk.ne.jp [210.161.188.73]) by p2272.nsk.ne.jp (8.9.3/3.7W-20000722) with SMTP id MAA21946; Sat, 5 May 2001 12:43:19 +0900 (JST) From: "Hiroshi Inoue" To: "Keith Millard" Cc: Subject: RE: Postgres odbc driver bug Date: Sat, 5 May 2001 12:43:41 +0900 Message-ID: MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="----=_NextPart_000_010B_01C0D561.03D3F3A0" X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook IMO, Build 9.0.2416 (9.0.2910.0) In-Reply-To: X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2919.6700 Importance: Normal X-Archive-Number: 200105/24 X-Sequence-Number: 1550 This is a multi-part message in MIME format. ------=_NextPart_000_010B_01C0D561.03D3F3A0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Please try the latest driver 7.01.0005. It solves several parameter handling problems. regards, Hiroshi Inoue -----Original Message----- From: pgsql-interfaces-owner@postgresql.org [mailto:pgsql-interfaces-owner@postgresql.org]On Behalf Of Keith Millard Sent: Tuesday, May 01, 2001 10:37 PM To: 'pgsql-interfaces@postgresql.org' Subject: [INTERFACES] Postgres odbc driver bug We have found a reproducible problem with the Postgres ODBC driver. It has to do with the parameter replacement feature in the driver. Below is a piece of test code that shows the problem. We were able to fix the problem by making a change to execute.c in the ODBC driver code (attached). odbc driver version : Found in both 6.50 and 7.01.0004. postgresql database version : Found with both 7.0.2 and 7.0.3 versions of Postgres. Server Operating System: Windows2000 Client Operation System: Windows2000 Explanation of the odbc driver bug: /***************************************** * ERROR HAPPENS HERE: * If we set the buffer that we binded to column "text1" now, it will FAIL. * The SQLExecute in doQuery() will succeed (finding 0 rows), and the * SQLFetchScroll call will return SQL_NO_DATA_FOUND. * * This is because of a bug in the odbc driver. The call to SQLNumResultCols * will execute the query in the driver, but the buffer that is binded is * empty, so no rows will be found. This of course assumes that the table * doesn't contain any empty records for the "text1" column, which is correct * for our test. Then when we call SQLExcute, the driver will realize it has * already done the query work and will not do it again, even though our * buffer for parameter substitution has changed (next line of code below * this comment). *****************************************/ Zip file is attached. The code is currently set up to fail, but I describe in my comments that you can uncomment the code that sets the buffer before SQLNumResultCols to make things will work. Thanks for your attention, Keith Millard ------=_NextPart_000_010B_01C0D561.03D3F3A0 Content-Type: text/html; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable
Please try the latest driver=20 7.01.0005.
It solves several parameter handling=20 problems.
 
regards,
Hiroshi Inoue 
-----Original Message-----
From:=20 pgsql-interfaces-owner@postgresql.org=20 [mailto:pgsql-interfaces-owner@postgresql.org]On Behalf Of Keith= =20 Millard
Sent: Tuesday, May 01, 2001 10:37 PM
To:=20 'pgsql-interfaces@postgresql.org'
Subject: [INTERFACES] Postgre= s=20 odbc driver bug

We=20 have found a reproducible problem with the Postgres ODBC driver.  It has to do with the parameter= =20 replacement feature in the driver. = ;=20 Below is a piece of test code that shows the problem.  We were able to fix the problem= by=20 making a change to execute.c in the ODBC driver code=20 (attached).

 =

odbc=20 driver version : Found in both 6.50 and=20 7.01.0004.

postgresql=20 database version : Found with both 7.0.2 and 7.0.3 versions of=20 Postgres.

Server=20 Operating System: Windows2000

Client=20 Operation System: Windows2000

 =

Explanation of= the=20 odbc driver bug:

 

 

  = =20 /*****************************************
    * ERROR= =20 HAPPENS HERE:
    * If we set the buffer that we binded= to=20 column "text1" now, it will FAIL.
    * The SQLExecute = in=20 doQuery() will succeed (finding 0 rows), and the
    *= =20 SQLFetchScroll call will return SQL_NO_DATA_FOUND.
   = =20 *
    * This is because of a bug in the odbc driver. Th= e=20 call to SQLNumResultCols
    * will execute the query i= n the=20 driver, but the buffer that is binded is
    * empty, = so no=20 rows will be found.  This of course assumes that the=20 table
    * doesn't contain any empty records for the= =20 "text1" column, which is correct
    * for our test.&nb= sp;=20 Then when we call SQLExcute, the driver will realize it=20 has
    * already done the query work and will not do i= t=20 again, even though our
    * buffer for parameter=20 substitution has changed (next line of code below
    = *=20 this comment).
   =20 *****************************************/

 

 Zip file is=20 attached.  The code is currently set up to fail, but I describe in m= y=20 comments that you can uncomment the code that sets the buffer before=20 SQLNumResultCols to make things will work.

 =

Thanks=20 for your attention,

Keith=20 Millard

------=_NextPart_000_010B_01C0D561.03D3F3A0-- From pgman@candle.pha.pa.us Tue May 8 16:55:55 2001 Received: from candle.pha.pa.us (candle.navpoint.com [162.33.245.46]) by postgresql.org (8.11.3/8.11.1) with ESMTP id f48GttA57771 for ; Tue, 8 May 2001 12:55:55 -0400 (EDT) (envelope-from pgman@candle.pha.pa.us) Received: (from pgman@localhost) by candle.pha.pa.us (8.10.1/8.10.1) id f48GtkL12980; Tue, 8 May 2001 12:55:46 -0400 (EDT) From: Bruce Momjian Message-Id: <200105081655.f48GtkL12980@candle.pha.pa.us> Subject: Re: [INTERFACES] Postgres odbc driver bug In-Reply-To: "from Keith Millard at May 1, 2001 06:36:36 am" To: Keith Millard Date: Tue, 8 May 2001 12:55:46 -0400 (EDT) CC: PostgreSQL odbc list X-Mailer: ELM [version 2.4ME+ PL90 (25)] MIME-Version: 1.0 Content-Type: multipart/mixed; boundary=ELM989340946-29922-1_ Content-Transfer-Encoding: 7bit X-Archive-Number: 200105/44 X-Sequence-Number: 433 --ELM989340946-29922-1_ Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII OK, I have created a context diff of your changes, which is attached. Can someone comment on this? The patch appears to deal with STMT_PREMATURE differently than our current code. In fact, it seems to disable this code: /* * If the statement is premature, it means we already executed it from * an SQLPrepare/SQLDescribeCol type of scenario. So just return * success. */ if (stmt->prepare && stmt->status == STMT_PREMATURE) > We have found a reproducible problem with the Postgres ODBC driver. It has > to do with the parameter replacement feature in the driver. Below is a > piece of test code that shows the problem. We were able to fix the problem > by making a change to execute.c in the ODBC driver code (attached). > > odbc driver version : Found in both 6.50 and 7.01.0004. > postgresql database version : Found with both 7.0.2 and 7.0.3 versions of > Postgres. > Server Operating System: Windows2000 > Client Operation System: Windows2000 > > Explanation of the odbc driver bug: > > > /***************************************** > * ERROR HAPPENS HERE: > * If we set the buffer that we binded to column "text1" now, it will > FAIL. > * The SQLExecute in doQuery() will succeed (finding 0 rows), and the > * SQLFetchScroll call will return SQL_NO_DATA_FOUND. > * > * This is because of a bug in the odbc driver. The call to > SQLNumResultCols > * will execute the query in the driver, but the buffer that is binded is > > * empty, so no rows will be found. This of course assumes that the > table > * doesn't contain any empty records for the "text1" column, which is > correct > * for our test. Then when we call SQLExcute, the driver will realize it > has > * already done the query work and will not do it again, even though our > * buffer for parameter substitution has changed (next line of code below > > * this comment). > *****************************************/ > > Zip file is attached. The code is currently set up to fail, but I describe > in my comments that you can uncomment the code that sets the buffer before > SQLNumResultCols to make things will work. > > Thanks for your attention, > Keith Millard > > > _____ > > Alex > Shore.. > Senior Software Engineer.. > Pumatech.. > tel 603-888-0666 x1017.. > .. > ashore@pumatech.com.. > www.pumatech.com.. > > [ Attachment, skipping... ] [ Attachment, skipping... ] > > ---------------------------(end of broadcast)--------------------------- > TIP 3: if posting/reading through Usenet, please send an appropriate > subscribe-nomail command to majordomo@postgresql.org so that your > message can get through to the mailing list cleanly -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026 --ELM989340946-29922-1_ Content-Transfer-Encoding: 7bit Content-Type: text/plain Content-Disposition: inline; filename="/bjm/diff" *** e2 Tue May 8 12:49:51 2001 --- execute.c Tue May 8 12:47:48 2001 *************** *** 204,209 **** --- 204,210 ---- it from an SQLPrepare/SQLDescribeCol type of scenario. So just return success. */ + #if 0 //chuck if ( stmt->prepare && stmt->status == STMT_PREMATURE) { stmt->status = STMT_FINISHED; if (stmt->errormsg == NULL) { *************** *** 216,221 **** --- 217,223 ---- return SQL_ERROR; } } + #endif mylog("%s: clear errors...\n", func); *************** *** 248,255 **** } /* Check if the statement is in the correct state */ ! if ((stmt->prepare && stmt->status != STMT_READY) || ! (stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY)) { stmt->errornumber = STMT_STATUS_ERROR; stmt->errormsg = "The handle does not point to a statement that is ready to be executed"; --- 250,259 ---- } /* Check if the statement is in the correct state */ ! //chuck if ((stmt->prepare && stmt->status != STMT_READY) || ! //chuck (stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY)) { ! if ((stmt->prepare && (stmt->status != STMT_READY && stmt->status != STMT_PREMATURE)) || //chuck ! (stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY && stmt->status != STMT_PREMATURE)) { //chuck stmt->errornumber = STMT_STATUS_ERROR; stmt->errormsg = "The handle does not point to a statement that is ready to be executed"; *************** *** 262,270 **** --- 266,277 ---- /* The bound parameters could have possibly changed since the last execute of this statement? Therefore check for params and re-copy. */ + mylog("%s: Check for data at execution parameters\n", func); + mylog("%s: stmt->parameters_allocated = %d\n", func,stmt->parameters_allocated); stmt->data_at_exec = -1; for (i = 0; i < stmt->parameters_allocated; i++) { /* Check for data at execution parameters */ + mylog("%s: stmt->parameters[%d].data_at_exec = %d\n", func,i,stmt->parameters[i].data_at_exec); if ( stmt->parameters[i].data_at_exec == TRUE) { if (stmt->data_at_exec < 0) stmt->data_at_exec = 1; --ELM989340946-29922-1_-- From pgman@candle.pha.pa.us Tue May 8 20:05:33 2001 Received: from candle.pha.pa.us (candle.navpoint.com [162.33.245.46]) by postgresql.org (8.11.3/8.11.1) with ESMTP id f48K5XA37426; Tue, 8 May 2001 16:05:33 -0400 (EDT) (envelope-from pgman@candle.pha.pa.us) Received: (from pgman@localhost) by candle.pha.pa.us (8.10.1/8.10.1) id f48K5Rt27279; Tue, 8 May 2001 16:05:27 -0400 (EDT) From: Bruce Momjian Message-Id: <200105082005.f48K5Rt27279@candle.pha.pa.us> Subject: Re: Postgres odbc driver bug In-Reply-To: "from Keith Millard at May 1, 2001 06:36:36 am" To: Keith Millard Date: Tue, 8 May 2001 16:05:27 -0400 (EDT) CC: "'pgsql-interfaces@postgresql.org'" , PostgreSQL odbc list X-Mailer: ELM [version 2.4ME+ PL90 (25)] MIME-Version: 1.0 Content-Type: multipart/mixed; boundary=ELM989352327-26780-0_ Content-Transfer-Encoding: 7bit X-Archive-Number: 200105/37 X-Sequence-Number: 1563 --ELM989352327-26780-0_ Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII OK, I have found another person who reported this problem. I have attached their patch. Can you compare yours to theirs and let me know what you think? Thanks. > We have found a reproducible problem with the Postgres ODBC driver. It has > to do with the parameter replacement feature in the driver. Below is a > piece of test code that shows the problem. We were able to fix the problem > by making a change to execute.c in the ODBC driver code (attached). > > odbc driver version : Found in both 6.50 and 7.01.0004. > postgresql database version : Found with both 7.0.2 and 7.0.3 versions of > Postgres. > Server Operating System: Windows2000 > Client Operation System: Windows2000 > > Explanation of the odbc driver bug: > > > /***************************************** > * ERROR HAPPENS HERE: > * If we set the buffer that we binded to column "text1" now, it will > FAIL. > * The SQLExecute in doQuery() will succeed (finding 0 rows), and the > * SQLFetchScroll call will return SQL_NO_DATA_FOUND. > * > * This is because of a bug in the odbc driver. The call to > SQLNumResultCols > * will execute the query in the driver, but the buffer that is binded is > > * empty, so no rows will be found. This of course assumes that the > table > * doesn't contain any empty records for the "text1" column, which is > correct > * for our test. Then when we call SQLExcute, the driver will realize it > has > * already done the query work and will not do it again, even though our > * buffer for parameter substitution has changed (next line of code below > > * this comment). > *****************************************/ > > Zip file is attached. The code is currently set up to fail, but I describe > in my comments that you can uncomment the code that sets the buffer before > SQLNumResultCols to make things will work. > > Thanks for your attention, > Keith Millard > > > _____ > > Alex > Shore.. > Senior Software Engineer.. > Pumatech.. > tel 603-888-0666 x1017.. > .. > ashore@pumatech.com.. > www.pumatech.com.. > > [ Attachment, skipping... ] [ Attachment, skipping... ] > > ---------------------------(end of broadcast)--------------------------- > TIP 3: if posting/reading through Usenet, please send an appropriate > subscribe-nomail command to majordomo@postgresql.org so that your > message can get through to the mailing list cleanly -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026 --ELM989352327-26780-0_ Content-Transfer-Encoding: 7bit Content-Type: text/plain Content-Disposition: inline; filename="/bjm/diff" Index: bind.c =================================================================== RCS file: /usr/local/src/cvsroot/psqlodbc/bind.c,v retrieving revision 1.1.1.3 retrieving revision 1.1.1.3.2.2 diff -c -r1.1.1.3 -r1.1.1.3.2.2 *** bind.c 2001/03/24 08:14:27 1.1.1.3 --- bind.c 2001/03/24 17:08:26 1.1.1.3.2.2 *************** *** 144,153 **** } /* Data at exec macro only valid for C char/binary data */ ! if ((fSqlType == SQL_LONGVARBINARY || fSqlType == SQL_LONGVARCHAR) && pcbValue && *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET) stmt->parameters[ipar].data_at_exec = TRUE; else stmt->parameters[ipar].data_at_exec = FALSE; mylog("SQLBindParamater: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue : -777, stmt->parameters[ipar].data_at_exec); --- 144,158 ---- } /* Data at exec macro only valid for C char/binary data */ ! if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC || *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET)) stmt->parameters[ipar].data_at_exec = TRUE; else stmt->parameters[ipar].data_at_exec = FALSE; + + /* Clear premature result */ + if (stmt->status == STMT_PREMATURE) + SC_recycle_statement(stmt); mylog("SQLBindParamater: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue : -777, stmt->parameters[ipar].data_at_exec); Index: convert.c =================================================================== RCS file: /usr/local/src/cvsroot/psqlodbc/convert.c,v retrieving revision 1.1.1.3 retrieving revision 1.1.1.3.2.1 diff -c -r1.1.1.3 -r1.1.1.3.2.1 *** convert.c 2001/03/24 08:14:31 1.1.1.3 --- convert.c 2001/03/24 15:35:10 1.1.1.3.2.1 *************** *** 838,844 **** param_number++; if (param_number >= stmt->parameters_allocated) ! break; /* Assign correct buffers based on data at exec param or not */ if (stmt->parameters[param_number].data_at_exec) --- 838,857 ---- param_number++; if (param_number >= stmt->parameters_allocated) ! { ! if (stmt->pre_executing) ! { ! strcpy(&new_statement[npos], "NULL"); ! npos += 4; ! stmt->inaccurate_result = TRUE; ! continue; ! } ! else ! { ! new_statement[npos++] = '?'; ! continue; ! } ! } /* Assign correct buffers based on data at exec param or not */ if (stmt->parameters[param_number].data_at_exec) *************** *** 866,873 **** */ if (!buffer) { ! new_statement[npos++] = '?'; ! continue; } param_ctype = stmt->parameters[param_number].CType; --- 879,896 ---- */ if (!buffer) { ! if (stmt->pre_executing) ! { ! strcpy(&new_statement[npos], "NULL"); ! npos += 4; ! stmt->inaccurate_result = TRUE; ! continue; ! } ! else ! { ! new_statement[npos++] = '?'; ! continue; ! } } param_ctype = stmt->parameters[param_number].CType; Index: execute.c =================================================================== RCS file: /usr/local/src/cvsroot/psqlodbc/execute.c,v retrieving revision 1.1.1.3 retrieving revision 1.1.1.3.2.2 diff -c -r1.1.1.3 -r1.1.1.3.2.2 *** execute.c 2001/03/24 08:14:35 1.1.1.3 --- execute.c 2001/03/24 16:40:47 1.1.1.3.2.2 *************** *** 34,39 **** --- 34,40 ---- #include "qresult.h" #include "convert.h" #include "bind.h" + #include "pgtypes.h" #include "lobj.h" extern GLOBAL_VALUES globals; *************** *** 223,239 **** */ if (stmt->prepare && stmt->status == STMT_PREMATURE) { ! stmt->status = STMT_FINISHED; ! if (stmt->errormsg == NULL) ! { ! mylog("%s: premature statement but return SQL_SUCCESS\n", func); ! return SQL_SUCCESS; ! } else { ! SC_log_error(func, "", stmt); ! mylog("%s: premature statement so return SQL_ERROR\n", func); ! return SQL_ERROR; } } --- 224,245 ---- */ if (stmt->prepare && stmt->status == STMT_PREMATURE) { ! if (stmt->inaccurate_result) ! SC_recycle_statement(stmt); else { ! stmt->status = STMT_FINISHED; ! if (stmt->errormsg == NULL) ! { ! mylog("%s: premature statement but return SQL_SUCCESS\n", func); ! return SQL_SUCCESS; ! } ! else ! { ! SC_log_error(func, "", stmt); ! mylog("%s: premature statement so return SQL_ERROR\n", func); ! return SQL_ERROR; ! } } } *************** *** 284,314 **** } ! /* ! * The bound parameters could have possibly changed since the last ! * execute of this statement? Therefore check for params and re-copy. ! */ ! stmt->data_at_exec = -1; ! for (i = 0; i < stmt->parameters_allocated; i++) { ! /* Check for data at execution parameters */ ! if (stmt->parameters[i].data_at_exec == TRUE) { ! if (stmt->data_at_exec < 0) ! stmt->data_at_exec = 1; ! else ! stmt->data_at_exec++; } ! } ! /* If there are some data at execution parameters, return need data */ ! /* ! * SQLParamData and SQLPutData will be used to send params and execute ! * the statement. ! */ ! if (stmt->data_at_exec > 0) ! return SQL_NEED_DATA; mylog("%s: copying statement params: trans_status=%d, len=%d, stmt='%s'\n", func, conn->transact_status, strlen(stmt->statement), stmt->statement); --- 290,326 ---- } ! /* Check if statement has any data-at-execute parameters when it is not in SC_pre_execute. */ ! if (!stmt->pre_executing) { ! ! /* ! * The bound parameters could have possibly changed since the last ! * execute of this statement? Therefore check for params and re-copy. ! */ ! stmt->data_at_exec = -1; ! for (i = 0; i < stmt->parameters_allocated; i++) { ! /* Check for data at execution parameters */ ! if (stmt->parameters[i].data_at_exec == TRUE) ! { ! if (stmt->data_at_exec < 0) ! stmt->data_at_exec = 1; ! else ! stmt->data_at_exec++; ! } } ! /* If there are some data at execution parameters, return need data */ ! /* ! * SQLParamData and SQLPutData will be used to send params and execute ! * the statement. ! */ ! if (stmt->data_at_exec > 0) ! return SQL_NEED_DATA; + } + mylog("%s: copying statement params: trans_status=%d, len=%d, stmt='%s'\n", func, conn->transact_status, strlen(stmt->statement), stmt->statement); *************** *** 778,785 **** } else ! { /* for handling text fields and small ! * binaries */ if (cbValue == SQL_NTS) { --- 790,796 ---- } else ! { /* for handling fields */ if (cbValue == SQL_NTS) { *************** *** 794,809 **** } else { ! current_param->EXEC_buffer = malloc(cbValue + 1); ! if (!current_param->EXEC_buffer) { ! stmt->errornumber = STMT_NO_MEMORY_ERROR; ! stmt->errormsg = "Out of memory in SQLPutData (2)"; ! SC_log_error(func, "", stmt); ! return SQL_ERROR; } - memcpy(current_param->EXEC_buffer, rgbValue, cbValue); - current_param->EXEC_buffer[cbValue] = '\0'; } } } --- 805,839 ---- } else { ! Int2 ctype = current_param->CType; ! if (ctype == SQL_C_DEFAULT) ! ctype = sqltype_to_default_ctype(current_param->SQLType); ! if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY) { ! current_param->EXEC_buffer = malloc(cbValue + 1); ! if (!current_param->EXEC_buffer) ! { ! stmt->errornumber = STMT_NO_MEMORY_ERROR; ! stmt->errormsg = "Out of memory in SQLPutData (2)"; ! SC_log_error(func, "", stmt); ! return SQL_ERROR; ! } ! memcpy(current_param->EXEC_buffer, rgbValue, cbValue); ! current_param->EXEC_buffer[cbValue] = '\0'; ! } ! else ! { ! Int4 used = ctype_length(ctype); ! current_param->EXEC_buffer = malloc(used); ! if (!current_param->EXEC_buffer) ! { ! stmt->errornumber = STMT_NO_MEMORY_ERROR; ! stmt->errormsg = "Out of memory in SQLPutData (2)"; ! SC_log_error(func, "", stmt); ! return SQL_ERROR; ! } ! memcpy(current_param->EXEC_buffer, rgbValue, used); } } } } Index: pgtypes.c =================================================================== RCS file: /usr/local/src/cvsroot/psqlodbc/pgtypes.c,v retrieving revision 1.1.1.3 retrieving revision 1.1.1.3.2.2 diff -c -r1.1.1.3 -r1.1.1.3.2.2 *** pgtypes.c 2001/03/24 08:14:46 1.1.1.3 --- pgtypes.c 2001/03/24 16:40:47 1.1.1.3.2.2 *************** *** 956,958 **** --- 956,1011 ---- return SQL_C_CHAR; } } + + Int4 + ctype_length(Int2 ctype) + { + switch (ctype) + { + case SQL_C_SSHORT: + case SQL_C_SHORT: + return sizeof(SWORD); + + case SQL_C_USHORT: + return sizeof(UWORD); + + case SQL_C_SLONG: + case SQL_C_LONG: + return sizeof(SDWORD); + + case SQL_C_ULONG: + return sizeof(UDWORD); + + case SQL_C_FLOAT: + return sizeof(SFLOAT); + + case SQL_C_DOUBLE: + return sizeof(SDOUBLE); + + case SQL_C_BIT: + return sizeof(UCHAR); + + case SQL_C_STINYINT: + case SQL_C_TINYINT: + return sizeof(SCHAR); + + case SQL_C_UTINYINT: + return sizeof(UCHAR); + + case SQL_C_DATE: + return sizeof(DATE_STRUCT); + + case SQL_C_TIME: + return sizeof(TIME_STRUCT); + + case SQL_C_TIMESTAMP: + return sizeof(TIMESTAMP_STRUCT); + + case SQL_C_BINARY: + case SQL_C_CHAR: + return 0; + + default: /* should never happen */ + return 0; + } + } Index: pgtypes.h =================================================================== RCS file: /usr/local/src/cvsroot/psqlodbc/pgtypes.h,v retrieving revision 1.1.1.3 retrieving revision 1.1.1.3.2.1 diff -c -r1.1.1.3 -r1.1.1.3.2.1 *** pgtypes.h 2001/03/24 08:14:46 1.1.1.3 --- pgtypes.h 2001/03/24 15:35:12 1.1.1.3.2.1 *************** *** 93,97 **** --- 93,98 ---- char *pgtype_create_params(StatementClass *stmt, Int4 type); Int2 sqltype_to_default_ctype(Int2 sqltype); + Int4 ctype_length(Int2 ctype); #endif Index: statement.c =================================================================== RCS file: /usr/local/src/cvsroot/psqlodbc/statement.c,v retrieving revision 1.1.1.3 retrieving revision 1.1.1.3.2.1 diff -c -r1.1.1.3 -r1.1.1.3.2.1 *** statement.c 2001/03/24 08:14:53 1.1.1.3 --- statement.c 2001/03/24 15:35:12 1.1.1.3.2.1 *************** *** 292,297 **** --- 292,300 ---- /* Clear Statement Options -- defaults will be set in AllocStmt */ memset(&rv->options, 0, sizeof(StatementOptions)); + + rv->pre_executing = FALSE; + rv->inaccurate_result = FALSE; } return rv; } *************** *** 519,524 **** --- 522,528 ---- QR_Destructor(self->result); self->result = NULL; } + self->inaccurate_result = FALSE; /****************************************************************/ /* Reset only parameters that have anything to do with results */ *************** *** 551,568 **** void SC_pre_execute(StatementClass *self) { - mylog("SC_pre_execute: status = %d\n", self->status); if (self->status == STMT_READY) { mylog(" preprocess: status = READY\n"); ! SQLExecute(self); ! if (self->status == STMT_FINISHED) { ! mylog(" preprocess: after status = FINISHED, so set PREMATURE\n"); self->status = STMT_PREMATURE; } } --- 555,587 ---- void SC_pre_execute(StatementClass *self) { mylog("SC_pre_execute: status = %d\n", self->status); if (self->status == STMT_READY) { mylog(" preprocess: status = READY\n"); + + if (self->statement_type == STMT_TYPE_SELECT) + { + char old_pre_executing = self->pre_executing; + self->pre_executing = TRUE; + self->inaccurate_result = FALSE; ! SQLExecute(self); ! self->pre_executing = old_pre_executing; ! ! if (self->status == STMT_FINISHED) ! { ! mylog(" preprocess: after status = FINISHED, so set PREMATURE\n"); ! self->status = STMT_PREMATURE; ! } ! } ! else { ! self->result = QR_Constructor(); ! QR_set_status(self->result, PGRES_TUPLES_OK); ! self->inaccurate_result = TRUE; self->status = STMT_PREMATURE; } } Index: statement.h =================================================================== RCS file: /usr/local/src/cvsroot/psqlodbc/statement.h,v retrieving revision 1.1.1.3 retrieving revision 1.1.1.3.2.1 diff -c -r1.1.1.3 -r1.1.1.3.2.1 *** statement.h 2001/03/24 08:14:54 1.1.1.3 --- statement.h 2001/03/24 15:35:13 1.1.1.3.2.1 *************** *** 213,218 **** --- 213,221 ---- * parameter * substitution */ + char pre_executing; /* This statement is prematurely executing */ + char inaccurate_result; /* Current status is PREMATURE + * but result is inaccurate */ }; #define SC_get_conn(a) (a->hdbc) --ELM989352327-26780-0_-- From Inoue@tpf.co.jp Wed May 9 01:11:32 2001 Received: from sd.tpf.co.jp (sd.tpf.co.jp [210.161.239.34]) by postgresql.org (8.11.3/8.11.1) with SMTP id f491BWA30020 for ; Tue, 8 May 2001 21:11:32 -0400 (EDT) (envelope-from Inoue@tpf.co.jp) Received: (qmail 28120 invoked from network); 9 May 2001 01:11:27 -0000 Received: from unknown (HELO viscomail.tpf.co.jp) (100.0.0.108) by sd2.10.0.100.in-addr.arpa with SMTP; 9 May 2001 01:11:27 -0000 Received: from tpf.co.jp (3d_note1 [126.0.1.61]) by viscomail.tpf.co.jp (8.8.8+Sun/8.8.8) with ESMTP id KAA02257; Wed, 9 May 2001 10:11:26 +0900 (JST) Message-ID: <3AF89956.47FEDBF5@tpf.co.jp> Date: Wed, 09 May 2001 10:11:50 +0900 From: Hiroshi Inoue X-Mailer: Mozilla 4.73 [ja] (Windows NT 5.0; U) X-Accept-Language: ja MIME-Version: 1.0 To: Bruce Momjian CC: Keith Millard , PostgreSQL odbc list Subject: Re: Re: [INTERFACES] Postgres odbc driver bug References: <200105081655.f48GtkL12980@candle.pha.pa.us> Content-Type: text/plain; charset=iso-2022-jp Content-Transfer-Encoding: 7bit X-Archive-Number: 200105/47 X-Sequence-Number: 436 Bruce Momjian wrote: > > OK, I have created a context diff of your changes, which is attached. > Can someone comment on this? The patch appears to deal with > STMT_PREMATURE differently than our current code. > > In fact, it seems to disable this code: > > /* > * If the statement is premature, it means we already executed it from > * an SQLPrepare/SQLDescribeCol type of scenario. So just return > * success. > */ > if (stmt->prepare && stmt->status == STMT_PREMATURE) > Though this fixes the bug reported by Keith, STMT_PREMATURE loses its meaning and SC_pre_execute() does a non-essential work as a result. Possibly SQLPrepare() must be rewritten though I'm not sure. regards, Hiroshi Inoue From Inoue@tpf.co.jp Wed May 9 01:16:12 2001 Received: from sd.tpf.co.jp (sd.tpf.co.jp [210.161.239.34]) by postgresql.org (8.11.3/8.11.1) with SMTP id f491GCA31353 for ; Tue, 8 May 2001 21:16:12 -0400 (EDT) (envelope-from Inoue@tpf.co.jp) Received: (qmail 28488 invoked from network); 9 May 2001 01:16:08 -0000 Received: from unknown (HELO viscomail.tpf.co.jp) (100.0.0.108) by sd2.10.0.100.in-addr.arpa with SMTP; 9 May 2001 01:16:08 -0000 Received: from tpf.co.jp (3d_note1 [126.0.1.61]) by viscomail.tpf.co.jp (8.8.8+Sun/8.8.8) with ESMTP id KAA02267; Wed, 9 May 2001 10:16:08 +0900 (JST) Message-ID: <3AF89A70.A42198ED@tpf.co.jp> Date: Wed, 09 May 2001 10:16:32 +0900 From: Hiroshi Inoue X-Mailer: Mozilla 4.73 [ja] (Windows NT 5.0; U) X-Accept-Language: ja MIME-Version: 1.0 To: Bruce Momjian CC: Keith Millard , "'pgsql-interfaces@postgresql.org'" , PostgreSQL odbc list Subject: Re: [ODBC] Re: Postgres odbc driver bug References: <200105082005.f48K5Rt27279@candle.pha.pa.us> Content-Type: text/plain; charset=iso-2022-jp Content-Transfer-Encoding: 7bit X-Archive-Number: 200105/39 X-Sequence-Number: 1565 Bruce Momjian wrote: > > OK, I have found another person who reported this problem. I have > attached their patch. Can you compare yours to theirs and let me know > what you think? Thanks. > This patch is already committed but it doesn't fix the bug reported by Keith. regards, Hiroshi Inoue From pgman@candle.pha.pa.us Wed May 9 01:53:48 2001 Received: from candle.pha.pa.us (candle.navpoint.com [162.33.245.46]) by postgresql.org (8.11.3/8.11.1) with ESMTP id f491rmA41410 for ; Tue, 8 May 2001 21:53:48 -0400 (EDT) (envelope-from pgman@candle.pha.pa.us) Received: (from pgman@localhost) by candle.pha.pa.us (8.10.1/8.10.1) id f491rWd17938; Tue, 8 May 2001 21:53:32 -0400 (EDT) From: Bruce Momjian Message-Id: <200105090153.f491rWd17938@candle.pha.pa.us> Subject: Re: Re: [INTERFACES] Postgres odbc driver bug In-Reply-To: <3AF89956.47FEDBF5@tpf.co.jp> "from Hiroshi Inoue at May 9, 2001 10:11:50 am" To: Hiroshi Inoue Date: Tue, 8 May 2001 21:53:31 -0400 (EDT) CC: Keith Millard , PostgreSQL odbc list X-Mailer: ELM [version 2.4ME+ PL90 (25)] MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII X-Archive-Number: 200105/49 X-Sequence-Number: 438 > Bruce Momjian wrote: > > > > OK, I have created a context diff of your changes, which is > attached. > > Can someone comment on this? The patch appears to deal with > > STMT_PREMATURE differently than our current code. > > > > In fact, it seems to disable this code: > > > > /* > > * If the statement is premature, it means we already executed it from > > * an SQLPrepare/SQLDescribeCol type of scenario. So just return > > * success. > > */ > > if (stmt->prepare && stmt->status == STMT_PREMATURE) > > > > Though this fixes the bug reported by Keith, STMT_PREMATURE > loses its meaning and SC_pre_execute() does a non-essential > work as a result. Possibly SQLPrepare() must be rewritten > though I'm not sure. OK, I see you have applied your patch: 1) [ODBC] Psqlodbc and Centura: here it is a patch posted by Matteo Cavalleli 2) [ODBC] pgsqODBC binding parameters II posted by Ludek Finstrle 3) Invalid Page Fault in PSQLODBC.DLL personal mail from Johann Zuschlag I removed it from the outstanding patches page. And you are saying that this patch fixes a different problem. The user reported his problems were fixed by that patch, so I am inclined to apply it. Thanks. -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026 From pgman@candle.pha.pa.us Wed May 9 01:57:19 2001 Received: from candle.pha.pa.us (candle.navpoint.com [162.33.245.46]) by postgresql.org (8.11.3/8.11.1) with ESMTP id f491vJA42399; Tue, 8 May 2001 21:57:19 -0400 (EDT) (envelope-from pgman@candle.pha.pa.us) Received: (from pgman@localhost) by candle.pha.pa.us (8.10.1/8.10.1) id f491vBb18158; Tue, 8 May 2001 21:57:11 -0400 (EDT) From: Bruce Momjian Message-Id: <200105090157.f491vBb18158@candle.pha.pa.us> Subject: Re: Postgres odbc driver bug In-Reply-To: "from Keith Millard at May 1, 2001 06:36:36 am" To: Keith Millard Date: Tue, 8 May 2001 21:57:11 -0400 (EDT) CC: "'pgsql-interfaces@postgresql.org'" , PostgreSQL odbc list X-Mailer: ELM [version 2.4ME+ PL90 (25)] MIME-Version: 1.0 Content-Type: multipart/mixed; boundary=ELM989373431-17228-0_ Content-Transfer-Encoding: 7bit X-Archive-Number: 200105/40 X-Sequence-Number: 1566 --ELM989373431-17228-0_ Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII Keith, forget my earlier request about reviewing the patch. One of our ODBC guys (Hiroshi) says your patch fixes a different problem. If no one objects, I will be applying yours in a day or two. Can you make sure my version of your patch is correct? I will change the #if 0 and just remove that code, and remove your //chuck comments. Thanks. > We have found a reproducible problem with the Postgres ODBC driver. It has > to do with the parameter replacement feature in the driver. Below is a > piece of test code that shows the problem. We were able to fix the problem > by making a change to execute.c in the ODBC driver code (attached). > > odbc driver version : Found in both 6.50 and 7.01.0004. > postgresql database version : Found with both 7.0.2 and 7.0.3 versions of > Postgres. > Server Operating System: Windows2000 > Client Operation System: Windows2000 > > Explanation of the odbc driver bug: > > > /***************************************** > * ERROR HAPPENS HERE: > * If we set the buffer that we binded to column "text1" now, it will > FAIL. > * The SQLExecute in doQuery() will succeed (finding 0 rows), and the > * SQLFetchScroll call will return SQL_NO_DATA_FOUND. > * > * This is because of a bug in the odbc driver. The call to > SQLNumResultCols > * will execute the query in the driver, but the buffer that is binded is > > * empty, so no rows will be found. This of course assumes that the > table > * doesn't contain any empty records for the "text1" column, which is > correct > * for our test. Then when we call SQLExcute, the driver will realize it > has > * already done the query work and will not do it again, even though our > * buffer for parameter substitution has changed (next line of code below > > * this comment). > *****************************************/ > > Zip file is attached. The code is currently set up to fail, but I describe > in my comments that you can uncomment the code that sets the buffer before > SQLNumResultCols to make things will work. > > Thanks for your attention, > Keith Millard > > > _____ > > Alex > Shore.. > Senior Software Engineer.. > Pumatech.. > tel 603-888-0666 x1017.. > .. > ashore@pumatech.com.. > www.pumatech.com.. > > [ Attachment, skipping... ] [ Attachment, skipping... ] > > ---------------------------(end of broadcast)--------------------------- > TIP 3: if posting/reading through Usenet, please send an appropriate > subscribe-nomail command to majordomo@postgresql.org so that your > message can get through to the mailing list cleanly -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026 --ELM989373431-17228-0_ Content-Transfer-Encoding: 7bit Content-Type: text/plain Content-Disposition: inline; filename="/bjm/diff" *** e2 Tue May 8 12:49:51 2001 --- execute.c Tue May 8 12:47:48 2001 *************** *** 204,209 **** --- 204,210 ---- it from an SQLPrepare/SQLDescribeCol type of scenario. So just return success. */ + #if 0 //chuck if ( stmt->prepare && stmt->status == STMT_PREMATURE) { stmt->status = STMT_FINISHED; if (stmt->errormsg == NULL) { *************** *** 216,221 **** --- 217,223 ---- return SQL_ERROR; } } + #endif mylog("%s: clear errors...\n", func); *************** *** 248,255 **** } /* Check if the statement is in the correct state */ ! if ((stmt->prepare && stmt->status != STMT_READY) || ! (stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY)) { stmt->errornumber = STMT_STATUS_ERROR; stmt->errormsg = "The handle does not point to a statement that is ready to be executed"; --- 250,259 ---- } /* Check if the statement is in the correct state */ ! //chuck if ((stmt->prepare && stmt->status != STMT_READY) || ! //chuck (stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY)) { ! if ((stmt->prepare && (stmt->status != STMT_READY && stmt->status != STMT_PREMATURE)) || //chuck ! (stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY && stmt->status != STMT_PREMATURE)) { //chuck stmt->errornumber = STMT_STATUS_ERROR; stmt->errormsg = "The handle does not point to a statement that is ready to be executed"; *************** *** 262,270 **** --- 266,277 ---- /* The bound parameters could have possibly changed since the last execute of this statement? Therefore check for params and re-copy. */ + mylog("%s: Check for data at execution parameters\n", func); + mylog("%s: stmt->parameters_allocated = %d\n", func,stmt->parameters_allocated); stmt->data_at_exec = -1; for (i = 0; i < stmt->parameters_allocated; i++) { /* Check for data at execution parameters */ + mylog("%s: stmt->parameters[%d].data_at_exec = %d\n", func,i,stmt->parameters[i].data_at_exec); if ( stmt->parameters[i].data_at_exec == TRUE) { if (stmt->data_at_exec < 0) stmt->data_at_exec = 1; --ELM989373431-17228-0_-- From Inoue@tpf.co.jp Wed May 9 02:05:29 2001 Received: from sd.tpf.co.jp (sd.tpf.co.jp [210.161.239.34]) by postgresql.org (8.11.3/8.11.1) with SMTP id f4925TA44900 for ; Tue, 8 May 2001 22:05:29 -0400 (EDT) (envelope-from Inoue@tpf.co.jp) Received: (qmail 32560 invoked from network); 9 May 2001 02:05:23 -0000 Received: from unknown (HELO viscomail.tpf.co.jp) (100.0.0.108) by sd2.10.0.100.in-addr.arpa with SMTP; 9 May 2001 02:05:23 -0000 Received: from tpf.co.jp (3d_note1 [126.0.1.61]) by viscomail.tpf.co.jp (8.8.8+Sun/8.8.8) with ESMTP id LAA02298; Wed, 9 May 2001 11:05:23 +0900 (JST) Message-ID: <3AF8A5FB.819D8A92@tpf.co.jp> Date: Wed, 09 May 2001 11:05:47 +0900 From: Hiroshi Inoue X-Mailer: Mozilla 4.73 [ja] (Windows NT 5.0; U) X-Accept-Language: ja MIME-Version: 1.0 To: Bruce Momjian CC: Keith Millard , PostgreSQL odbc list Subject: Re: Re: [INTERFACES] Postgres odbc driver bug References: <200105090153.f491rWd17938@candle.pha.pa.us> Content-Type: text/plain; charset=iso-2022-jp Content-Transfer-Encoding: 7bit X-Archive-Number: 200105/51 X-Sequence-Number: 440 Bruce Momjian wrote: > > > Bruce Momjian wrote: > > > > > > OK, I have created a context diff of your changes, which is > > attached. > > > Can someone comment on this? The patch appears to deal with > > > STMT_PREMATURE differently than our current code. > > > > > > In fact, it seems to disable this code: > > > > > > /* > > > * If the statement is premature, it means we already executed it from > > > * an SQLPrepare/SQLDescribeCol type of scenario. So just return > > > * success. > > > */ > > > if (stmt->prepare && stmt->status == STMT_PREMATURE) > > > > > > > Though this fixes the bug reported by Keith, STMT_PREMATURE > > loses its meaning and SC_pre_execute() does a non-essential > > work as a result. Possibly SQLPrepare() must be rewritten > > though I'm not sure. > [snip] > > And you are saying that this patch fixes a different problem. The user > reported his problems were fixed by that patch, so I am inclined to > apply it. > I don't agree to apply the patch because the patch makes the current code hardly understandable. regards, Hiroshi inoue From pgman@candle.pha.pa.us Wed May 9 02:58:23 2001 Received: from candle.pha.pa.us (candle.navpoint.com [162.33.245.46]) by postgresql.org (8.11.3/8.11.1) with ESMTP id f492wNA59197 for ; Tue, 8 May 2001 22:58:23 -0400 (EDT) (envelope-from pgman@candle.pha.pa.us) Received: (from pgman@localhost) by candle.pha.pa.us (8.10.1/8.10.1) id f492w8u21241; Tue, 8 May 2001 22:58:08 -0400 (EDT) From: Bruce Momjian Message-Id: <200105090258.f492w8u21241@candle.pha.pa.us> Subject: Re: Re: [INTERFACES] Postgres odbc driver bug In-Reply-To: <3AF8A5FB.819D8A92@tpf.co.jp> "from Hiroshi Inoue at May 9, 2001 11:05:47 am" To: Hiroshi Inoue Date: Tue, 8 May 2001 22:58:08 -0400 (EDT) CC: Keith Millard , PostgreSQL odbc list X-Mailer: ELM [version 2.4ME+ PL90 (25)] MIME-Version: 1.0 Content-Type: multipart/mixed; boundary=ELM989377088-20955-0_ Content-Transfer-Encoding: 7bit X-Archive-Number: 200105/52 X-Sequence-Number: 441 --ELM989377088-20955-0_ Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII > > And you are saying that this patch fixes a different problem. The user > > reported his problems were fixed by that patch, so I am inclined to > > apply it. > > > > I don't agree to apply the patch because the patch makes > the current code hardly understandable. Agreed. I mentioned to Keith I was going to clean it up before application. Here is the cleaned up patch. Hiroshi, what do you think? -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026 --ELM989377088-20955-0_ Content-Transfer-Encoding: 7bit Content-Type: text/plain Content-Disposition: inline; filename="/bjm/diff" Index: src/interfaces/odbc/execute.c =================================================================== RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/odbc/execute.c,v retrieving revision 1.29 diff -c -r1.29 execute.c *** src/interfaces/odbc/execute.c 2001/05/08 17:12:36 1.29 --- src/interfaces/odbc/execute.c 2001/05/09 02:37:04 *************** *** 217,248 **** return SQL_INVALID_HANDLE; } - /* - * If the statement is premature, it means we already executed it from - * an SQLPrepare/SQLDescribeCol type of scenario. So just return - * success. - */ - if (stmt->prepare && stmt->status == STMT_PREMATURE) - { - if (stmt->inaccurate_result) - SC_recycle_statement(stmt); - else - { - stmt->status = STMT_FINISHED; - if (stmt->errormsg == NULL) - { - mylog("%s: premature statement but return SQL_SUCCESS\n", func); - return SQL_SUCCESS; - } - else - { - SC_log_error(func, "", stmt); - mylog("%s: premature statement so return SQL_ERROR\n", func); - return SQL_ERROR; - } - } - } - mylog("%s: clear errors...\n", func); SC_clear_error(stmt); --- 217,222 ---- *************** *** 278,285 **** } /* Check if the statement is in the correct state */ ! if ((stmt->prepare && stmt->status != STMT_READY) || ! (stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY)) { stmt->errornumber = STMT_STATUS_ERROR; stmt->errormsg = "The handle does not point to a statement that is ready to be executed"; --- 252,259 ---- } /* Check if the statement is in the correct state */ ! if ((stmt->prepare && (stmt->status != STMT_READY && stmt->status != STMT_PREMATURE)) || ! (stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY && stmt->status != STMT_PREMATURE)) { stmt->errornumber = STMT_STATUS_ERROR; stmt->errormsg = "The handle does not point to a statement that is ready to be executed"; *************** *** 294,310 **** */ if (!stmt->pre_executing) { - /* * The bound parameters could have possibly changed since the last * execute of this statement? Therefore check for params and * re-copy. */ stmt->data_at_exec = -1; for (i = 0; i < stmt->parameters_allocated; i++) { Int4 *pcVal = stmt->parameters[i].used; if (pcVal && (*pcVal == SQL_DATA_AT_EXEC || *pcVal <= SQL_LEN_DATA_AT_EXEC_OFFSET)) stmt->parameters[i].data_at_exec = TRUE; else --- 268,286 ---- */ if (!stmt->pre_executing) { /* * The bound parameters could have possibly changed since the last * execute of this statement? Therefore check for params and * re-copy. */ + mylog("%s: Check for data at execution parameters\n", func); + mylog("%s: stmt->parameters_allocated = %d\n", func,stmt->parameters_allocated); stmt->data_at_exec = -1; for (i = 0; i < stmt->parameters_allocated; i++) { Int4 *pcVal = stmt->parameters[i].used; + mylog("%s: stmt->parameters[%d].data_at_exec = %d\n", func,i,stmt->parameters[i].data_at_exec); if (pcVal && (*pcVal == SQL_DATA_AT_EXEC || *pcVal <= SQL_LEN_DATA_AT_EXEC_OFFSET)) stmt->parameters[i].data_at_exec = TRUE; else --ELM989377088-20955-0_-- From Inoue@tpf.co.jp Wed May 9 03:20:02 2001 Received: from sd.tpf.co.jp (sd.tpf.co.jp [210.161.239.34]) by postgresql.org (8.11.3/8.11.1) with SMTP id f493K2A65947 for ; Tue, 8 May 2001 23:20:02 -0400 (EDT) (envelope-from Inoue@tpf.co.jp) Received: (qmail 6442 invoked from network); 9 May 2001 03:19:57 -0000 Received: from unknown (HELO viscomail.tpf.co.jp) (100.0.0.108) by sd2.10.0.100.in-addr.arpa with SMTP; 9 May 2001 03:19:57 -0000 Received: from tpf.co.jp (3d_note1 [126.0.1.61]) by viscomail.tpf.co.jp (8.8.8+Sun/8.8.8) with ESMTP id MAA02323; Wed, 9 May 2001 12:19:56 +0900 (JST) Message-ID: <3AF8B775.C63AE519@tpf.co.jp> Date: Wed, 09 May 2001 12:20:21 +0900 From: Hiroshi Inoue X-Mailer: Mozilla 4.73 [ja] (Windows NT 5.0; U) X-Accept-Language: ja MIME-Version: 1.0 To: Bruce Momjian CC: Keith Millard , PostgreSQL odbc list Subject: Re: Re: [INTERFACES] Postgres odbc driver bug References: <200105090258.f492w8u21241@candle.pha.pa.us> Content-Type: text/plain; charset=iso-2022-jp Content-Transfer-Encoding: 7bit X-Archive-Number: 200105/53 X-Sequence-Number: 442 Bruce Momjian wrote: > > > > And you are saying that this patch fixes a different problem. The user > > > reported his problems were fixed by that patch, so I am inclined to > > > apply it. > > > > > > > I don't agree to apply the patch because the patch makes > > the current code hardly understandable. > > Agreed. I mentioned to Keith I was going to clean it up before > application. Here is the cleaned up patch. > > Hiroshi, what do you think? > Hmm that's not what I mean. The patch essentially means that the STMT_PREMATURE state is unnecessary. Well why is the concept *PREMATURE* introduced ? What meaning does the stuff related to the concept *PREMATURE* have ? IMHO we have to reconsider from the first. regards, Hiroshi Inoue From pgman@candle.pha.pa.us Wed May 9 03:24:58 2001 Received: from candle.pha.pa.us (candle.navpoint.com [162.33.245.46]) by postgresql.org (8.11.3/8.11.1) with ESMTP id f493OwA67392 for ; Tue, 8 May 2001 23:24:58 -0400 (EDT) (envelope-from pgman@candle.pha.pa.us) Received: (from pgman@localhost) by candle.pha.pa.us (8.10.1/8.10.1) id f493Oio22886; Tue, 8 May 2001 23:24:44 -0400 (EDT) From: Bruce Momjian Message-Id: <200105090324.f493Oio22886@candle.pha.pa.us> Subject: Re: Re: [INTERFACES] Postgres odbc driver bug In-Reply-To: <3AF8B775.C63AE519@tpf.co.jp> "from Hiroshi Inoue at May 9, 2001 12:20:21 pm" To: Hiroshi Inoue Date: Tue, 8 May 2001 23:24:44 -0400 (EDT) CC: Keith Millard , PostgreSQL odbc list X-Mailer: ELM [version 2.4ME+ PL90 (25)] MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII X-Archive-Number: 200105/54 X-Sequence-Number: 443 > > Agreed. I mentioned to Keith I was going to clean it up before > > application. Here is the cleaned up patch. > > > > Hiroshi, what do you think? > > > > Hmm that's not what I mean. The patch essentially means > that the STMT_PREMATURE state is unnecessary. Well why is > the concept *PREMATURE* introduced ? What meaning does the > stuff related to the concept *PREMATURE* have ? IMHO we > have to reconsider from the first. Oh, so you need Keith to explain the patch. OK. -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026 From Inoue@tpf.co.jp Wed May 9 03:44:43 2001 Received: from sd.tpf.co.jp (sd.tpf.co.jp [210.161.239.34]) by postgresql.org (8.11.3/8.11.1) with SMTP id f493ihA73073 for ; Tue, 8 May 2001 23:44:43 -0400 (EDT) (envelope-from Inoue@tpf.co.jp) Received: (qmail 8288 invoked from network); 9 May 2001 03:44:38 -0000 Received: from unknown (HELO viscomail.tpf.co.jp) (100.0.0.108) by sd2.10.0.100.in-addr.arpa with SMTP; 9 May 2001 03:44:38 -0000 Received: from tpf.co.jp (3d_note1 [126.0.1.61]) by viscomail.tpf.co.jp (8.8.8+Sun/8.8.8) with ESMTP id MAA02338; Wed, 9 May 2001 12:44:37 +0900 (JST) Message-ID: <3AF8BD3E.BE32AA0A@tpf.co.jp> Date: Wed, 09 May 2001 12:45:02 +0900 From: Hiroshi Inoue X-Mailer: Mozilla 4.73 [ja] (Windows NT 5.0; U) X-Accept-Language: ja MIME-Version: 1.0 To: Bruce Momjian CC: Keith Millard , PostgreSQL odbc list Subject: Re: Re: [INTERFACES] Postgres odbc driver bug References: <200105090324.f493Oio22886@candle.pha.pa.us> Content-Type: text/plain; charset=iso-2022-jp Content-Transfer-Encoding: 7bit X-Archive-Number: 200105/55 X-Sequence-Number: 444 Bruce Momjian wrote: > > > > Agreed. I mentioned to Keith I was going to clean it up before > > > application. Here is the cleaned up patch. > > > > > > Hiroshi, what do you think? > > > > > > > Hmm that's not what I mean. The patch essentially means > > that the STMT_PREMATURE state is unnecessary. Well why is > > the concept *PREMATURE* introduced ? What meaning does the > > stuff related to the concept *PREMATURE* have ? IMHO we > > have to reconsider from the first. > > Oh, so you need Keith to explain the patch. OK. > I got the following mail from Keith personally about 10 hours ago. I don't like the temporary fix. It also loses the advantge of *PREMATURE* handling. [A part of his mail] > I'm not saying that our fix is the long-term solution > to this problem but it does demonstrate the issue we > found and a possible fix. What we were not sure of > is what other ramifications are there with the fix we made. regards, Hiroshi Inoue From pgman@candle.pha.pa.us Wed May 9 13:04:05 2001 Received: from candle.pha.pa.us (candle.navpoint.com [162.33.245.46]) by postgresql.org (8.11.3/8.11.1) with ESMTP id f49D45A12609 for ; Wed, 9 May 2001 09:04:05 -0400 (EDT) (envelope-from pgman@candle.pha.pa.us) Received: (from pgman@localhost) by candle.pha.pa.us (8.10.1/8.10.1) id f49D3tR19915; Wed, 9 May 2001 09:03:55 -0400 (EDT) From: Bruce Momjian Message-Id: <200105091303.f49D3tR19915@candle.pha.pa.us> Subject: Re: Re: [INTERFACES] Postgres odbc driver bug In-Reply-To: <3AF8BD3E.BE32AA0A@tpf.co.jp> "from Hiroshi Inoue at May 9, 2001 12:45:02 pm" To: Hiroshi Inoue Date: Wed, 9 May 2001 09:03:55 -0400 (EDT) CC: Keith Millard , PostgreSQL odbc list X-Mailer: ELM [version 2.4ME+ PL90 (25)] MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII X-Archive-Number: 200105/58 X-Sequence-Number: 447 > I got the following mail from Keith personally about > 10 hours ago. I don't like the temporary fix. It also > loses the advantge of *PREMATURE* handling. > > [A part of his mail] > > > I'm not saying that our fix is the long-term solution > > to this problem but it does demonstrate the issue we > > found and a possible fix. What we were not sure of > > is what other ramifications are there with the fix we made. Yes, I emailed him and asked that he test your fixes. My guess is that you fixed the cause of his problem already in 7.1.1. Removing the patch from the outstanding patches list. -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026