Bug #32270 SQLBindParameter with value = '\' fails with myODBC 3.51.21
Submitted: 12 Nov 2007 9:45 Modified: 20 Nov 2007 17:21
Reporter: vha
Status: Not a Bug
Category:Connector/ODBC Severity:S3 (Non-critical)
Version:3.51.21 OS:Microsoft Windows
Assigned to: Target Version:

[12 Nov 2007 9:45] vha
Description:
When executing an SQL statement like for example 'SELECT * FROM myTable WHERE myColumn =
?' using SqlBindParameter and where the value of the path is a single backslash, the
SqlExecDirect() function fails with return code -1.

If I replace the \ by \\, the function succeeds.

Remark however that if the Path contains something like '\Users', the function succeeds
(without having to dup the \)

Also, with myODBC 5.1 (mysql-connector-odbc-5.1.1-alphar798_20070925_2311-win32.msi), I
have no problems.

vha

How to repeat:
#ifndef UNICODE
#define UNICODE
#endif

#ifndef _UNICODE
#define _UNICODE
#endif

#include <windows.h>
#include <stdio.h>
#include <tchar.h>

#include <sql.h>
#include <sqlext.h>

#define _tsizeof(S) sizeof(S) / sizeof(S[0])

#define CONN_351 TEXT("DRIVER={MySQL ODBC 3.51
Driver};SERVER=localhost;Regional=No;UID=root;PWD=mysql;Trusted_Connection=no;DATABASE=dt4
ed;Option=3")
#define CONN_510 TEXT("DRIVER={MySQL ODBC 5.1
Driver};SERVER=localhost;Regional=No;UID=root;PWD=mysql;Trusted_Connection=no;DATABASE=dt4
ed;Option=3")

#define ODBC_5_1

