implemented DB driver call DrvGetFieldUnbufferedUTF8 (for databases with native UTF...
[public/netxms.git] / src / db / dbdrv / mysql / mysql.cpp
CommitLineData
5039dede
AK
1/*
2** MySQL Database Driver
3bca413f 3** Copyright (C) 2003-2015 Victor Kirhenshtein
5039dede
AK
4**
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.
9**
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.
14**
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.
18**
19** File: mysql.cpp
20**
21**/
22
23#include "mysqldrv.h"
24
c94bb5aa
VK
25DECLARE_DRIVER_HEADER("MYSQL")
26
7aad6641
VK
27/**
28 * Update error message from given source
29 */
c94bb5aa
VK
30static void UpdateErrorMessage(const char *source, WCHAR *errorText)
31{
32 if (errorText != NULL)
33 {
34 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, -1, errorText, DBDRV_MAX_ERROR_TEXT);
35 errorText[DBDRV_MAX_ERROR_TEXT - 1] = 0;
36 RemoveTrailingCRLFW(errorText);
37 }
38}
5039dede 39
7aad6641
VK
40/**
41 * Update buffer length in DrvPrepareStringW
42 */
643c9dcb
VK
43#define UPDATE_LENGTH \
44 len++; \
45 if (len >= bufferSize - 1) \
46 { \
47 bufferSize += 128; \
fe1d4002 48 out = (WCHAR *)realloc(out, bufferSize * sizeof(WCHAR)); \
643c9dcb
VK
49 }
50
7aad6641
VK
51/**
52 * Prepare string for using in SQL query - enclose in quotes and escape as needed
53 * (wide string version)
54 */
fe1d4002 55extern "C" WCHAR EXPORT *DrvPrepareStringW(const WCHAR *str)
643c9dcb 56{
fe1d4002 57 int len = (int)wcslen(str) + 3; // + two quotes and \0 at the end
643c9dcb 58 int bufferSize = len + 128;
fe1d4002 59 WCHAR *out = (WCHAR *)malloc(bufferSize * sizeof(WCHAR));
643c9dcb
VK
60 out[0] = _T('\'');
61
fe1d4002 62 const WCHAR *src = str;
643c9dcb 63 int outPos;
66827adf 64 for(outPos = 1; *src != 0; src++)
643c9dcb
VK
65 {
66 switch(*src)
67 {
fe1d4002
VK
68 case L'\'':
69 out[outPos++] = L'\'';
70 out[outPos++] = L'\'';
643c9dcb
VK
71 UPDATE_LENGTH;
72 break;
fe1d4002
VK
73 case L'\r':
74 out[outPos++] = L'\\';
75 out[outPos++] = L'\r';
643c9dcb
VK
76 UPDATE_LENGTH;
77 break;
fe1d4002
VK
78 case L'\n':
79 out[outPos++] = L'\\';
80 out[outPos++] = L'\n';
643c9dcb
VK
81 UPDATE_LENGTH;
82 break;
fe1d4002
VK
83 case L'\b':
84 out[outPos++] = L'\\';
85 out[outPos++] = L'\b';
643c9dcb
VK
86 UPDATE_LENGTH;
87 break;
fe1d4002
VK
88 case L'\t':
89 out[outPos++] = L'\\';
90 out[outPos++] = L'\t';
643c9dcb
VK
91 UPDATE_LENGTH;
92 break;
93 case 26:
fe1d4002
VK
94 out[outPos++] = L'\\';
95 out[outPos++] = L'Z';
643c9dcb 96 break;
fe1d4002
VK
97 case L'\\':
98 out[outPos++] = L'\\';
99 out[outPos++] = L'\\';
643c9dcb
VK
100 UPDATE_LENGTH;
101 break;
102 default:
103 out[outPos++] = *src;
104 break;
105 }
106 }
fe1d4002
VK
107 out[outPos++] = L'\'';
108 out[outPos++] = 0;
109
110 return out;
111}
112
113#undef UPDATE_LENGTH
7aad6641
VK
114
115/**
116 * Update buffer length in DrvPrepareStringA
117 */
fe1d4002
VK
118#define UPDATE_LENGTH \
119 len++; \
120 if (len >= bufferSize - 1) \
121 { \
122 bufferSize += 128; \
123 out = (char *)realloc(out, bufferSize); \
124 }
125
7aad6641
VK
126/**
127 * Prepare string for using in SQL query - enclose in quotes and escape as needed
128 * (multibyte string version)
129 */
fe1d4002
VK
130extern "C" char EXPORT *DrvPrepareStringA(const char *str)
131{
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);
135 out[0] = _T('\'');
136
137 const char *src = str;
138 int outPos;
66827adf 139 for(outPos = 1; *src != 0; src++)
fe1d4002
VK
140 {
141 switch(*src)
142 {
143 case '\'':
144 out[outPos++] = '\'';
145 out[outPos++] = '\'';
146 UPDATE_LENGTH;
147 break;
148 case '\r':
149 out[outPos++] = '\\';
150 out[outPos++] = '\r';
151 UPDATE_LENGTH;
152 break;
153 case '\n':
154 out[outPos++] = '\\';
155 out[outPos++] = '\n';
156 UPDATE_LENGTH;
157 break;
158 case '\b':
159 out[outPos++] = '\\';
160 out[outPos++] = '\b';
161 UPDATE_LENGTH;
162 break;
163 case '\t':
164 out[outPos++] = '\\';
165 out[outPos++] = '\t';
166 UPDATE_LENGTH;
167 break;
168 case 26:
169 out[outPos++] = '\\';
170 out[outPos++] = 'Z';
171 break;
172 case '\\':
173 out[outPos++] = '\\';
174 out[outPos++] = '\\';
175 UPDATE_LENGTH;
176 break;
177 default:
178 out[outPos++] = *src;
179 break;
180 }
181 }
182 out[outPos++] = '\'';
643c9dcb
VK
183 out[outPos++] = 0;
184
185 return out;
186}
187
188#undef UPDATE_LENGTH
189
7aad6641
VK
190/**
191 * Initialize driver
192 */
2df047f4 193extern "C" bool EXPORT DrvInit(const char *cmdLine)
5039dede 194{
fa88627b 195 return mysql_library_init(0, NULL, NULL) == 0;
5039dede
AK
196}
197
7aad6641
VK
198/**
199 * Unload handler
200 */
08b214c6 201extern "C" void EXPORT DrvUnload()
5039dede 202{
fa88627b 203 mysql_library_end();
5039dede
AK
204}
205
7aad6641
VK
206/**
207 * Connect to database
208 */
465b3f2d 209extern "C" DBDRV_CONNECTION EXPORT DrvConnect(const char *szHost, const char *szLogin, const char *szPassword,
f3c30cf5 210 const char *szDatabase, const char *schema, WCHAR *errorText)
5039dede
AK
211{
212 MYSQL *pMySQL;
213 MYSQL_CONN *pConn;
465b3f2d
VK
214 const char *pHost = szHost;
215 const char *pSocket = NULL;
5039dede
AK
216
217 pMySQL = mysql_init(NULL);
218 if (pMySQL == NULL)
219 {
465b3f2d 220 wcscpy(errorText, L"Insufficient memory to allocate connection handle");
5039dede
AK
221 return NULL;
222 }
223
224 pSocket = strstr(szHost, "socket:");
225 if (pSocket != NULL)
226 {
227 pHost = NULL;
228 pSocket += 7;
229 }
230
231 if (!mysql_real_connect(
232 pMySQL, // MYSQL *
233 pHost, // host
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
239 0 // flags
240 ))
241 {
c94bb5aa 242 UpdateErrorMessage(mysql_error(pMySQL), errorText);
5039dede
AK
243 mysql_close(pMySQL);
244 return NULL;
245 }
246
247 pConn = (MYSQL_CONN *)malloc(sizeof(MYSQL_CONN));
248 pConn->pMySQL = pMySQL;
249 pConn->mutexQueryLock = MutexCreate();
250
251 // Switch to UTF-8 encoding
643c9dcb 252 mysql_set_character_set(pMySQL, "utf8");
5039dede 253
b8c1ec69 254 return (DBDRV_CONNECTION)pConn;
5039dede
AK
255}
256
7aad6641
VK
257/**
258 * Disconnect from database
259 */
5039dede
AK
260extern "C" void EXPORT DrvDisconnect(MYSQL_CONN *pConn)
261{
262 if (pConn != NULL)
263 {
264 mysql_close(pConn->pMySQL);
265 MutexDestroy(pConn->mutexQueryLock);
266 free(pConn);
267 }
268}
269
7aad6641
VK
270/**
271 * Prepare statement
272 */
de1d708f 273extern "C" DBDRV_STATEMENT EXPORT DrvPrepare(MYSQL_CONN *pConn, WCHAR *pwszQuery, DWORD *pdwError, WCHAR *errorText)
c94bb5aa
VK
274{
275 MYSQL_STATEMENT *result = NULL;
276
c17f6cbc 277 MutexLock(pConn->mutexQueryLock);
c94bb5aa
VK
278 MYSQL_STMT *stmt = mysql_stmt_init(pConn->pMySQL);
279 if (stmt != NULL)
280 {
281 char *pszQueryUTF8 = UTF8StringFromWideString(pwszQuery);
ef856d02 282 int rc = mysql_stmt_prepare(stmt, pszQueryUTF8, (unsigned long)strlen(pszQueryUTF8));
c94bb5aa
VK
283 if (rc == 0)
284 {
285 result = (MYSQL_STATEMENT *)malloc(sizeof(MYSQL_STATEMENT));
fa88627b 286 result->connection = pConn;
c94bb5aa
VK
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);
140b8ada
VK
291 result->lengthFields = (unsigned long *)malloc(sizeof(unsigned long) * result->paramCount);
292 memset(result->lengthFields, 0, sizeof(unsigned long) * result->paramCount);
c94bb5aa 293 result->buffers = new Array(result->paramCount, 16, true);
de1d708f 294 *pdwError = DBERR_SUCCESS;
c94bb5aa
VK
295 }
296 else
297 {
de1d708f
VK
298 int nErr = mysql_errno(pConn->pMySQL);
299 if (nErr == CR_SERVER_LOST || nErr == CR_CONNECTION_ERROR || nErr == CR_SERVER_GONE_ERROR)
300 {
301 *pdwError = DBERR_CONNECTION_LOST;
302 }
303 else
304 {
305 *pdwError = DBERR_OTHER_ERROR;
306 }
c94bb5aa
VK
307 UpdateErrorMessage(mysql_stmt_error(stmt), errorText);
308 mysql_stmt_close(stmt);
309 }
523f1ceb 310 free(pszQueryUTF8);
c94bb5aa
VK
311 }
312 else
313 {
de1d708f 314 *pdwError = DBERR_OTHER_ERROR;
c94bb5aa
VK
315 UpdateErrorMessage("Call to mysql_stmt_init failed", errorText);
316 }
317 MutexUnlock(pConn->mutexQueryLock);
318 return result;
319}
320
7aad6641
VK
321/**
322 * Bind parameter to prepared statement
323 */
c94bb5aa
VK
324extern "C" void EXPORT DrvBind(MYSQL_STATEMENT *hStmt, int pos, int sqlType, int cType, void *buffer, int allocType)
325{
b8849590 326 static size_t bufferSize[] = { 0, sizeof(INT32), sizeof(UINT32), sizeof(INT64), sizeof(UINT64), sizeof(double), 0 };
c94bb5aa 327
fa88627b 328 if ((pos < 1) || (pos > hStmt->paramCount))
c94bb5aa
VK
329 return;
330 MYSQL_BIND *b = &hStmt->bindings[pos - 1];
331
332 if (cType == DB_CTYPE_STRING)
333 {
334 b->buffer = UTF8StringFromWideString((WCHAR *)buffer);
335 hStmt->buffers->add(b->buffer);
336 if (allocType == DB_BIND_DYNAMIC)
337 free(buffer);
ef856d02 338 b->buffer_length = (unsigned long)strlen((char *)b->buffer) + 1;
140b8ada
VK
339 hStmt->lengthFields[pos - 1] = b->buffer_length - 1;
340 b->length = &hStmt->lengthFields[pos - 1];
c94bb5aa
VK
341 b->buffer_type = MYSQL_TYPE_STRING;
342 }
b8849590
VK
343 else if (cType == DB_CTYPE_UTF8_STRING)
344 {
345 b->buffer = (allocType == DB_BIND_DYNAMIC) ? buffer : strdup((char *)buffer);
346 hStmt->buffers->add(b->buffer);
347 b->buffer_length = (unsigned long)strlen((char *)b->buffer) + 1;
348 hStmt->lengthFields[pos - 1] = b->buffer_length - 1;
349 b->length = &hStmt->lengthFields[pos - 1];
350 b->buffer_type = MYSQL_TYPE_STRING;
351 }
c94bb5aa
VK
352 else
353 {
354 switch(allocType)
355 {
356 case DB_BIND_STATIC:
357 b->buffer = buffer;
358 break;
359 case DB_BIND_DYNAMIC:
360 b->buffer = buffer;
361 hStmt->buffers->add(buffer);
362 break;
363 case DB_BIND_TRANSIENT:
364 b->buffer = nx_memdup(buffer, bufferSize[cType]);
365 hStmt->buffers->add(b->buffer);
366 break;
367 default:
368 return; // Invalid call
369 }
370
371 switch(cType)
372 {
373 case DB_CTYPE_UINT32:
750d59f2 374 b->is_unsigned = true;
f17cf019 375 /* no break */
c94bb5aa
VK
376 case DB_CTYPE_INT32:
377 b->buffer_type = MYSQL_TYPE_LONG;
378 break;
379 case DB_CTYPE_UINT64:
750d59f2 380 b->is_unsigned = true;
f17cf019 381 /* no break */
c94bb5aa
VK
382 case DB_CTYPE_INT64:
383 b->buffer_type = MYSQL_TYPE_LONGLONG;
384 break;
385 case DB_CTYPE_DOUBLE:
386 b->buffer_type = MYSQL_TYPE_DOUBLE;
387 break;
388 }
389 }
390}
391
55285a3e
VK
392/**
393 * Execute prepared statement
394 */
c94bb5aa
VK
395extern "C" DWORD EXPORT DrvExecute(MYSQL_CONN *pConn, MYSQL_STATEMENT *hStmt, WCHAR *errorText)
396{
397 DWORD dwResult;
398
c17f6cbc 399 MutexLock(pConn->mutexQueryLock);
c94bb5aa 400
140b8ada 401 if (mysql_stmt_bind_param(hStmt->statement, hStmt->bindings) == 0)
c94bb5aa
VK
402 {
403 if (mysql_stmt_execute(hStmt->statement) == 0)
404 {
405 dwResult = DBERR_SUCCESS;
406 }
407 else
408 {
409 int nErr = mysql_errno(pConn->pMySQL);
410 if (nErr == CR_SERVER_LOST || nErr == CR_CONNECTION_ERROR || nErr == CR_SERVER_GONE_ERROR)
411 {
412 dwResult = DBERR_CONNECTION_LOST;
413 }
414 else
415 {
416 dwResult = DBERR_OTHER_ERROR;
417 }
418 UpdateErrorMessage(mysql_stmt_error(hStmt->statement), errorText);
419 }
420 }
421 else
422 {
423 UpdateErrorMessage(mysql_stmt_error(hStmt->statement), errorText);
424 dwResult = DBERR_OTHER_ERROR;
425 }
426
427 MutexUnlock(pConn->mutexQueryLock);
428 return dwResult;
429}
430
7aad6641
VK
431/**
432 * Destroy prepared statement
433 */
c94bb5aa
VK
434extern "C" void EXPORT DrvFreeStatement(MYSQL_STATEMENT *hStmt)
435{
436 if (hStmt == NULL)
437 return;
438
c17f6cbc 439 MutexLock(hStmt->connection->mutexQueryLock);
c94bb5aa 440 mysql_stmt_close(hStmt->statement);
fa88627b 441 MutexUnlock(hStmt->connection->mutexQueryLock);
c94bb5aa
VK
442 delete hStmt->buffers;
443 safe_free(hStmt->bindings);
140b8ada 444 safe_free(hStmt->lengthFields);
c94bb5aa
VK
445 free(hStmt);
446}
447
7aad6641
VK
448/**
449 * Perform actual non-SELECT query
450 */
465b3f2d 451static DWORD DrvQueryInternal(MYSQL_CONN *pConn, const char *pszQuery, WCHAR *errorText)
5039dede
AK
452{
453 DWORD dwRet = DBERR_INVALID_HANDLE;
454
c17f6cbc 455 MutexLock(pConn->mutexQueryLock);
5039dede
AK
456 if (mysql_query(pConn->pMySQL, pszQuery) == 0)
457 {
458 dwRet = DBERR_SUCCESS;
459 if (errorText != NULL)
460 *errorText = 0;
461 }
462 else
463 {
464 int nErr = mysql_errno(pConn->pMySQL);
465 if (nErr == CR_SERVER_LOST || nErr == CR_CONNECTION_ERROR || nErr == CR_SERVER_GONE_ERROR) // CR_SERVER_GONE_ERROR - ???
466 {
467 dwRet = DBERR_CONNECTION_LOST;
468 }
469 else
470 {
471 dwRet = DBERR_OTHER_ERROR;
472 }
c94bb5aa 473 UpdateErrorMessage(mysql_error(pConn->pMySQL), errorText);
5039dede
AK
474 }
475
476 MutexUnlock(pConn->mutexQueryLock);
477 return dwRet;
478}
479
7aad6641
VK
480/**
481 * Perform non-SELECT query
482 */
465b3f2d 483extern "C" DWORD EXPORT DrvQuery(MYSQL_CONN *pConn, WCHAR *pwszQuery, WCHAR *errorText)
5039dede
AK
484{
485 DWORD dwRet;
486 char *pszQueryUTF8;
487
488 pszQueryUTF8 = UTF8StringFromWideString(pwszQuery);
489 dwRet = DrvQueryInternal(pConn, pszQueryUTF8, errorText);
490 free(pszQueryUTF8);
491 return dwRet;
492}
493
7aad6641
VK
494/**
495 * Perform SELECT query
496 */
465b3f2d 497extern "C" DBDRV_RESULT EXPORT DrvSelect(MYSQL_CONN *pConn, WCHAR *pwszQuery, DWORD *pdwError, WCHAR *errorText)
5039dede 498{
c94bb5aa 499 MYSQL_RESULT *result = NULL;
5039dede
AK
500 char *pszQueryUTF8;
501
502 if (pConn == NULL)
503 {
504 *pdwError = DBERR_INVALID_HANDLE;
505 return NULL;
506 }
507
508 pszQueryUTF8 = UTF8StringFromWideString(pwszQuery);
c17f6cbc 509 MutexLock(pConn->mutexQueryLock);
5039dede
AK
510 if (mysql_query(pConn->pMySQL, pszQueryUTF8) == 0)
511 {
c94bb5aa 512 result = (MYSQL_RESULT *)malloc(sizeof(MYSQL_RESULT));
fe94cc01 513 result->connection = pConn;
c94bb5aa
VK
514 result->isPreparedStatement = false;
515 result->resultSet = mysql_store_result(pConn->pMySQL);
5039dede
AK
516 *pdwError = DBERR_SUCCESS;
517 if (errorText != NULL)
518 *errorText = 0;
519 }
520 else
521 {
522 int nErr = mysql_errno(pConn->pMySQL);
523 if (nErr == CR_SERVER_LOST || nErr == CR_CONNECTION_ERROR || nErr == CR_SERVER_GONE_ERROR) // CR_SERVER_GONE_ERROR - ???
524 {
525 *pdwError = DBERR_CONNECTION_LOST;
526 }
527 else
528 {
529 *pdwError = DBERR_OTHER_ERROR;
530 }
c94bb5aa
VK
531 UpdateErrorMessage(mysql_error(pConn->pMySQL), errorText);
532 }
533
534 MutexUnlock(pConn->mutexQueryLock);
535 free(pszQueryUTF8);
536 return result;
537}
538
7aad6641
VK
539/**
540 * Perform SELECT query using prepared statement
541 */
c94bb5aa
VK
542extern "C" DBDRV_RESULT EXPORT DrvSelectPrepared(MYSQL_CONN *pConn, MYSQL_STATEMENT *hStmt, DWORD *pdwError, WCHAR *errorText)
543{
544 MYSQL_RESULT *result = NULL;
545
546 if (pConn == NULL)
547 {
548 *pdwError = DBERR_INVALID_HANDLE;
549 return NULL;
550 }
551
c17f6cbc 552 MutexLock(pConn->mutexQueryLock);
c94bb5aa 553
140b8ada 554 if (mysql_stmt_bind_param(hStmt->statement, hStmt->bindings) == 0)
c94bb5aa
VK
555 {
556 if (mysql_stmt_execute(hStmt->statement) == 0)
557 {
558 result = (MYSQL_RESULT *)malloc(sizeof(MYSQL_RESULT));
fe94cc01 559 result->connection = pConn;
c94bb5aa 560 result->isPreparedStatement = true;
fa88627b
VK
561 result->statement = hStmt->statement;
562 result->resultSet = mysql_stmt_result_metadata(hStmt->statement);
c94bb5aa
VK
563 if (result->resultSet != NULL)
564 {
fa88627b
VK
565 result->numColumns = mysql_num_fields(result->resultSet);
566
567 result->lengthFields = (unsigned long *)malloc(sizeof(unsigned long) * result->numColumns);
568 memset(result->lengthFields, 0, sizeof(unsigned long) * result->numColumns);
569
570 result->bindings = (MYSQL_BIND *)malloc(sizeof(MYSQL_BIND) * result->numColumns);
571 memset(result->bindings, 0, sizeof(MYSQL_BIND) * result->numColumns);
572 for(int i = 0; i < result->numColumns; i++)
573 {
574 result->bindings[i].buffer_type = MYSQL_TYPE_STRING;
575 result->bindings[i].length = &result->lengthFields[i];
576 }
577
578 mysql_stmt_bind_result(hStmt->statement, result->bindings);
579
580 if (mysql_stmt_store_result(hStmt->statement) == 0)
581 {
582 result->numRows = (int)mysql_stmt_num_rows(hStmt->statement);
583 result->currentRow = -1;
6e3f4556 584 *pdwError = DBERR_SUCCESS;
fa88627b
VK
585 }
586 else
587 {
588 UpdateErrorMessage(mysql_stmt_error(hStmt->statement), errorText);
589 *pdwError = DBERR_OTHER_ERROR;
590 mysql_free_result(result->resultSet);
591 free(result->bindings);
592 free(result->lengthFields);
593 free(result);
594 result = NULL;
595 }
c94bb5aa
VK
596 }
597 else
598 {
599 UpdateErrorMessage(mysql_stmt_error(hStmt->statement), errorText);
600 *pdwError = DBERR_OTHER_ERROR;
601 free(result);
602 result = NULL;
603 }
604 }
605 else
3783d300 606 {
c94bb5aa
VK
607 int nErr = mysql_errno(pConn->pMySQL);
608 if (nErr == CR_SERVER_LOST || nErr == CR_CONNECTION_ERROR || nErr == CR_SERVER_GONE_ERROR)
609 {
610 *pdwError = DBERR_CONNECTION_LOST;
611 }
612 else
613 {
614 *pdwError = DBERR_OTHER_ERROR;
615 }
616 UpdateErrorMessage(mysql_stmt_error(hStmt->statement), errorText);
3783d300 617 }
5039dede 618 }
c94bb5aa
VK
619 else
620 {
621 UpdateErrorMessage(mysql_stmt_error(hStmt->statement), errorText);
622 *pdwError = DBERR_OTHER_ERROR;
623 }
5039dede
AK
624
625 MutexUnlock(pConn->mutexQueryLock);
c94bb5aa 626 return result;
5039dede
AK
627}
628
7aad6641
VK
629/**
630 * Get field length from result
631 */
c94bb5aa 632extern "C" LONG EXPORT DrvGetFieldLength(MYSQL_RESULT *hResult, int iRow, int iColumn)
5039dede 633{
fa88627b
VK
634 if (hResult->isPreparedStatement)
635 {
636 if ((iRow < 0) || (iRow >= hResult->numRows) ||
637 (iColumn < 0) || (iColumn >= hResult->numColumns))
638 return -1;
639
640 if (hResult->currentRow != iRow)
641 {
fe94cc01 642 MutexLock(hResult->connection->mutexQueryLock);
fa88627b
VK
643 mysql_stmt_data_seek(hResult->statement, iRow);
644 mysql_stmt_fetch(hResult->statement);
b1789b80 645 hResult->currentRow = iRow;
fe94cc01 646 MutexUnlock(hResult->connection->mutexQueryLock);
fa88627b
VK
647 }
648 return (LONG)hResult->lengthFields[iColumn];
649 }
650 else
651 {
652 mysql_data_seek(hResult->resultSet, iRow);
653 MYSQL_ROW row = mysql_fetch_row(hResult->resultSet);
654 return (row == NULL) ? (LONG)-1 : ((row[iColumn] == NULL) ? -1 : (LONG)strlen(row[iColumn]));
655 }
5039dede
AK
656}
657
74d4ba34 658/**
43526096 659 * Get field value from result - UNICODE and UTF8 implementation
74d4ba34 660 */
43526096 661static void *GetFieldInternal(MYSQL_RESULT *hResult, int iRow, int iColumn, void *pBuffer, int nBufSize, bool utf8)
5039dede 662{
43526096 663 void *pRet = NULL;
5039dede 664
fa88627b 665 if (hResult->isPreparedStatement)
5039dede 666 {
fa88627b
VK
667 if ((iRow < 0) || (iRow >= hResult->numRows) ||
668 (iColumn < 0) || (iColumn >= hResult->numColumns))
669 return NULL;
670
fe94cc01 671 MutexLock(hResult->connection->mutexQueryLock);
fa88627b 672 if (hResult->currentRow != iRow)
5039dede 673 {
fa88627b
VK
674 mysql_stmt_data_seek(hResult->statement, iRow);
675 mysql_stmt_fetch(hResult->statement);
b1789b80 676 hResult->currentRow = iRow;
fa88627b
VK
677 }
678
54aa9c6f
VK
679 MYSQL_BIND b;
680 unsigned long l = 0;
681 my_bool isNull;
682
fa88627b 683 memset(&b, 0, sizeof(MYSQL_BIND));
8d4bb054 684#if HAVE_ALLOCA
c453795b 685 b.buffer = alloca(hResult->lengthFields[iColumn] + 1);
fa88627b 686#else
c453795b 687 b.buffer = malloc(hResult->lengthFields[iColumn] + 1);
fa88627b 688#endif
c453795b 689 b.buffer_length = hResult->lengthFields[iColumn] + 1;
fa88627b
VK
690 b.buffer_type = MYSQL_TYPE_STRING;
691 b.length = &l;
692 b.is_null = &isNull;
54aa9c6f
VK
693 int rc = mysql_stmt_fetch_column(hResult->statement, &b, iColumn, 0);
694 if (rc == 0)
fa88627b 695 {
54aa9c6f
VK
696 if (!isNull)
697 {
698 ((char *)b.buffer)[l] = 0;
43526096
VK
699 if (utf8)
700 {
701 strncpy((char *)pBuffer, (char *)b.buffer, nBufSize);
702 ((char *)pBuffer)[nBufSize - 1] = 0;
703 }
704 else
705 {
706 MultiByteToWideChar(CP_UTF8, 0, (char *)b.buffer, -1, (WCHAR *)pBuffer, nBufSize);
707 ((WCHAR *)pBuffer)[nBufSize - 1] = 0;
708 }
54aa9c6f
VK
709 }
710 else
711 {
43526096
VK
712 if (utf8)
713 *((char *)pBuffer) = 0;
714 else
715 *((WCHAR *)pBuffer) = 0;
54aa9c6f 716 }
5039dede
AK
717 pRet = pBuffer;
718 }
fe94cc01 719 MutexUnlock(hResult->connection->mutexQueryLock);
8d4bb054 720#if !HAVE_ALLOCA
fa88627b
VK
721 free(b.buffer);
722#endif
723 }
724 else
725 {
726 mysql_data_seek(hResult->resultSet, iRow);
727 MYSQL_ROW row = mysql_fetch_row(hResult->resultSet);
728 if (row != NULL)
729 {
730 if (row[iColumn] != NULL)
731 {
43526096
VK
732 if (utf8)
733 {
734 strncpy((char *)pBuffer, row[iColumn], nBufSize);
735 ((char *)pBuffer)[nBufSize - 1] = 0;
736 }
737 else
738 {
739 MultiByteToWideChar(CP_UTF8, 0, row[iColumn], -1, (WCHAR *)pBuffer, nBufSize);
740 ((WCHAR *)pBuffer)[nBufSize - 1] = 0;
741 }
fa88627b
VK
742 pRet = pBuffer;
743 }
744 }
5039dede
AK
745 }
746 return pRet;
747}
748
43526096
VK
749/**
750 * Get field value from result
751 */
752extern "C" WCHAR EXPORT *DrvGetField(MYSQL_RESULT *hResult, int iRow, int iColumn, WCHAR *pBuffer, int nBufSize)
753{
754 return (WCHAR *)GetFieldInternal(hResult, iRow, iColumn, pBuffer, nBufSize, false);
755}
756
757/**
758 * Get field value from result as UTF8 string
759 */
760extern "C" char EXPORT *DrvGetFieldUTF8(MYSQL_RESULT *hResult, int iRow, int iColumn, char *pBuffer, int nBufSize)
761{
762 return (char *)GetFieldInternal(hResult, iRow, iColumn, pBuffer, nBufSize, true);
763}
764
54aa9c6f
VK
765/**
766 * Get number of rows in result
767 */
c94bb5aa 768extern "C" int EXPORT DrvGetNumRows(MYSQL_RESULT *hResult)
5039dede 769{
54aa9c6f 770 return (hResult != NULL) ? (int)(hResult->isPreparedStatement ? hResult->numRows : mysql_num_rows(hResult->resultSet)) : 0;
480c7789
VK
771}
772
54aa9c6f
VK
773/**
774 * Get column count in query result
775 */
c94bb5aa 776extern "C" int EXPORT DrvGetColumnCount(MYSQL_RESULT *hResult)
480c7789 777{
c94bb5aa 778 return (hResult != NULL) ? (int)mysql_num_fields(hResult->resultSet) : 0;
480c7789
VK
779}
780
54aa9c6f
VK
781/**
782 * Get column name in query result
783 */
c94bb5aa 784extern "C" const char EXPORT *DrvGetColumnName(MYSQL_RESULT *hResult, int column)
480c7789 785{
2a8e6a7b
VK
786 MYSQL_FIELD *field;
787
788 if (hResult == NULL)
789 return NULL;
790
c94bb5aa 791 field = mysql_fetch_field_direct(hResult->resultSet, column);
2a8e6a7b 792 return (field != NULL) ? field->name : NULL;
5039dede
AK
793}
794
54aa9c6f
VK
795/**
796 * Free SELECT results
797 */
c94bb5aa 798extern "C" void EXPORT DrvFreeResult(MYSQL_RESULT *hResult)
5039dede 799{
c94bb5aa
VK
800 if (hResult == NULL)
801 return;
802
fa88627b
VK
803 if (hResult->isPreparedStatement)
804 {
805 safe_free(hResult->bindings);
806 safe_free(hResult->lengthFields);
807 }
808
c94bb5aa
VK
809 mysql_free_result(hResult->resultSet);
810 free(hResult);
5039dede
AK
811}
812
54aa9c6f 813/**
f17cf019 814 * Perform unbuffered SELECT query
54aa9c6f 815 */
f17cf019 816extern "C" DBDRV_UNBUFFERED_RESULT EXPORT DrvSelectUnbuffered(MYSQL_CONN *pConn, WCHAR *pwszQuery, DWORD *pdwError, WCHAR *errorText)
5039dede 817{
f17cf019 818 MYSQL_UNBUFFERED_RESULT *pResult = NULL;
5039dede
AK
819 char *pszQueryUTF8;
820
821 if (pConn == NULL)
822 {
823 *pdwError = DBERR_INVALID_HANDLE;
824 return NULL;
825 }
826
827 pszQueryUTF8 = UTF8StringFromWideString(pwszQuery);
c17f6cbc 828 MutexLock(pConn->mutexQueryLock);
5039dede
AK
829 if (mysql_query(pConn->pMySQL, pszQueryUTF8) == 0)
830 {
f17cf019 831 pResult = (MYSQL_UNBUFFERED_RESULT *)malloc(sizeof(MYSQL_UNBUFFERED_RESULT));
fe94cc01 832 pResult->connection = pConn;
3bca413f
VK
833 pResult->isPreparedStatement = false;
834 pResult->resultSet = mysql_use_result(pConn->pMySQL);
835 if (pResult->resultSet != NULL)
5039dede 836 {
750d59f2 837 pResult->noMoreRows = false;
3bca413f 838 pResult->numColumns = mysql_num_fields(pResult->resultSet);
5039dede 839 pResult->pCurrRow = NULL;
3bca413f
VK
840 pResult->lengthFields = (unsigned long *)malloc(sizeof(unsigned long) * pResult->numColumns);
841 pResult->bindings = NULL;
5039dede
AK
842 }
843 else
844 {
845 free(pResult);
846 pResult = NULL;
847 }
848
849 *pdwError = DBERR_SUCCESS;
850 if (errorText != NULL)
851 *errorText = 0;
852 }
853 else
854 {
855 int nErr = mysql_errno(pConn->pMySQL);
856 if (nErr == CR_SERVER_LOST || nErr == CR_CONNECTION_ERROR || nErr == CR_SERVER_GONE_ERROR) // CR_SERVER_GONE_ERROR - ???
857 {
858 *pdwError = DBERR_CONNECTION_LOST;
859 }
860 else
861 {
862 *pdwError = DBERR_OTHER_ERROR;
863 }
864
865 if (errorText != NULL)
3783d300 866 {
465b3f2d
VK
867 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mysql_error(pConn->pMySQL), -1, errorText, DBDRV_MAX_ERROR_TEXT);
868 errorText[DBDRV_MAX_ERROR_TEXT - 1] = 0;
869 RemoveTrailingCRLFW(errorText);
3783d300 870 }
5039dede
AK
871 }
872
873 if (pResult == NULL)
874 {
875 MutexUnlock(pConn->mutexQueryLock);
876 }
877 free(pszQueryUTF8);
878
879 return pResult;
880}
881
3bca413f
VK
882/**
883 * Perform unbuffered SELECT query using prepared statement
884 */
885extern "C" DBDRV_RESULT EXPORT DrvSelectPreparedUnbuffered(MYSQL_CONN *pConn, MYSQL_STATEMENT *hStmt, DWORD *pdwError, WCHAR *errorText)
886{
887 MYSQL_UNBUFFERED_RESULT *result = NULL;
888
889 MutexLock(pConn->mutexQueryLock);
890
891 if (mysql_stmt_bind_param(hStmt->statement, hStmt->bindings) == 0)
892 {
893 if (mysql_stmt_execute(hStmt->statement) == 0)
894 {
895 result = (MYSQL_UNBUFFERED_RESULT *)malloc(sizeof(MYSQL_UNBUFFERED_RESULT));
896 result->connection = pConn;
897 result->isPreparedStatement = true;
898 result->statement = hStmt->statement;
899 result->resultSet = mysql_stmt_result_metadata(hStmt->statement);
900 if (result->resultSet != NULL)
901 {
902 result->noMoreRows = false;
903 result->numColumns = mysql_num_fields(result->resultSet);
904 result->pCurrRow = NULL;
905
906 result->lengthFields = (unsigned long *)malloc(sizeof(unsigned long) * result->numColumns);
907 memset(result->lengthFields, 0, sizeof(unsigned long) * result->numColumns);
908
909 result->bindings = (MYSQL_BIND *)malloc(sizeof(MYSQL_BIND) * result->numColumns);
910 memset(result->bindings, 0, sizeof(MYSQL_BIND) * result->numColumns);
911 for(int i = 0; i < result->numColumns; i++)
912 {
913 result->bindings[i].buffer_type = MYSQL_TYPE_STRING;
914 result->bindings[i].length = &result->lengthFields[i];
915 }
916
917 mysql_stmt_bind_result(hStmt->statement, result->bindings);
918 *pdwError = DBERR_SUCCESS;
919 }
920 else
921 {
922 UpdateErrorMessage(mysql_stmt_error(hStmt->statement), errorText);
923 *pdwError = DBERR_OTHER_ERROR;
924 free(result);
925 result = NULL;
926 }
927 }
928 else
929 {
930 int nErr = mysql_errno(pConn->pMySQL);
931 if (nErr == CR_SERVER_LOST || nErr == CR_CONNECTION_ERROR || nErr == CR_SERVER_GONE_ERROR)
932 {
933 *pdwError = DBERR_CONNECTION_LOST;
934 }
935 else
936 {
937 *pdwError = DBERR_OTHER_ERROR;
938 }
939 UpdateErrorMessage(mysql_stmt_error(hStmt->statement), errorText);
940 }
941 }
942 else
943 {
944 UpdateErrorMessage(mysql_stmt_error(hStmt->statement), errorText);
945 *pdwError = DBERR_OTHER_ERROR;
946 }
947
948 if (result == NULL)
949 {
950 MutexUnlock(pConn->mutexQueryLock);
951 }
952 return result;
953}
954
fe94cc01
VK
955/**
956 * Fetch next result line from asynchronous SELECT results
957 */
3bca413f 958extern "C" bool EXPORT DrvFetch(MYSQL_UNBUFFERED_RESULT *result)
5039dede 959{
3bca413f
VK
960 if ((result == NULL) || (result->noMoreRows))
961 return false;
962
963 bool success = true;
5039dede 964
3bca413f 965 if (result->isPreparedStatement)
5039dede 966 {
3bca413f
VK
967 int rc = mysql_stmt_fetch(result->statement);
968 if ((rc != 0) && (rc != MYSQL_DATA_TRUNCATED))
969 {
970 result->noMoreRows = true;
971 success = false;
972 MutexUnlock(result->connection->mutexQueryLock);
973 }
5039dede
AK
974 }
975 else
976 {
3bca413f
VK
977 // Try to fetch next row from server
978 result->pCurrRow = mysql_fetch_row(result->resultSet);
979 if (result->pCurrRow == NULL)
980 {
981 result->noMoreRows = true;
982 success = false;
983 MutexUnlock(result->connection->mutexQueryLock);
984 }
985 else
986 {
987 unsigned long *pLen;
988
989 // Get column lengths for current row
990 pLen = mysql_fetch_lengths(result->resultSet);
991 if (pLen != NULL)
992 {
993 memcpy(result->lengthFields, pLen, sizeof(unsigned long) * result->numColumns);
994 }
995 else
996 {
997 memset(result->lengthFields, 0, sizeof(unsigned long) * result->numColumns);
998 }
999 }
5039dede 1000 }
3bca413f 1001 return success;
5039dede
AK
1002}
1003
fe94cc01
VK
1004/**
1005 * Get field length from async query result result
1006 */
f17cf019 1007extern "C" LONG EXPORT DrvGetFieldLengthUnbuffered(MYSQL_UNBUFFERED_RESULT *hResult, int iColumn)
61f032f5
VK
1008{
1009 // Check if we have valid result handle
1010 if (hResult == NULL)
1011 return 0;
1012
1013 // Check if there are valid fetched row
3bca413f 1014 if (hResult->noMoreRows || ((hResult->pCurrRow == NULL) && !hResult->isPreparedStatement))
61f032f5
VK
1015 return 0;
1016
1017 // Check if column number is valid
3bca413f 1018 if ((iColumn < 0) || (iColumn >= hResult->numColumns))
61f032f5
VK
1019 return 0;
1020
3bca413f 1021 return hResult->lengthFields[iColumn];
61f032f5
VK
1022}
1023
fe94cc01 1024/**
7f8e3ccf 1025 * Get field from current row in async query result - common implementation for wide char and UTF-8
fe94cc01 1026 */
7f8e3ccf 1027static void *GetFieldUnbufferedInternal(MYSQL_UNBUFFERED_RESULT *hResult, int iColumn, void *pBuffer, int iBufSize, bool utf8)
5039dede 1028{
7f8e3ccf
VK
1029 // Check if we have valid result handle
1030 if (hResult == NULL)
1031 return NULL;
1032
1033 // Check if there are valid fetched row
1034 if ((hResult->noMoreRows) || ((hResult->pCurrRow == NULL) && !hResult->isPreparedStatement))
1035 return NULL;
1036
1037 // Check if column number is valid
1038 if ((iColumn < 0) || (iColumn >= hResult->numColumns))
1039 return NULL;
1040
1041 // Now get column data
1042 void *value = NULL;
1043 if (hResult->isPreparedStatement)
1044 {
3bca413f
VK
1045 MYSQL_BIND b;
1046 unsigned long l = 0;
1047 my_bool isNull;
1048
1049 memset(&b, 0, sizeof(MYSQL_BIND));
1050#if HAVE_ALLOCA
1051 b.buffer = alloca(hResult->lengthFields[iColumn] + 1);
1052#else
1053 b.buffer = malloc(hResult->lengthFields[iColumn] + 1);
1054#endif
1055 b.buffer_length = hResult->lengthFields[iColumn] + 1;
1056 b.buffer_type = MYSQL_TYPE_STRING;
1057 b.length = &l;
1058 b.is_null = &isNull;
1059 int rc = mysql_stmt_fetch_column(hResult->statement, &b, iColumn, 0);
1060 if (rc == 0)
1061 {
1062 if (!isNull)
1063 {
1064 ((char *)b.buffer)[l] = 0;
7f8e3ccf
VK
1065 if (utf8)
1066 {
1067 strncpy((char *)pBuffer, (char *)b.buffer, iBufSize);
1068 ((char *)pBuffer)[iBufSize - 1] = 0;
1069 }
1070 else
1071 {
1072 MultiByteToWideChar(CP_UTF8, 0, (char *)b.buffer, -1, (WCHAR *)pBuffer, iBufSize);
1073 ((WCHAR *)pBuffer)[iBufSize - 1] = 0;
1074 }
3bca413f
VK
1075 }
1076 else
1077 {
7f8e3ccf
VK
1078 if (utf8)
1079 *((char *)pBuffer) = 0;
1080 else
1081 *((WCHAR *)pBuffer) = 0;
3bca413f
VK
1082 }
1083 value = pBuffer;
1084 }
1085#if !HAVE_ALLOCA
1086 free(b.buffer);
1087#endif
7f8e3ccf
VK
1088 }
1089 else
1090 {
3bca413f
VK
1091 int iLen = min((int)hResult->lengthFields[iColumn], iBufSize - 1);
1092 if (iLen > 0)
1093 {
7f8e3ccf
VK
1094 if (utf8)
1095 {
1096 memcpy(pBuffer, hResult->pCurrRow[iColumn], iLen);
1097 ((char *)pBuffer)[iLen] = 0;
1098 }
1099 else
1100 {
1101 MultiByteToWideChar(CP_UTF8, 0, hResult->pCurrRow[iColumn], iLen, (WCHAR *)pBuffer, iBufSize);
1102 ((WCHAR *)pBuffer)[iLen] = 0;
1103 }
1104 }
1105 else
1106 {
1107 if (utf8)
1108 *((char *)pBuffer) = 0;
1109 else
1110 *((WCHAR *)pBuffer) = 0;
3bca413f 1111 }
3bca413f 1112 value = pBuffer;
7f8e3ccf
VK
1113 }
1114 return value;
1115}
1116
1117/**
1118 * Get field from current row in async query result
1119 */
1120extern "C" WCHAR EXPORT *DrvGetFieldUnbuffered(MYSQL_UNBUFFERED_RESULT *hResult, int iColumn, WCHAR *pBuffer, int iBufSize)
1121{
1122 return (WCHAR *)GetFieldUnbufferedInternal(hResult, iColumn, pBuffer, iBufSize, false);
1123}
1124
1125/**
1126 * Get field from current row in async query result
1127 */
1128extern "C" char EXPORT *DrvGetFieldUnbufferedUTF8(MYSQL_UNBUFFERED_RESULT *hResult, int iColumn, char *pBuffer, int iBufSize)
1129{
1130 return (char *)GetFieldUnbufferedInternal(hResult, iColumn, pBuffer, iBufSize, true);
5039dede
AK
1131}
1132
fe94cc01
VK
1133/**
1134 * Get column count in async query result
1135 */
f17cf019 1136extern "C" int EXPORT DrvGetColumnCountUnbuffered(MYSQL_UNBUFFERED_RESULT *hResult)
480c7789 1137{
3bca413f 1138 return (hResult != NULL) ? hResult->numColumns : 0;
480c7789
VK
1139}
1140
fe94cc01
VK
1141/**
1142 * Get column name in async query result
1143 */
f17cf019 1144extern "C" const char EXPORT *DrvGetColumnNameUnbuffered(MYSQL_UNBUFFERED_RESULT *hResult, int column)
480c7789 1145{
2a8e6a7b
VK
1146 MYSQL_FIELD *field;
1147
3bca413f 1148 if ((hResult == NULL) || (hResult->resultSet == NULL))
2a8e6a7b
VK
1149 return NULL;
1150
3bca413f 1151 field = mysql_fetch_field_direct(hResult->resultSet, column);
2a8e6a7b 1152 return (field != NULL) ? field->name : NULL;
480c7789
VK
1153}
1154
fe94cc01
VK
1155/**
1156 * Destroy result of async query
1157 */
f17cf019 1158extern "C" void EXPORT DrvFreeUnbufferedResult(MYSQL_UNBUFFERED_RESULT *hResult)
5039dede 1159{
3bca413f
VK
1160 if (hResult == NULL)
1161 return;
1162
1163 // Check if all result rows fetched
1164 if (!hResult->noMoreRows)
1165 {
1166 // Fetch remaining rows
1167 if (!hResult->isPreparedStatement)
1168 {
1169 while(mysql_fetch_row(hResult->resultSet) != NULL);
1170 }
1171
1172 // Now we are ready for next query, so unlock query mutex
1173 MutexUnlock(hResult->connection->mutexQueryLock);
1174 }
1175
1176 // Free allocated memory
1177 mysql_free_result(hResult->resultSet);
1178 free(hResult->lengthFields);
1179 free(hResult->bindings);
1180 free(hResult);
5039dede
AK
1181}
1182
fe94cc01
VK
1183/**
1184 * Begin transaction
1185 */
5039dede
AK
1186extern "C" DWORD EXPORT DrvBegin(MYSQL_CONN *pConn)
1187{
1188 return DrvQueryInternal(pConn, "BEGIN", NULL);
1189}
1190
fe94cc01
VK
1191/**
1192 * Commit transaction
1193 */
5039dede
AK
1194extern "C" DWORD EXPORT DrvCommit(MYSQL_CONN *pConn)
1195{
1196 return DrvQueryInternal(pConn, "COMMIT", NULL);
1197}
1198
fe94cc01
VK
1199/**
1200 * Rollback transaction
1201 */
5039dede
AK
1202extern "C" DWORD EXPORT DrvRollback(MYSQL_CONN *pConn)
1203{
1204 return DrvQueryInternal(pConn, "ROLLBACK", NULL);
1205}
1206
b4805ef1
VK
1207/**
1208 * Check if table exist
1209 */
1210extern "C" int EXPORT DrvIsTableExist(MYSQL_CONN *pConn, const WCHAR *name)
1211{
1212 WCHAR query[256], lname[256];
1213 wcsncpy(lname, name, 256);
1214 wcslwr(lname);
fdf1ed50 1215 swprintf(query, 256, L"SHOW TABLES LIKE '%ls'", lname);
b4805ef1
VK
1216 DWORD error;
1217 WCHAR errorText[DBDRV_MAX_ERROR_TEXT];
1218 int rc = DBIsTableExist_Failure;
1219 MYSQL_RESULT *hResult = (MYSQL_RESULT *)DrvSelect(pConn, query, &error, errorText);
1220 if (hResult != NULL)
1221 {
1222 rc = (DrvGetNumRows(hResult) > 0) ? DBIsTableExist_Found : DBIsTableExist_NotFound;
1223 DrvFreeResult(hResult);
1224 }
1225 return rc;
1226}
1227
5039dede
AK
1228#ifdef _WIN32
1229
fe94cc01
VK
1230/**
1231 * DLL Entry point
1232 */
750d59f2 1233bool WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
5039dede
AK
1234{
1235 if (dwReason == DLL_PROCESS_ATTACH)
1236 DisableThreadLibraryCalls(hInstance);
750d59f2 1237 return true;
5039dede
AK
1238}
1239
1240#endif