2 ** MySQL Database Driver
3 ** Copyright (C) 2003-2015 Victor Kirhenshtein
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 DECLARE_DRIVER_HEADER("MYSQL")
28 * Update error message from given source
30 static void UpdateErrorMessage(const char *source
, WCHAR
*errorText
)
32 if (errorText
!= NULL
)
34 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, source
, -1, errorText
, DBDRV_MAX_ERROR_TEXT
);
35 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
36 RemoveTrailingCRLFW(errorText
);
41 * Update buffer length in DrvPrepareStringW
43 #define UPDATE_LENGTH \
45 if (len >= bufferSize - 1) \
48 out = (WCHAR *)realloc(out, bufferSize * sizeof(WCHAR)); \
52 * Prepare string for using in SQL query - enclose in quotes and escape as needed
53 * (wide string version)
55 extern "C" WCHAR EXPORT
*DrvPrepareStringW(const WCHAR
*str
)
57 int len
= (int)wcslen(str
) + 3; // + two quotes and \0 at the end
58 int bufferSize
= len
+ 128;
59 WCHAR
*out
= (WCHAR
*)malloc(bufferSize
* sizeof(WCHAR
));
62 const WCHAR
*src
= str
;
64 for(outPos
= 1; *src
!= 0; src
++)
69 out
[outPos
++] = L
'\'';
70 out
[outPos
++] = L
'\'';
74 out
[outPos
++] = L
'\\';
75 out
[outPos
++] = L
'\r';
79 out
[outPos
++] = L
'\\';
80 out
[outPos
++] = L
'\n';
84 out
[outPos
++] = L
'\\';
85 out
[outPos
++] = L
'\b';
89 out
[outPos
++] = L
'\\';
90 out
[outPos
++] = L
'\t';
94 out
[outPos
++] = L
'\\';
98 out
[outPos
++] = L
'\\';
99 out
[outPos
++] = L
'\\';
103 out
[outPos
++] = *src
;
107 out
[outPos
++] = L
'\'';
116 * Update buffer length in DrvPrepareStringA
118 #define UPDATE_LENGTH \
120 if (len >= bufferSize - 1) \
123 out = (char *)realloc(out, bufferSize); \
127 * Prepare string for using in SQL query - enclose in quotes and escape as needed
128 * (multibyte string version)
130 extern "C" char EXPORT
*DrvPrepareStringA(const char *str
)
132 int len
= (int)strlen(str
) + 3; // + two quotes and \0 at the end
133 int bufferSize
= len
+ 128;
134 char *out
= (char *)malloc(bufferSize
);
137 const char *src
= str
;
139 for(outPos
= 1; *src
!= 0; src
++)
144 out
[outPos
++] = '\'';
145 out
[outPos
++] = '\'';
149 out
[outPos
++] = '\\';
150 out
[outPos
++] = '\r';
154 out
[outPos
++] = '\\';
155 out
[outPos
++] = '\n';
159 out
[outPos
++] = '\\';
160 out
[outPos
++] = '\b';
164 out
[outPos
++] = '\\';
165 out
[outPos
++] = '\t';
169 out
[outPos
++] = '\\';
173 out
[outPos
++] = '\\';
174 out
[outPos
++] = '\\';
178 out
[outPos
++] = *src
;
182 out
[outPos
++] = '\'';
193 extern "C" bool EXPORT
DrvInit(const char *cmdLine
)
195 return mysql_library_init(0, NULL
, NULL
) == 0;
201 extern "C" void EXPORT
DrvUnload()
207 * Connect to database
209 extern "C" DBDRV_CONNECTION EXPORT
DrvConnect(const char *szHost
, const char *szLogin
, const char *szPassword
,
210 const char *szDatabase
, const char *schema
, WCHAR
*errorText
)
214 const char *pHost
= szHost
;
215 const char *pSocket
= NULL
;
217 pMySQL
= mysql_init(NULL
);
220 wcscpy(errorText
, L
"Insufficient memory to allocate connection handle");
224 pSocket
= strstr(szHost
, "socket:");
231 if (!mysql_real_connect(
234 szLogin
[0] == 0 ? NULL
: szLogin
, // user
235 (szPassword
[0] == 0 || szLogin
[0] == 0) ? NULL
: szPassword
, // pass
236 szDatabase
, // DB Name
237 0, // use default port
238 pSocket
, // char * - unix socket
242 UpdateErrorMessage(mysql_error(pMySQL
), errorText
);
247 pConn
= (MYSQL_CONN
*)malloc(sizeof(MYSQL_CONN
));
248 pConn
->pMySQL
= pMySQL
;
249 pConn
->mutexQueryLock
= MutexCreate();
251 // Switch to UTF-8 encoding
252 mysql_set_character_set(pMySQL
, "utf8");
254 return (DBDRV_CONNECTION
)pConn
;
258 * Disconnect from database
260 extern "C" void EXPORT
DrvDisconnect(MYSQL_CONN
*pConn
)
264 mysql_close(pConn
->pMySQL
);
265 MutexDestroy(pConn
->mutexQueryLock
);
273 extern "C" DBDRV_STATEMENT EXPORT
DrvPrepare(MYSQL_CONN
*pConn
, WCHAR
*pwszQuery
, DWORD
*pdwError
, WCHAR
*errorText
)
275 MYSQL_STATEMENT
*result
= NULL
;
277 MutexLock(pConn
->mutexQueryLock
);
278 MYSQL_STMT
*stmt
= mysql_stmt_init(pConn
->pMySQL
);
281 char *pszQueryUTF8
= UTF8StringFromWideString(pwszQuery
);
282 int rc
= mysql_stmt_prepare(stmt
, pszQueryUTF8
, (unsigned long)strlen(pszQueryUTF8
));
285 result
= (MYSQL_STATEMENT
*)malloc(sizeof(MYSQL_STATEMENT
));
286 result
->connection
= pConn
;
287 result
->statement
= stmt
;
288 result
->paramCount
= (int)mysql_stmt_param_count(stmt
);
289 result
->bindings
= (MYSQL_BIND
*)malloc(sizeof(MYSQL_BIND
) * result
->paramCount
);
290 memset(result
->bindings
, 0, sizeof(MYSQL_BIND
) * result
->paramCount
);
291 result
->lengthFields
= (unsigned long *)malloc(sizeof(unsigned long) * result
->paramCount
);
292 memset(result
->lengthFields
, 0, sizeof(unsigned long) * result
->paramCount
);
293 result
->buffers
= new Array(result
->paramCount
, 16, true);
294 *pdwError
= DBERR_SUCCESS
;
298 int nErr
= mysql_errno(pConn
->pMySQL
);
299 if (nErr
== CR_SERVER_LOST
|| nErr
== CR_CONNECTION_ERROR
|| nErr
== CR_SERVER_GONE_ERROR
)
301 *pdwError
= DBERR_CONNECTION_LOST
;
305 *pdwError
= DBERR_OTHER_ERROR
;
307 UpdateErrorMessage(mysql_stmt_error(stmt
), errorText
);
308 mysql_stmt_close(stmt
);
314 *pdwError
= DBERR_OTHER_ERROR
;
315 UpdateErrorMessage("Call to mysql_stmt_init failed", errorText
);
317 MutexUnlock(pConn
->mutexQueryLock
);
322 * Bind parameter to prepared statement
324 extern "C" void EXPORT
DrvBind(MYSQL_STATEMENT
*hStmt
, int pos
, int sqlType
, int cType
, void *buffer
, int allocType
)
326 static size_t bufferSize
[] = { 0, sizeof(INT32
), sizeof(UINT32
), sizeof(INT64
), sizeof(UINT64
), sizeof(double) };
328 if ((pos
< 1) || (pos
> hStmt
->paramCount
))
330 MYSQL_BIND
*b
= &hStmt
->bindings
[pos
- 1];
332 if (cType
== DB_CTYPE_STRING
)
334 b
->buffer
= UTF8StringFromWideString((WCHAR
*)buffer
);
335 hStmt
->buffers
->add(b
->buffer
);
336 if (allocType
== DB_BIND_DYNAMIC
)
338 b
->buffer_length
= (unsigned long)strlen((char *)b
->buffer
) + 1;
339 hStmt
->lengthFields
[pos
- 1] = b
->buffer_length
- 1;
340 b
->length
= &hStmt
->lengthFields
[pos
- 1];
341 b
->buffer_type
= MYSQL_TYPE_STRING
;
350 case DB_BIND_DYNAMIC
:
352 hStmt
->buffers
->add(buffer
);
354 case DB_BIND_TRANSIENT
:
355 b
->buffer
= nx_memdup(buffer
, bufferSize
[cType
]);
356 hStmt
->buffers
->add(b
->buffer
);
359 return; // Invalid call
364 case DB_CTYPE_UINT32
:
365 b
->is_unsigned
= true;
368 b
->buffer_type
= MYSQL_TYPE_LONG
;
370 case DB_CTYPE_UINT64
:
371 b
->is_unsigned
= true;
374 b
->buffer_type
= MYSQL_TYPE_LONGLONG
;
376 case DB_CTYPE_DOUBLE
:
377 b
->buffer_type
= MYSQL_TYPE_DOUBLE
;
384 * Execute prepared statement
386 extern "C" DWORD EXPORT
DrvExecute(MYSQL_CONN
*pConn
, MYSQL_STATEMENT
*hStmt
, WCHAR
*errorText
)
390 MutexLock(pConn
->mutexQueryLock
);
392 if (mysql_stmt_bind_param(hStmt
->statement
, hStmt
->bindings
) == 0)
394 if (mysql_stmt_execute(hStmt
->statement
) == 0)
396 dwResult
= DBERR_SUCCESS
;
400 int nErr
= mysql_errno(pConn
->pMySQL
);
401 if (nErr
== CR_SERVER_LOST
|| nErr
== CR_CONNECTION_ERROR
|| nErr
== CR_SERVER_GONE_ERROR
)
403 dwResult
= DBERR_CONNECTION_LOST
;
407 dwResult
= DBERR_OTHER_ERROR
;
409 UpdateErrorMessage(mysql_stmt_error(hStmt
->statement
), errorText
);
414 UpdateErrorMessage(mysql_stmt_error(hStmt
->statement
), errorText
);
415 dwResult
= DBERR_OTHER_ERROR
;
418 MutexUnlock(pConn
->mutexQueryLock
);
423 * Destroy prepared statement
425 extern "C" void EXPORT
DrvFreeStatement(MYSQL_STATEMENT
*hStmt
)
430 MutexLock(hStmt
->connection
->mutexQueryLock
);
431 mysql_stmt_close(hStmt
->statement
);
432 MutexUnlock(hStmt
->connection
->mutexQueryLock
);
433 delete hStmt
->buffers
;
434 safe_free(hStmt
->bindings
);
435 safe_free(hStmt
->lengthFields
);
440 * Perform actual non-SELECT query
442 static DWORD
DrvQueryInternal(MYSQL_CONN
*pConn
, const char *pszQuery
, WCHAR
*errorText
)
444 DWORD dwRet
= DBERR_INVALID_HANDLE
;
446 MutexLock(pConn
->mutexQueryLock
);
447 if (mysql_query(pConn
->pMySQL
, pszQuery
) == 0)
449 dwRet
= DBERR_SUCCESS
;
450 if (errorText
!= NULL
)
455 int nErr
= mysql_errno(pConn
->pMySQL
);
456 if (nErr
== CR_SERVER_LOST
|| nErr
== CR_CONNECTION_ERROR
|| nErr
== CR_SERVER_GONE_ERROR
) // CR_SERVER_GONE_ERROR - ???
458 dwRet
= DBERR_CONNECTION_LOST
;
462 dwRet
= DBERR_OTHER_ERROR
;
464 UpdateErrorMessage(mysql_error(pConn
->pMySQL
), errorText
);
467 MutexUnlock(pConn
->mutexQueryLock
);
472 * Perform non-SELECT query
474 extern "C" DWORD EXPORT
DrvQuery(MYSQL_CONN
*pConn
, WCHAR
*pwszQuery
, WCHAR
*errorText
)
479 pszQueryUTF8
= UTF8StringFromWideString(pwszQuery
);
480 dwRet
= DrvQueryInternal(pConn
, pszQueryUTF8
, errorText
);
486 * Perform SELECT query
488 extern "C" DBDRV_RESULT EXPORT
DrvSelect(MYSQL_CONN
*pConn
, WCHAR
*pwszQuery
, DWORD
*pdwError
, WCHAR
*errorText
)
490 MYSQL_RESULT
*result
= NULL
;
495 *pdwError
= DBERR_INVALID_HANDLE
;
499 pszQueryUTF8
= UTF8StringFromWideString(pwszQuery
);
500 MutexLock(pConn
->mutexQueryLock
);
501 if (mysql_query(pConn
->pMySQL
, pszQueryUTF8
) == 0)
503 result
= (MYSQL_RESULT
*)malloc(sizeof(MYSQL_RESULT
));
504 result
->connection
= pConn
;
505 result
->isPreparedStatement
= false;
506 result
->resultSet
= mysql_store_result(pConn
->pMySQL
);
507 *pdwError
= DBERR_SUCCESS
;
508 if (errorText
!= NULL
)
513 int nErr
= mysql_errno(pConn
->pMySQL
);
514 if (nErr
== CR_SERVER_LOST
|| nErr
== CR_CONNECTION_ERROR
|| nErr
== CR_SERVER_GONE_ERROR
) // CR_SERVER_GONE_ERROR - ???
516 *pdwError
= DBERR_CONNECTION_LOST
;
520 *pdwError
= DBERR_OTHER_ERROR
;
522 UpdateErrorMessage(mysql_error(pConn
->pMySQL
), errorText
);
525 MutexUnlock(pConn
->mutexQueryLock
);
531 * Perform SELECT query using prepared statement
533 extern "C" DBDRV_RESULT EXPORT
DrvSelectPrepared(MYSQL_CONN
*pConn
, MYSQL_STATEMENT
*hStmt
, DWORD
*pdwError
, WCHAR
*errorText
)
535 MYSQL_RESULT
*result
= NULL
;
539 *pdwError
= DBERR_INVALID_HANDLE
;
543 MutexLock(pConn
->mutexQueryLock
);
545 if (mysql_stmt_bind_param(hStmt
->statement
, hStmt
->bindings
) == 0)
547 if (mysql_stmt_execute(hStmt
->statement
) == 0)
549 result
= (MYSQL_RESULT
*)malloc(sizeof(MYSQL_RESULT
));
550 result
->connection
= pConn
;
551 result
->isPreparedStatement
= true;
552 result
->statement
= hStmt
->statement
;
553 result
->resultSet
= mysql_stmt_result_metadata(hStmt
->statement
);
554 if (result
->resultSet
!= NULL
)
556 result
->numColumns
= mysql_num_fields(result
->resultSet
);
558 result
->lengthFields
= (unsigned long *)malloc(sizeof(unsigned long) * result
->numColumns
);
559 memset(result
->lengthFields
, 0, sizeof(unsigned long) * result
->numColumns
);
561 result
->bindings
= (MYSQL_BIND
*)malloc(sizeof(MYSQL_BIND
) * result
->numColumns
);
562 memset(result
->bindings
, 0, sizeof(MYSQL_BIND
) * result
->numColumns
);
563 for(int i
= 0; i
< result
->numColumns
; i
++)
565 result
->bindings
[i
].buffer_type
= MYSQL_TYPE_STRING
;
566 result
->bindings
[i
].length
= &result
->lengthFields
[i
];
569 mysql_stmt_bind_result(hStmt
->statement
, result
->bindings
);
571 if (mysql_stmt_store_result(hStmt
->statement
) == 0)
573 result
->numRows
= (int)mysql_stmt_num_rows(hStmt
->statement
);
574 result
->currentRow
= -1;
575 *pdwError
= DBERR_SUCCESS
;
579 UpdateErrorMessage(mysql_stmt_error(hStmt
->statement
), errorText
);
580 *pdwError
= DBERR_OTHER_ERROR
;
581 mysql_free_result(result
->resultSet
);
582 free(result
->bindings
);
583 free(result
->lengthFields
);
590 UpdateErrorMessage(mysql_stmt_error(hStmt
->statement
), errorText
);
591 *pdwError
= DBERR_OTHER_ERROR
;
598 int nErr
= mysql_errno(pConn
->pMySQL
);
599 if (nErr
== CR_SERVER_LOST
|| nErr
== CR_CONNECTION_ERROR
|| nErr
== CR_SERVER_GONE_ERROR
)
601 *pdwError
= DBERR_CONNECTION_LOST
;
605 *pdwError
= DBERR_OTHER_ERROR
;
607 UpdateErrorMessage(mysql_stmt_error(hStmt
->statement
), errorText
);
612 UpdateErrorMessage(mysql_stmt_error(hStmt
->statement
), errorText
);
613 *pdwError
= DBERR_OTHER_ERROR
;
616 MutexUnlock(pConn
->mutexQueryLock
);
621 * Get field length from result
623 extern "C" LONG EXPORT
DrvGetFieldLength(MYSQL_RESULT
*hResult
, int iRow
, int iColumn
)
625 if (hResult
->isPreparedStatement
)
627 if ((iRow
< 0) || (iRow
>= hResult
->numRows
) ||
628 (iColumn
< 0) || (iColumn
>= hResult
->numColumns
))
631 if (hResult
->currentRow
!= iRow
)
633 MutexLock(hResult
->connection
->mutexQueryLock
);
634 mysql_stmt_data_seek(hResult
->statement
, iRow
);
635 mysql_stmt_fetch(hResult
->statement
);
636 hResult
->currentRow
= iRow
;
637 MutexUnlock(hResult
->connection
->mutexQueryLock
);
639 return (LONG
)hResult
->lengthFields
[iColumn
];
643 mysql_data_seek(hResult
->resultSet
, iRow
);
644 MYSQL_ROW row
= mysql_fetch_row(hResult
->resultSet
);
645 return (row
== NULL
) ? (LONG
)-1 : ((row
[iColumn
] == NULL
) ? -1 : (LONG
)strlen(row
[iColumn
]));
650 * Get field value from result - UNICODE and UTF8 implementation
652 static void *GetFieldInternal(MYSQL_RESULT
*hResult
, int iRow
, int iColumn
, void *pBuffer
, int nBufSize
, bool utf8
)
656 if (hResult
->isPreparedStatement
)
658 if ((iRow
< 0) || (iRow
>= hResult
->numRows
) ||
659 (iColumn
< 0) || (iColumn
>= hResult
->numColumns
))
662 MutexLock(hResult
->connection
->mutexQueryLock
);
663 if (hResult
->currentRow
!= iRow
)
665 mysql_stmt_data_seek(hResult
->statement
, iRow
);
666 mysql_stmt_fetch(hResult
->statement
);
667 hResult
->currentRow
= iRow
;
674 memset(&b
, 0, sizeof(MYSQL_BIND
));
676 b
.buffer
= alloca(hResult
->lengthFields
[iColumn
] + 1);
678 b
.buffer
= malloc(hResult
->lengthFields
[iColumn
] + 1);
680 b
.buffer_length
= hResult
->lengthFields
[iColumn
] + 1;
681 b
.buffer_type
= MYSQL_TYPE_STRING
;
684 int rc
= mysql_stmt_fetch_column(hResult
->statement
, &b
, iColumn
, 0);
689 ((char *)b
.buffer
)[l
] = 0;
692 strncpy((char *)pBuffer
, (char *)b
.buffer
, nBufSize
);
693 ((char *)pBuffer
)[nBufSize
- 1] = 0;
697 MultiByteToWideChar(CP_UTF8
, 0, (char *)b
.buffer
, -1, (WCHAR
*)pBuffer
, nBufSize
);
698 ((WCHAR
*)pBuffer
)[nBufSize
- 1] = 0;
704 *((char *)pBuffer
) = 0;
706 *((WCHAR
*)pBuffer
) = 0;
710 MutexUnlock(hResult
->connection
->mutexQueryLock
);
717 mysql_data_seek(hResult
->resultSet
, iRow
);
718 MYSQL_ROW row
= mysql_fetch_row(hResult
->resultSet
);
721 if (row
[iColumn
] != NULL
)
725 strncpy((char *)pBuffer
, row
[iColumn
], nBufSize
);
726 ((char *)pBuffer
)[nBufSize
- 1] = 0;
730 MultiByteToWideChar(CP_UTF8
, 0, row
[iColumn
], -1, (WCHAR
*)pBuffer
, nBufSize
);
731 ((WCHAR
*)pBuffer
)[nBufSize
- 1] = 0;
741 * Get field value from result
743 extern "C" WCHAR EXPORT
*DrvGetField(MYSQL_RESULT
*hResult
, int iRow
, int iColumn
, WCHAR
*pBuffer
, int nBufSize
)
745 return (WCHAR
*)GetFieldInternal(hResult
, iRow
, iColumn
, pBuffer
, nBufSize
, false);
749 * Get field value from result as UTF8 string
751 extern "C" char EXPORT
*DrvGetFieldUTF8(MYSQL_RESULT
*hResult
, int iRow
, int iColumn
, char *pBuffer
, int nBufSize
)
753 return (char *)GetFieldInternal(hResult
, iRow
, iColumn
, pBuffer
, nBufSize
, true);
757 * Get number of rows in result
759 extern "C" int EXPORT
DrvGetNumRows(MYSQL_RESULT
*hResult
)
761 return (hResult
!= NULL
) ? (int)(hResult
->isPreparedStatement
? hResult
->numRows
: mysql_num_rows(hResult
->resultSet
)) : 0;
765 * Get column count in query result
767 extern "C" int EXPORT
DrvGetColumnCount(MYSQL_RESULT
*hResult
)
769 return (hResult
!= NULL
) ? (int)mysql_num_fields(hResult
->resultSet
) : 0;
773 * Get column name in query result
775 extern "C" const char EXPORT
*DrvGetColumnName(MYSQL_RESULT
*hResult
, int column
)
782 field
= mysql_fetch_field_direct(hResult
->resultSet
, column
);
783 return (field
!= NULL
) ? field
->name
: NULL
;
787 * Free SELECT results
789 extern "C" void EXPORT
DrvFreeResult(MYSQL_RESULT
*hResult
)
794 if (hResult
->isPreparedStatement
)
796 safe_free(hResult
->bindings
);
797 safe_free(hResult
->lengthFields
);
800 mysql_free_result(hResult
->resultSet
);
805 * Perform unbuffered SELECT query
807 extern "C" DBDRV_UNBUFFERED_RESULT EXPORT
DrvSelectUnbuffered(MYSQL_CONN
*pConn
, WCHAR
*pwszQuery
, DWORD
*pdwError
, WCHAR
*errorText
)
809 MYSQL_UNBUFFERED_RESULT
*pResult
= NULL
;
814 *pdwError
= DBERR_INVALID_HANDLE
;
818 pszQueryUTF8
= UTF8StringFromWideString(pwszQuery
);
819 MutexLock(pConn
->mutexQueryLock
);
820 if (mysql_query(pConn
->pMySQL
, pszQueryUTF8
) == 0)
822 pResult
= (MYSQL_UNBUFFERED_RESULT
*)malloc(sizeof(MYSQL_UNBUFFERED_RESULT
));
823 pResult
->connection
= pConn
;
824 pResult
->isPreparedStatement
= false;
825 pResult
->resultSet
= mysql_use_result(pConn
->pMySQL
);
826 if (pResult
->resultSet
!= NULL
)
828 pResult
->noMoreRows
= false;
829 pResult
->numColumns
= mysql_num_fields(pResult
->resultSet
);
830 pResult
->pCurrRow
= NULL
;
831 pResult
->lengthFields
= (unsigned long *)malloc(sizeof(unsigned long) * pResult
->numColumns
);
832 pResult
->bindings
= NULL
;
840 *pdwError
= DBERR_SUCCESS
;
841 if (errorText
!= NULL
)
846 int nErr
= mysql_errno(pConn
->pMySQL
);
847 if (nErr
== CR_SERVER_LOST
|| nErr
== CR_CONNECTION_ERROR
|| nErr
== CR_SERVER_GONE_ERROR
) // CR_SERVER_GONE_ERROR - ???
849 *pdwError
= DBERR_CONNECTION_LOST
;
853 *pdwError
= DBERR_OTHER_ERROR
;
856 if (errorText
!= NULL
)
858 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, mysql_error(pConn
->pMySQL
), -1, errorText
, DBDRV_MAX_ERROR_TEXT
);
859 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
860 RemoveTrailingCRLFW(errorText
);
866 MutexUnlock(pConn
->mutexQueryLock
);
874 * Perform unbuffered SELECT query using prepared statement
876 extern "C" DBDRV_RESULT EXPORT
DrvSelectPreparedUnbuffered(MYSQL_CONN
*pConn
, MYSQL_STATEMENT
*hStmt
, DWORD
*pdwError
, WCHAR
*errorText
)
878 MYSQL_UNBUFFERED_RESULT
*result
= NULL
;
880 MutexLock(pConn
->mutexQueryLock
);
882 if (mysql_stmt_bind_param(hStmt
->statement
, hStmt
->bindings
) == 0)
884 if (mysql_stmt_execute(hStmt
->statement
) == 0)
886 result
= (MYSQL_UNBUFFERED_RESULT
*)malloc(sizeof(MYSQL_UNBUFFERED_RESULT
));
887 result
->connection
= pConn
;
888 result
->isPreparedStatement
= true;
889 result
->statement
= hStmt
->statement
;
890 result
->resultSet
= mysql_stmt_result_metadata(hStmt
->statement
);
891 if (result
->resultSet
!= NULL
)
893 result
->noMoreRows
= false;
894 result
->numColumns
= mysql_num_fields(result
->resultSet
);
895 result
->pCurrRow
= NULL
;
897 result
->lengthFields
= (unsigned long *)malloc(sizeof(unsigned long) * result
->numColumns
);
898 memset(result
->lengthFields
, 0, sizeof(unsigned long) * result
->numColumns
);
900 result
->bindings
= (MYSQL_BIND
*)malloc(sizeof(MYSQL_BIND
) * result
->numColumns
);
901 memset(result
->bindings
, 0, sizeof(MYSQL_BIND
) * result
->numColumns
);
902 for(int i
= 0; i
< result
->numColumns
; i
++)
904 result
->bindings
[i
].buffer_type
= MYSQL_TYPE_STRING
;
905 result
->bindings
[i
].length
= &result
->lengthFields
[i
];
908 mysql_stmt_bind_result(hStmt
->statement
, result
->bindings
);
909 *pdwError
= DBERR_SUCCESS
;
913 UpdateErrorMessage(mysql_stmt_error(hStmt
->statement
), errorText
);
914 *pdwError
= DBERR_OTHER_ERROR
;
921 int nErr
= mysql_errno(pConn
->pMySQL
);
922 if (nErr
== CR_SERVER_LOST
|| nErr
== CR_CONNECTION_ERROR
|| nErr
== CR_SERVER_GONE_ERROR
)
924 *pdwError
= DBERR_CONNECTION_LOST
;
928 *pdwError
= DBERR_OTHER_ERROR
;
930 UpdateErrorMessage(mysql_stmt_error(hStmt
->statement
), errorText
);
935 UpdateErrorMessage(mysql_stmt_error(hStmt
->statement
), errorText
);
936 *pdwError
= DBERR_OTHER_ERROR
;
941 MutexUnlock(pConn
->mutexQueryLock
);
947 * Fetch next result line from asynchronous SELECT results
949 extern "C" bool EXPORT
DrvFetch(MYSQL_UNBUFFERED_RESULT
*result
)
951 if ((result
== NULL
) || (result
->noMoreRows
))
956 if (result
->isPreparedStatement
)
958 int rc
= mysql_stmt_fetch(result
->statement
);
959 if ((rc
!= 0) && (rc
!= MYSQL_DATA_TRUNCATED
))
961 result
->noMoreRows
= true;
963 MutexUnlock(result
->connection
->mutexQueryLock
);
968 // Try to fetch next row from server
969 result
->pCurrRow
= mysql_fetch_row(result
->resultSet
);
970 if (result
->pCurrRow
== NULL
)
972 result
->noMoreRows
= true;
974 MutexUnlock(result
->connection
->mutexQueryLock
);
980 // Get column lengths for current row
981 pLen
= mysql_fetch_lengths(result
->resultSet
);
984 memcpy(result
->lengthFields
, pLen
, sizeof(unsigned long) * result
->numColumns
);
988 memset(result
->lengthFields
, 0, sizeof(unsigned long) * result
->numColumns
);
996 * Get field length from async query result result
998 extern "C" LONG EXPORT
DrvGetFieldLengthUnbuffered(MYSQL_UNBUFFERED_RESULT
*hResult
, int iColumn
)
1000 // Check if we have valid result handle
1001 if (hResult
== NULL
)
1004 // Check if there are valid fetched row
1005 if (hResult
->noMoreRows
|| ((hResult
->pCurrRow
== NULL
) && !hResult
->isPreparedStatement
))
1008 // Check if column number is valid
1009 if ((iColumn
< 0) || (iColumn
>= hResult
->numColumns
))
1012 return hResult
->lengthFields
[iColumn
];
1016 * Get field from current row in async query result
1018 extern "C" WCHAR EXPORT
*DrvGetFieldUnbuffered(MYSQL_UNBUFFERED_RESULT
*hResult
, int iColumn
, WCHAR
*pBuffer
, int iBufSize
)
1020 // Check if we have valid result handle
1021 if (hResult
== NULL
)
1024 // Check if there are valid fetched row
1025 if ((hResult
->noMoreRows
) || ((hResult
->pCurrRow
== NULL
) && !hResult
->isPreparedStatement
))
1028 // Check if column number is valid
1029 if ((iColumn
< 0) || (iColumn
>= hResult
->numColumns
))
1032 // Now get column data
1033 WCHAR
*value
= NULL
;
1034 if (hResult
->isPreparedStatement
)
1037 unsigned long l
= 0;
1040 memset(&b
, 0, sizeof(MYSQL_BIND
));
1042 b
.buffer
= alloca(hResult
->lengthFields
[iColumn
] + 1);
1044 b
.buffer
= malloc(hResult
->lengthFields
[iColumn
] + 1);
1046 b
.buffer_length
= hResult
->lengthFields
[iColumn
] + 1;
1047 b
.buffer_type
= MYSQL_TYPE_STRING
;
1049 b
.is_null
= &isNull
;
1050 int rc
= mysql_stmt_fetch_column(hResult
->statement
, &b
, iColumn
, 0);
1055 ((char *)b
.buffer
)[l
] = 0;
1056 MultiByteToWideChar(CP_UTF8
, 0, (char *)b
.buffer
, -1, (WCHAR
*)pBuffer
, iBufSize
);
1057 ((WCHAR
*)pBuffer
)[iBufSize
- 1] = 0;
1061 *((WCHAR
*)pBuffer
) = 0;
1071 int iLen
= min((int)hResult
->lengthFields
[iColumn
], iBufSize
- 1);
1074 MultiByteToWideChar(CP_UTF8
, 0, hResult
->pCurrRow
[iColumn
], iLen
, pBuffer
, iBufSize
);
1083 * Get column count in async query result
1085 extern "C" int EXPORT
DrvGetColumnCountUnbuffered(MYSQL_UNBUFFERED_RESULT
*hResult
)
1087 return (hResult
!= NULL
) ? hResult
->numColumns
: 0;
1091 * Get column name in async query result
1093 extern "C" const char EXPORT
*DrvGetColumnNameUnbuffered(MYSQL_UNBUFFERED_RESULT
*hResult
, int column
)
1097 if ((hResult
== NULL
) || (hResult
->resultSet
== NULL
))
1100 field
= mysql_fetch_field_direct(hResult
->resultSet
, column
);
1101 return (field
!= NULL
) ? field
->name
: NULL
;
1105 * Destroy result of async query
1107 extern "C" void EXPORT
DrvFreeUnbufferedResult(MYSQL_UNBUFFERED_RESULT
*hResult
)
1109 if (hResult
== NULL
)
1112 // Check if all result rows fetched
1113 if (!hResult
->noMoreRows
)
1115 // Fetch remaining rows
1116 if (!hResult
->isPreparedStatement
)
1118 while(mysql_fetch_row(hResult
->resultSet
) != NULL
);
1121 // Now we are ready for next query, so unlock query mutex
1122 MutexUnlock(hResult
->connection
->mutexQueryLock
);
1125 // Free allocated memory
1126 mysql_free_result(hResult
->resultSet
);
1127 free(hResult
->lengthFields
);
1128 free(hResult
->bindings
);
1135 extern "C" DWORD EXPORT
DrvBegin(MYSQL_CONN
*pConn
)
1137 return DrvQueryInternal(pConn
, "BEGIN", NULL
);
1141 * Commit transaction
1143 extern "C" DWORD EXPORT
DrvCommit(MYSQL_CONN
*pConn
)
1145 return DrvQueryInternal(pConn
, "COMMIT", NULL
);
1149 * Rollback transaction
1151 extern "C" DWORD EXPORT
DrvRollback(MYSQL_CONN
*pConn
)
1153 return DrvQueryInternal(pConn
, "ROLLBACK", NULL
);
1157 * Check if table exist
1159 extern "C" int EXPORT
DrvIsTableExist(MYSQL_CONN
*pConn
, const WCHAR
*name
)
1161 WCHAR query
[256], lname
[256];
1162 wcsncpy(lname
, name
, 256);
1164 swprintf(query
, 256, L
"SHOW TABLES LIKE '%ls'", lname
);
1166 WCHAR errorText
[DBDRV_MAX_ERROR_TEXT
];
1167 int rc
= DBIsTableExist_Failure
;
1168 MYSQL_RESULT
*hResult
= (MYSQL_RESULT
*)DrvSelect(pConn
, query
, &error
, errorText
);
1169 if (hResult
!= NULL
)
1171 rc
= (DrvGetNumRows(hResult
) > 0) ? DBIsTableExist_Found
: DBIsTableExist_NotFound
;
1172 DrvFreeResult(hResult
);
1182 bool WINAPI
DllMain(HINSTANCE hInstance
, DWORD dwReason
, LPVOID lpReserved
)
1184 if (dwReason
== DLL_PROCESS_ATTACH
)
1185 DisableThreadLibraryCalls(hInstance
);