int _tmain(int argc, LPTSTR *argv)
//********************************
{
  SQLHENV  hEnv;
  SQLHDBC  hDBC;

  BOOL bODBC_51 = (argc > 1);

  SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv);
  SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);
  SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDBC);

  SQLSetConnectAttr(hDBC, SQL_ATTR_LOGIN_TIMEOUT,      (SQLPOINTER)5, 0);
  SQLSetConnectAttr(hDBC, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER)5, 0);

  TCHAR szTmp[512] = {0};
  SHORT dwLen      = 0;

  LPTSTR szConn = ( bODBC_51 ) ? CONN_510 : CONN_351;
  SQLDriverConnect(hDBC, NULL, (SQLTCHAR *)szConn, _tcslen(szConn), (SQLTCHAR *)szTmp,
_tsizeof(szTmp), &dwLen, SQL_DRIVER_NOPROMPT);

  _tprintf(TEXT("%s\n"), szTmp);

  SQLHSTMT hStmt;

  //
  // Re-create the table
  //
  SQLAllocHandle(SQL_HANDLE_STMT, hDBC, &hStmt);
  SQLExecDirect(hStmt, (SQLTCHAR*)TEXT("DROP TABLE IF EXISTS t"), SQL_NTS);
  SQLExecDirect(hStmt, (SQLTCHAR*)TEXT("CREATE TABLE t ( Path NVARCHAR(256) )"),
SQL_NTS);
  SQLFreeStmt(hStmt, SQL_DROP);

  //
  // Select the data using column binding
  //
  LPTSTR pData1 = TEXT("\\");
  LONG   i1     = SQL_NTS;

  SQLAllocHandle(SQL_HANDLE_STMT, hDBC, &hStmt);

  if ( bODBC_51 )
  {
    SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_TCHAR, SQL_WVARCHAR, 256, 0, pData1,
_tcslen(pData1), &i1);
  }
  else
  {
    SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_TCHAR, SQL_VARCHAR, 256, 0, pData1,
_tcslen(pData1), &i1);
  }

  //
  // This one will fail for myODBC 3.51.21, and succeed for myODBC 5.1.x
  //
  int RetCode = SQLExecDirect(hStmt, (SQLTCHAR*)TEXT("SELECT DISTINCT Path FROM t WHERE
Upper(Path) = Upper(?)"), SQL_NTS);
  _tprintf(TEXT("SELECT: RetCode %d\n"), RetCode);
  SQLFreeStmt(hStmt, SQL_DROP);

  SQLEndTran(SQL_HANDLE_DBC, hDBC, SQL_COMMIT);
  SQLDisconnect(hDBC);
  SQLFreeHandle(SQL_HANDLE_DBC, hDBC);
  SQLEndTran(SQL_HANDLE_ENV, hEnv, SQL_COMMIT);
  SQLFreeHandle(SQL_HANDLE_ENV, hEnv);

  return 0;
}
[12 Nov 2007 14:43] vha
Note that the bug does not show up if in the sample code the _tcslen(pData1) in the
SQLBindParameter() functions is replaced with 0
[16 Nov 2007 9:34] Susanne Ebrecht
It seems, that you use the MyODBC v5.1 in your example code.

Please, can you add a simple test file and the trace file for your issues.
[16 Nov 2007 10:29] vha
If I use myODBC 5.1, there is no problem.

The bug onlyshows up when using myODBC 3.51

(I guess the "#define ODBC_5_1" in the sample code was confusing, but in fact that was
isn't used furtheron in the code).

vha
[16 Nov 2007 11:15] Susanne Ebrecht
Test and trace still missing ...
[16 Nov 2007 11:36] vha
What exactly do you need, and how do I create these (never done this...)?

Remark that if you compile and link the attached code, the executable will show you the
error.

vha
[16 Nov 2007 12:36] Tonci Grgin
Vha, Susanne is just being through. To enable DM trace start Control Panel/Administrative
tools/Data Sources (ODBC)/ check "Machine wide tracing" and click "Start tracing now".
Also, a general query log from server might help to see what got where (start server with
--log or add log command to [mysqld].
[16 Nov 2007 12:39] Susanne Ebrecht
Look here:

http://dev.mysql.com/doc/refman/5.1/en/myodbc-configuration-trace.html
[16 Nov 2007 13:02] vha
ODBC Trace & mysqld-nt.exe logfile

Attachment: SQL.log (text/plain), 8.45 KiB.

[16 Nov 2007 13:36] vha
Some extra tracing:

C:\Program Files\MySQL\MySQL Server 5.0\bin\mysqld-nt.exe, Version:
5.0.45-community-nt-log (MySQL Community Edition (GPL)). started with:
TCP Port: 3306, Named Pipe: (null)
Time                 Id Command    Argument

##
## using myODBC v5.10
## SQLBindParameter(..., SQL_C_TCHAR, SQL_WVARCHAR, 256, 0, p, _tcslen(p), &i)
## WCHAR *p = L"\\"
## -> return code 0
##
071116 13:20:36	      1 Connect     root@localhost on dt4ed
		      1 Query       SET NAMES utf8
		      1 Query       SET character_set_results = NULL
		      1 Query       SET SQL_AUTO_IS_NULL = 0
		      1 Query       DROP TABLE IF EXISTS t
		      1 Query       CREATE TABLE t ( Path NVARCHAR(256) )
		      1 Query       SELECT DISTINCT Path FROM t WHERE Upper(Path) = Upper('\\')
		      1 Quit
##
## using myODBC v3.51.22
## SQLBindParameter(..., SQL_C_TCHAR, SQL_VARCHAR, 256, 0, p, _tcslen(p), &i)
## WCHAR *p = L"\\"
## -> return code -1
##
071116 13:21:23	      2 Connect     root@localhost on dt4ed
		      2 Query       SET SQL_AUTO_IS_NULL = 0
		      2 Query       DROP TABLE IF EXISTS t
		      2 Query       CREATE TABLE t ( Path NVARCHAR(256) )
		      2 Query       SELECT DISTINCT Path FROM t WHERE Upper(Path) = Upper('\\')
		      2 Quit
##
## using myODBC v3.51.22
## SQLBindParameter(..., SQL_C_CHAR, SQL_VARCHAR, 256, 0, p, strlen(p), &i)
## char *p = "\\"
## -> return code 0!!!
##
071116 13:21:51	      3 Connect     root@localhost on dt4ed
		      3 Query       SET SQL_AUTO_IS_NULL = 0
		      3 Query       DROP TABLE IF EXISTS t
		      3 Query       CREATE TABLE t ( Path NVARCHAR(256) )
		      3 Query       SELECT DISTINCT Path FROM t WHERE Upper(Path) = Upper('\\')
		      3 Quit
##
## using myODBC v5.10
## SQLBindParameter(..., SQL_C_CHAR, SQL_WVARCHAR, 256, 0, p, strlen(p), &i)
## char *p = "\\"
## -> return code 0
##
071116 13:22:20	      4 Connect     root@localhost on dt4ed
		      4 Query       SET NAMES utf8
		      4 Query       SET character_set_results = NULL
		      4 Query       SET SQL_AUTO_IS_NULL = 0
		      4 Query       DROP TABLE IF EXISTS t
		      4 Query       CREATE TABLE t ( Path NVARCHAR(256) )
		      4 Query       SELECT DISTINCT Path FROM t WHERE Upper(Path) = Upper(_latin1'\\')
		      4 Quit
[17 Nov 2007 10:05] vha
Remark that the problem not only occurs with '\\'
[17 Nov 2007 10:05] vha
Remark that the problem not only occurs with \, but with any *single* character
[19 Nov 2007 14:01] Susanne Ebrecht
You confuse me.
Consider, that MyODBC v3.51 doesn't support unicode (W) functions and doesn't have proper
SQL_C_WCHAR support. 

I can't see the bug here. Please, add a test code written in C, where the error will
occur.
[19 Nov 2007 14:26] vha
The attached code is in C and reproduces the bug...
[19 Nov 2007 14:30] vha
Here is the C code attached as a file instead of embedded in the bug report

Attachment: q7.cpp (text/plain), 2.53 KiB.

[20 Nov 2007 9:00] Tonci Grgin
C++ test case

Attachment: Bug32270-351.cpp (text/x-c++), 4.01 KiB.

[20 Nov 2007 9:08] Tonci Grgin
Vha, this is not a bug. You have been warned that using unicode with MyODBC 3.51 might
lead to unpredictable results. Please consider my test case.

The part that fails is shown in my DM trace (using your test case):
d38-ba8	ENTER SQLExecDirectW 
		HSTMT               00972520
		WCHAR *             0x0045CF18 [      -3] "SELECT DISTINCT Path FROM bug32270 WHERE
Upper(Path) = Upper(?)\ 0"
		SDWORD                    -3

d38-ba8	EXIT  SQLExecDirectW  with return code -1 (SQL_ERROR)

I see this as expected and explained behavior.
[20 Nov 2007 9:28] vha
If that is not a bug, then why:
- does MySQL allow the use of SQL_C_TCHAR: why not always return an error here
- does MySQL allow the use of all the unicode functions
- does it only fail if the bound parameter has a length of 1 single character

Remark that in my test case of SQLBindParameter(), I specify that the *input* is unicode
(SQL_C_TCHAR), but that it should be converted, by the ODBC driver, to ansi (SQL_VARCHAR),
which MySQL does fully support:

>>SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_TCHAR, SQL_VARCHAR, 
>>                 256, 0, pData, _tcslen(pData), &i);

vha (disappointed)
[20 Nov 2007 12:31] Susanne Ebrecht
vha,

imagine, you want to cook potatoes. You need: potatoes, water and salt.
Of course there is also sugar in your kitchen (driver manager like unixODBC, libIODBC,
Windows ODBC Driver Manager).
When you now cook potatoes and put sugar instead of salt into the water, the pot won't
explode or won't tell you on another way, that this wasn't the right ingredients for your
potatoes cooking.

Only your little sister will tell you, that your potatoes tastes ugly.

When you need unicode support, MyODBC version 3.51 is the wrong connector. MyODBC version
5.1 supports unicode. Now you have two choices:

1. use MyODBC version 5.1
2. don't use unicode when you want to use MyODBC version 3.51

We recommend you, to do the first one.

Many thanks, for trusting MySQL.

Kind Regards,

Susanne
[20 Nov 2007 17:21] vha
The problem I have is this:

- ANSI is also not an option because my application has to support Japanese character sets
among others and this on different databases (MSSQL, Oracle, PostgreSQL, ...). This to me
can only be done using unicode.

- myODBC 5.10 is currently also not an option because not stable enough (I reported some
bugs with 5.10 that showed up during my tests)

Also, 3.51 not supporting UNICODE still doesn't explain to me why all strings can be used
in that select statement without any problem, *except* strings of 1 character long. I
can't believe that bug is hard to correct...

vha