1 /********************************************************************/
2 /* */
3 /* sql_my.c Database access functions for MariaDB and MySQL. */
4 /* Copyright (C) 1989 - 2020 Thomas Mertes */
5 /* */
6 /* This file is part of the Seed7 Runtime Library. */
7 /* */
8 /* The Seed7 Runtime Library is free software; you can */
9 /* redistribute it and/or modify it under the terms of the GNU */
10 /* Lesser General Public License as published by the Free Software */
11 /* Foundation; either version 2.1 of the License, or (at your */
12 /* option) any later version. */
13 /* */
14 /* The Seed7 Runtime Library is distributed in the hope that it */
15 /* will be useful, but WITHOUT ANY WARRANTY; without even the */
16 /* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */
17 /* PURPOSE. See the GNU Lesser General Public License for more */
18 /* details. */
19 /* */
20 /* You should have received a copy of the GNU Lesser General */
21 /* Public License along with this program; if not, write to the */
22 /* Free Software Foundation, Inc., 51 Franklin Street, */
23 /* Fifth Floor, Boston, MA 02110-1301, USA. */
24 /* */
25 /* Module: Seed7 Runtime Library */
26 /* File: seed7/src/sql_my.c */
27 /* Changes: 2014, 2015, 2017 - 2020 Thomas Mertes */
28 /* Content: Database access functions for MariaDB and MySQL. */
29 /* */
30 /********************************************************************/
31
32 #define LOG_FUNCTIONS 0
33 #define VERBOSE_EXCEPTIONS 0
34
35 #include "version.h"
36
37 #include "stdlib.h"
38 #include "stdio.h"
39 #include "string.h"
40 #include "time.h"
41 #include "limits.h"
42 #ifdef MYSQL_INCLUDE
43 #include MYSQL_INCLUDE
44 #endif
45
46 #include "common.h"
47 #include "data_rtl.h"
48 #include "striutl.h"
49 #include "heaputl.h"
50 #include "numutl.h"
51 #include "str_rtl.h"
52 #include "int_rtl.h"
53 #include "flt_rtl.h"
54 #include "tim_rtl.h"
55 #include "big_drv.h"
56 #include "rtl_err.h"
57 #include "dll_drv.h"
58 #include "sql_base.h"
59 #include "sql_drv.h"
60
61 #ifdef MYSQL_INCLUDE
62
63
64 typedef struct {
65 uintType usage_count;
66 sqlFuncType sqlFunc;
67 intType driver;
68 MYSQL *connection;
69 boolType autoCommit;
70 boolType backslashEscapes;
71 } dbRecord, *dbType;
72
73 typedef struct {
74 memSizeType buffer_capacity;
75 boolType bound;
76 } bindDataRecord, *bindDataType;
77
78 typedef struct {
79 char *name;
80 boolType binary;
81 } resultDataRecord, *resultDataType;
82
83 typedef struct {
84 uintType usage_count;
85 sqlFuncType sqlFunc;
86 MYSQL_STMT *ppStmt;
87 memSizeType param_array_size;
88 MYSQL_BIND *param_array;
89 bindDataType param_data_array;
90 memSizeType result_array_size;
91 MYSQL_BIND *result_array;
92 resultDataType result_data_array;
93 boolType executeSuccessful;
94 boolType fetchOkay;
95 boolType fetchFinished;
96 } preparedStmtRecord, *preparedStmtType;
97
98 static sqlFuncType sqlFunc = NULL;
99
100 #define DEFAULT_PORT 3306
101 #define MAX_DECIMAL_PRECISION 65
102 #define MAX_DECIMAL_SCALE 30
103 /* The maximum decimal length additionally needs place for a */
104 /* decimal point, a sign and a possible leading or trailing zero. */
105 #define MAX_DECIMAL_LENGTH (MAX_DECIMAL_PRECISION + 3)
106 #define MOST_POSITIVE_FLOAT 3.4028234663852885e+38
107 #define MOST_NEGATIVE_FLOAT -3.4028234663852885e+38
108 #define MOST_POSITIVE_DOUBLE 1.7976931348623157e+308
109 #define MOST_NEGATIVE_DOUBLE -1.7976931348623157e+308
110 #define MAX_TINY_BLOB_LENGTH 255 /* 2 ** 8 - 1 chars */
111 #define MAX_BLOB_LENGTH 65535 /* 2 ** 16 - 1 chars */
112 #define MAX_MEDIUM_BLOB_LENGTH 16777215 /* 2 ** 24 - 1 chars */
113 #define MAX_LONG_BLOB_LENGTH UINT32_SUFFIX(4294967295) /* 2 ** 32 - 1 chars */
114
115
116 #ifdef MYSQL_DLL
117
118 #ifndef STDCALL
119 #if defined(_WIN32) && HAS_STDCALL
120 #define STDCALL __stdcall
121 #else
122 #define STDCALL
123 #endif
124 #endif
125
126 typedef my_bool (STDCALL *tp_mysql_autocommit) (MYSQL *mysql, my_bool mode);
127 typedef void (STDCALL *tp_mysql_close) (MYSQL *sock);
128 typedef my_bool (STDCALL *tp_mysql_commit) (MYSQL *mysql);
129 typedef unsigned int (STDCALL *tp_mysql_errno) (MYSQL *mysql);
130 typedef const char *(STDCALL *tp_mysql_error) (MYSQL *mysql);
131 typedef MYSQL_FIELD *(STDCALL *tp_mysql_fetch_field_direct) (MYSQL_RES *res,
132 unsigned int fieldnr);
133 typedef void (STDCALL *tp_mysql_free_result) (MYSQL_RES *result);
134 typedef MYSQL *(STDCALL *tp_mysql_init) (MYSQL *mysql);
135 typedef unsigned int (STDCALL *tp_mysql_num_fields) (MYSQL_RES *res);
136 typedef int (STDCALL *tp_mysql_options) (MYSQL *mysql,
137 enum mysql_option option,
138 const void *arg);
139 typedef MYSQL *(STDCALL *tp_mysql_real_connect) (MYSQL *mysql,
140 const char *host,
141 const char *user,
142 const char *passwd,
143 const char *db,
144 unsigned int port,
145 const char *unix_socket,
146 unsigned long clientflag);
147 typedef my_bool (STDCALL *tp_mysql_rollback) (MYSQL *mysql);
148 typedef int (STDCALL *tp_mysql_set_character_set) (MYSQL *mysql,
149 const char *csname);
150 typedef my_bool (STDCALL *tp_mysql_stmt_bind_param) (MYSQL_STMT *stmt,
151 MYSQL_BIND *bnd);
152 typedef my_bool (STDCALL *tp_mysql_stmt_bind_result) (MYSQL_STMT *stmt,
153 MYSQL_BIND *bnd);
154 typedef my_bool (STDCALL *tp_mysql_stmt_close) (MYSQL_STMT *stmt);
155 typedef unsigned int (STDCALL *tp_mysql_stmt_errno) (MYSQL_STMT *stmt);
156 typedef const char *(STDCALL *tp_mysql_stmt_error) (MYSQL_STMT *stmt);
157 typedef int (STDCALL *tp_mysql_stmt_execute) (MYSQL_STMT *stmt);
158 typedef int (STDCALL *tp_mysql_stmt_fetch) (MYSQL_STMT *stmt);
159 typedef int (STDCALL *tp_mysql_stmt_fetch_column) (MYSQL_STMT *stmt,
160 MYSQL_BIND *bnd,
161 unsigned int column,
162 unsigned long offset);
163 typedef MYSQL_STMT *(STDCALL *tp_mysql_stmt_init) (MYSQL *mysql);
164 typedef unsigned long (STDCALL *tp_mysql_stmt_param_count) (MYSQL_STMT *stmt);
165 typedef int (STDCALL *tp_mysql_stmt_prepare) (MYSQL_STMT *stmt,
166 const char *query,
167 unsigned long length);
168 typedef MYSQL_RES *(STDCALL *tp_mysql_stmt_result_metadata) (MYSQL_STMT *stmt);
169 typedef int *(STDCALL *tp_mysql_stmt_store_result) (MYSQL_STMT *stmt);
170
171 static tp_mysql_autocommit ptr_mysql_autocommit;
172 static tp_mysql_close ptr_mysql_close;
173 static tp_mysql_commit ptr_mysql_commit;
174 static tp_mysql_errno ptr_mysql_errno;
175 static tp_mysql_error ptr_mysql_error;
176 static tp_mysql_fetch_field_direct ptr_mysql_fetch_field_direct;
177 static tp_mysql_free_result ptr_mysql_free_result;
178 static tp_mysql_init ptr_mysql_init;
179 static tp_mysql_num_fields ptr_mysql_num_fields;
180 static tp_mysql_options ptr_mysql_options;
181 static tp_mysql_real_connect ptr_mysql_real_connect;
182 static tp_mysql_rollback ptr_mysql_rollback;
183 static tp_mysql_set_character_set ptr_mysql_set_character_set;
184 static tp_mysql_stmt_bind_param ptr_mysql_stmt_bind_param;
185 static tp_mysql_stmt_bind_result ptr_mysql_stmt_bind_result;
186 static tp_mysql_stmt_close ptr_mysql_stmt_close;
187 static tp_mysql_stmt_errno ptr_mysql_stmt_errno;
188 static tp_mysql_stmt_error ptr_mysql_stmt_error;
189 static tp_mysql_stmt_execute ptr_mysql_stmt_execute;
190 static tp_mysql_stmt_fetch ptr_mysql_stmt_fetch;
191 static tp_mysql_stmt_fetch_column ptr_mysql_stmt_fetch_column;
192 static tp_mysql_stmt_init ptr_mysql_stmt_init;
193 static tp_mysql_stmt_param_count ptr_mysql_stmt_param_count;
194 static tp_mysql_stmt_prepare ptr_mysql_stmt_prepare;
195 static tp_mysql_stmt_result_metadata ptr_mysql_stmt_result_metadata;
196 static tp_mysql_stmt_store_result ptr_mysql_stmt_store_result;
197
198 #define mysql_autocommit ptr_mysql_autocommit
199 #define mysql_close ptr_mysql_close
200 #define mysql_commit ptr_mysql_commit
201 #define mysql_errno ptr_mysql_errno
202 #define mysql_error ptr_mysql_error
203 #define mysql_fetch_field_direct ptr_mysql_fetch_field_direct
204 #define mysql_free_result ptr_mysql_free_result
205 #define mysql_init ptr_mysql_init
206 #define mysql_num_fields ptr_mysql_num_fields
207 #define mysql_options ptr_mysql_options
208 #define mysql_real_connect ptr_mysql_real_connect
209 #define mysql_rollback ptr_mysql_rollback
210 #define mysql_set_character_set ptr_mysql_set_character_set
211 #define mysql_stmt_bind_param ptr_mysql_stmt_bind_param
212 #define mysql_stmt_bind_result ptr_mysql_stmt_bind_result
213 #define mysql_stmt_close ptr_mysql_stmt_close
214 #define mysql_stmt_errno ptr_mysql_stmt_errno
215 #define mysql_stmt_error ptr_mysql_stmt_error
216 #define mysql_stmt_execute ptr_mysql_stmt_execute
217 #define mysql_stmt_fetch ptr_mysql_stmt_fetch
218 #define mysql_stmt_fetch_column ptr_mysql_stmt_fetch_column
219 #define mysql_stmt_init ptr_mysql_stmt_init
220 #define mysql_stmt_param_count ptr_mysql_stmt_param_count
221 #define mysql_stmt_prepare ptr_mysql_stmt_prepare
222 #define mysql_stmt_result_metadata ptr_mysql_stmt_result_metadata
223 #define mysql_stmt_store_result ptr_mysql_stmt_store_result
224
225
226
setupDll(const char * dllName)227 static boolType setupDll (const char *dllName)
228
229 {
230 static void *dbDll = NULL;
231
232 /* setupDll */
233 logFunction(printf("setupDll(\"%s\")\n", dllName););
234 if (dbDll == NULL) {
235 dbDll = dllOpen(dllName);
236 if (dbDll != NULL) {
237 if ((mysql_autocommit = (tp_mysql_autocommit) dllFunc(dbDll, "mysql_autocommit")) == NULL ||
238 (mysql_close = (tp_mysql_close) dllFunc(dbDll, "mysql_close")) == NULL ||
239 (mysql_commit = (tp_mysql_commit) dllFunc(dbDll, "mysql_commit")) == NULL ||
240 (mysql_errno = (tp_mysql_errno) dllFunc(dbDll, "mysql_errno")) == NULL ||
241 (mysql_error = (tp_mysql_error) dllFunc(dbDll, "mysql_error")) == NULL ||
242 (mysql_fetch_field_direct = (tp_mysql_fetch_field_direct) dllFunc(dbDll, "mysql_fetch_field_direct")) == NULL ||
243 (mysql_free_result = (tp_mysql_free_result) dllFunc(dbDll, "mysql_free_result")) == NULL ||
244 (mysql_init = (tp_mysql_init) dllFunc(dbDll, "mysql_init")) == NULL ||
245 (mysql_num_fields = (tp_mysql_num_fields) dllFunc(dbDll, "mysql_num_fields")) == NULL ||
246 (mysql_options = (tp_mysql_options) dllFunc(dbDll, "mysql_options")) == NULL ||
247 (mysql_real_connect = (tp_mysql_real_connect) dllFunc(dbDll, "mysql_real_connect")) == NULL ||
248 (mysql_rollback = (tp_mysql_rollback) dllFunc(dbDll, "mysql_rollback")) == NULL ||
249 (mysql_set_character_set = (tp_mysql_set_character_set) dllFunc(dbDll, "mysql_set_character_set")) == NULL ||
250 (mysql_stmt_bind_param = (tp_mysql_stmt_bind_param) dllFunc(dbDll, "mysql_stmt_bind_param")) == NULL ||
251 (mysql_stmt_bind_result = (tp_mysql_stmt_bind_result) dllFunc(dbDll, "mysql_stmt_bind_result")) == NULL ||
252 (mysql_stmt_close = (tp_mysql_stmt_close) dllFunc(dbDll, "mysql_stmt_close")) == NULL ||
253 (mysql_stmt_errno = (tp_mysql_stmt_errno) dllFunc(dbDll, "mysql_stmt_errno")) == NULL ||
254 (mysql_stmt_error = (tp_mysql_stmt_error) dllFunc(dbDll, "mysql_stmt_error")) == NULL ||
255 (mysql_stmt_execute = (tp_mysql_stmt_execute) dllFunc(dbDll, "mysql_stmt_execute")) == NULL ||
256 (mysql_stmt_fetch = (tp_mysql_stmt_fetch) dllFunc(dbDll, "mysql_stmt_fetch")) == NULL ||
257 (mysql_stmt_fetch_column = (tp_mysql_stmt_fetch_column) dllFunc(dbDll, "mysql_stmt_fetch_column")) == NULL ||
258 (mysql_stmt_init = (tp_mysql_stmt_init) dllFunc(dbDll, "mysql_stmt_init")) == NULL ||
259 (mysql_stmt_param_count = (tp_mysql_stmt_param_count) dllFunc(dbDll, "mysql_stmt_param_count")) == NULL ||
260 (mysql_stmt_prepare = (tp_mysql_stmt_prepare) dllFunc(dbDll, "mysql_stmt_prepare")) == NULL ||
261 (mysql_stmt_result_metadata = (tp_mysql_stmt_result_metadata) dllFunc(dbDll, "mysql_stmt_result_metadata")) == NULL ||
262 (mysql_stmt_store_result = (tp_mysql_stmt_store_result) dllFunc(dbDll, "mysql_stmt_store_result")) == NULL) {
263 dbDll = NULL;
264 } /* if */
265 } /* if */
266 } /* if */
267 logFunction(printf("setupDll --> %d\n", dbDll != NULL););
268 return dbDll != NULL;
269 } /* setupDll */
270
271
272
findDll(void)273 static boolType findDll (void)
274
275 {
276 const char *dllList[] = { MYSQL_DLL };
277 unsigned int pos;
278 boolType found = FALSE;
279
280 /* findDll */
281 for (pos = 0; pos < sizeof(dllList) / sizeof(char *) && !found; pos++) {
282 found = setupDll(dllList[pos]);
283 } /* for */
284 if (!found) {
285 dllErrorMessage("sqlOpenMy", "findDll", dllList,
286 sizeof(dllList) / sizeof(char *));
287 } /* if */
288 return found;
289 } /* findDll */
290
291 #else
292
293 #define findDll() TRUE
294
295 #endif
296
297
298
299 static void sqlClose (databaseType database);
300
301
302
setDbErrorMsg(const char * funcName,const char * dbFuncName,unsigned int my_errno,const char * my_error)303 static void setDbErrorMsg (const char *funcName, const char *dbFuncName,
304 unsigned int my_errno, const char *my_error)
305
306 { /* setDbErrorMsg */
307 dbError.funcName = funcName;
308 dbError.dbFuncName = dbFuncName;
309 dbError.errorCode = my_errno;
310 snprintf(dbError.message, DB_ERR_MESSAGE_SIZE, "%s", my_error);
311 } /* setDbErrorMsg */
312
313
314
315 /**
316 * Closes a database and frees the memory used by it.
317 */
freeDatabase(databaseType database)318 static void freeDatabase (databaseType database)
319
320 {
321 dbType db;
322
323 /* freeDatabase */
324 logFunction(printf("freeDatabase(" FMT_U_MEM ")\n",
325 (memSizeType) database););
326 sqlClose(database);
327 db = (dbType) database;
328 FREE_RECORD2(db, dbRecord, count.database, count.database_bytes);
329 logFunction(printf("freeDatabase -->\n"););
330 } /* freeDatabase */
331
332
333
334 /**
335 * Closes a prepared statement and frees the memory used by it.
336 */
freePreparedStmt(sqlStmtType sqlStatement)337 static void freePreparedStmt (sqlStmtType sqlStatement)
338
339 {
340 preparedStmtType preparedStmt;
341 memSizeType pos;
342
343 /* freePreparedStmt */
344 logFunction(printf("freePreparedStmt(" FMT_U_MEM ")\n",
345 (memSizeType) sqlStatement););
346 preparedStmt = (preparedStmtType) sqlStatement;
347 if (preparedStmt->param_array != NULL) {
348 for (pos = 0; pos < preparedStmt->param_array_size; pos++) {
349 free(preparedStmt->param_array[pos].buffer);
350 } /* for */
351 FREE_TABLE(preparedStmt->param_array, MYSQL_BIND, preparedStmt->param_array_size);
352 FREE_TABLE(preparedStmt->param_data_array, bindDataRecord, preparedStmt->param_array_size);
353 } /* if */
354 if (preparedStmt->result_array != NULL) {
355 for (pos = 0; pos < preparedStmt->result_array_size; pos++) {
356 free(preparedStmt->result_array[pos].buffer);
357 } /* for */
358 FREE_TABLE(preparedStmt->result_array, MYSQL_BIND, preparedStmt->result_array_size);
359 } /* if */
360 if (preparedStmt->result_data_array != NULL) {
361 FREE_TABLE(preparedStmt->result_data_array, resultDataRecord, preparedStmt->result_array_size);
362 } /* if */
363 mysql_stmt_close(preparedStmt->ppStmt);
364 FREE_RECORD2(preparedStmt, preparedStmtRecord,
365 count.prepared_stmt, count.prepared_stmt_bytes);
366 logFunction(printf("freePreparedStmt -->\n"););
367 } /* freePreparedStmt */
368
369
370
371 #if LOG_FUNCTIONS_EVERYWHERE || LOG_FUNCTIONS || VERBOSE_EXCEPTIONS_EVERYWHERE || VERBOSE_EXCEPTIONS
nameOfBufferType(int buffer_type)372 static const char *nameOfBufferType (int buffer_type)
373
374 {
375 static char buffer[50];
376 const char *typeName;
377
378 /* nameOfBufferType */
379 logFunction(printf("nameOfBufferType(%d)\n", buffer_type););
380 switch (buffer_type) {
381 case MYSQL_TYPE_TINY: typeName = "MYSQL_TYPE_TINY"; break;
382 case MYSQL_TYPE_SHORT: typeName = "MYSQL_TYPE_SHORT"; break;
383 case MYSQL_TYPE_INT24: typeName = "MYSQL_TYPE_INT24"; break;
384 case MYSQL_TYPE_LONG: typeName = "MYSQL_TYPE_LONG"; break;
385 case MYSQL_TYPE_LONGLONG: typeName = "MYSQL_TYPE_LONGLONG"; break;
386 case MYSQL_TYPE_FLOAT: typeName = "MYSQL_TYPE_FLOAT"; break;
387 case MYSQL_TYPE_DOUBLE: typeName = "MYSQL_TYPE_DOUBLE"; break;
388 case MYSQL_TYPE_DECIMAL: typeName = "MYSQL_TYPE_DECIMAL"; break;
389 case MYSQL_TYPE_NEWDECIMAL: typeName = "MYSQL_TYPE_NEWDECIMAL"; break;
390 case MYSQL_TYPE_TIME: typeName = "MYSQL_TYPE_TIME"; break;
391 case MYSQL_TYPE_DATE: typeName = "MYSQL_TYPE_DATE"; break;
392 case MYSQL_TYPE_NEWDATE: typeName = "MYSQL_TYPE_NEWDATE"; break;
393 case MYSQL_TYPE_DATETIME: typeName = "MYSQL_TYPE_DATETIME"; break;
394 case MYSQL_TYPE_TIMESTAMP: typeName = "MYSQL_TYPE_TIMESTAMP"; break;
395 case MYSQL_TYPE_VARCHAR: typeName = "MYSQL_TYPE_VARCHAR"; break;
396 case MYSQL_TYPE_STRING: typeName = "MYSQL_TYPE_STRING"; break;
397 case MYSQL_TYPE_VAR_STRING: typeName = "MYSQL_TYPE_VAR_STRING"; break;
398 case MYSQL_TYPE_TINY_BLOB: typeName = "MYSQL_TYPE_TINY_BLOB"; break;
399 case MYSQL_TYPE_BLOB: typeName = "MYSQL_TYPE_BLOB"; break;
400 case MYSQL_TYPE_MEDIUM_BLOB: typeName = "MYSQL_TYPE_MEDIUM_BLOB"; break;
401 case MYSQL_TYPE_LONG_BLOB: typeName = "MYSQL_TYPE_LONG_BLOB"; break;
402 case MYSQL_TYPE_BIT: typeName = "MYSQL_TYPE_BIT"; break;
403 case MYSQL_TYPE_YEAR: typeName = "MYSQL_TYPE_YEAR"; break;
404 case MYSQL_TYPE_SET: typeName = "MYSQL_TYPE_SET"; break;
405 case MYSQL_TYPE_ENUM: typeName = "MYSQL_TYPE_ENUM"; break;
406 case MYSQL_TYPE_GEOMETRY: typeName = "MYSQL_TYPE_GEOMETRY"; break;
407 case MYSQL_TYPE_NULL: typeName = "MYSQL_TYPE_NULL"; break;
408 default:
409 sprintf(buffer, "%d", buffer_type);
410 typeName = buffer;
411 break;
412 } /* switch */
413 logFunction(printf("nameOfBufferType --> %s\n", typeName););
414 return typeName;
415 } /* nameOfBufferType */
416 #endif
417
418
419
420 /**
421 * Process strings delimited by single quotes (') and double quotes (").
422 * Depending on the parameter backslashEscapes backslashes (\) are
423 * replaced with double backslashes (\\) in strings, that are delimited
424 * by single quotes ('). This way a backslash in a SQL statement has no
425 * special meaning (like it is common practice in other SQL databases).
426 * Strings delimited with double quotes (") are converted into
427 * strings, that are delimited with a backtick (`). This way
428 * identifiers in a SQL statement can be enclosed in double
429 * quotes (") (like it is common proctice in other SQL databases).
430 * The function processes (and removes) also comments, to avoid that
431 * a quote (') inside a comment is misinterpreted as literal.
432 * This processing does not prohibit any form of SQL injection.
433 * It is strongly recommended that string literals in SQL statements
434 * are constant and never be constructed with data from outside.
435 */
processStatementStri(const const_striType sqlStatementStri,boolType backslashEscapes)436 static striType processStatementStri (const const_striType sqlStatementStri,
437 boolType backslashEscapes)
438
439 {
440 memSizeType pos = 0;
441 strElemType ch;
442 memSizeType destPos = 0;
443 striType processed;
444
445 /* processStatementStri */
446 logFunction(printf("processStatementStri(\"%s\", %d)\n",
447 striAsUnquotedCStri(sqlStatementStri), backslashEscapes););
448 if (unlikely(sqlStatementStri->size > MAX_STRI_LEN / 2 ||
449 !ALLOC_STRI_SIZE_OK(processed, sqlStatementStri->size * 2))) {
450 processed = NULL;
451 } else {
452 while (pos < sqlStatementStri->size) {
453 ch = sqlStatementStri->mem[pos];
454 if (ch == '\'') {
455 processed->mem[destPos++] = '\'';
456 pos++;
457 while (pos < sqlStatementStri->size &&
458 (ch = sqlStatementStri->mem[pos]) != '\'') {
459 if (ch == '\\' && backslashEscapes) {
460 processed->mem[destPos++] = ch;
461 } /* if */
462 processed->mem[destPos++] = ch;
463 pos++;
464 } /* while */
465 if (pos < sqlStatementStri->size) {
466 processed->mem[destPos++] = '\'';
467 pos++;
468 } /* if */
469 } else if (ch == '"') {
470 processed->mem[destPos++] = '`';
471 pos++;
472 do {
473 while (pos < sqlStatementStri->size &&
474 (ch = sqlStatementStri->mem[pos]) != '"') {
475 if (ch == '`') {
476 processed->mem[destPos++] = ch;
477 } /* if */
478 processed->mem[destPos++] = ch;
479 pos++;
480 } /* while */
481 if (pos < sqlStatementStri->size) {
482 pos++;
483 if (pos < sqlStatementStri->size &&
484 (ch = sqlStatementStri->mem[pos]) == '"') {
485 processed->mem[destPos++] = '"';
486 pos++;
487 } /* if */
488 } /* if */
489 } while (pos < sqlStatementStri->size && ch == '"');
490 if (pos < sqlStatementStri->size) {
491 processed->mem[destPos++] = '`';
492 } /* if */
493 } else if (ch == '`') {
494 processed->mem[destPos++] = '`';
495 pos++;
496 while (pos < sqlStatementStri->size &&
497 (ch = sqlStatementStri->mem[pos]) != '`') {
498 processed->mem[destPos++] = ch;
499 pos++;
500 } /* while */
501 if (pos < sqlStatementStri->size) {
502 processed->mem[destPos++] = '`';
503 pos++;
504 } /* if */
505 } else if (ch == '/') {
506 pos++;
507 if (pos >= sqlStatementStri->size || sqlStatementStri->mem[pos] != '*') {
508 processed->mem[destPos++] = ch;
509 } else {
510 pos++;
511 do {
512 while (pos < sqlStatementStri->size && sqlStatementStri->mem[pos] != '*') {
513 pos++;
514 } /* while */
515 pos++;
516 } while (pos < sqlStatementStri->size && sqlStatementStri->mem[pos] != '/');
517 pos++;
518 /* Replace the comment with a space. */
519 processed->mem[destPos++] = ' ';
520 } /* if */
521 } else if (ch == '-') {
522 pos++;
523 if (pos >= sqlStatementStri->size || sqlStatementStri->mem[pos] != '-') {
524 processed->mem[destPos++] = ch;
525 } else {
526 pos++;
527 while (pos < sqlStatementStri->size && sqlStatementStri->mem[pos] != '\n') {
528 pos++;
529 } /* while */
530 /* The final newline replaces the comment. */
531 } /* if */
532 } else {
533 processed->mem[destPos++] = ch;
534 pos++;
535 } /* if */
536 } /* while */
537 processed->size = destPos;
538 } /* if */
539 logFunction(printf("processStatementStri --> \"%s\"\n",
540 striAsUnquotedCStri(processed)););
541 return processed;
542 } /* processStatementStri */
543
544
545
setupParameters(preparedStmtType preparedStmt)546 static errInfoType setupParameters (preparedStmtType preparedStmt)
547
548 {
549 unsigned long num_params;
550 errInfoType err_info = OKAY_NO_ERROR;
551
552 /* setupParameters */
553 logFunction(printf("setupParameters\n"););
554 num_params = mysql_stmt_param_count(preparedStmt->ppStmt);
555 if (num_params == 0) {
556 /* malloc(0) may return NULL, which would wrongly trigger a MEMORY_ERROR. */
557 preparedStmt->param_array_size = 0;
558 preparedStmt->param_array = NULL;
559 preparedStmt->param_data_array = NULL;
560 } else if (unlikely(!ALLOC_TABLE(preparedStmt->param_array,
561 MYSQL_BIND, (memSizeType) num_params))) {
562 err_info = MEMORY_ERROR;
563 } else if (unlikely(!ALLOC_TABLE(preparedStmt->param_data_array,
564 bindDataRecord, (memSizeType) num_params))) {
565 FREE_TABLE(preparedStmt->param_array, MYSQL_BIND, (memSizeType) num_params);
566 err_info = MEMORY_ERROR;
567 } else {
568 preparedStmt->param_array_size = (memSizeType) num_params;
569 memset(preparedStmt->param_array, 0,
570 (memSizeType) num_params * sizeof(MYSQL_BIND));
571 memset(preparedStmt->param_data_array, 0,
572 (memSizeType) num_params * sizeof(bindDataRecord));
573 } /* if */
574 logFunction(printf("setupParameters --> %d\n", err_info););
575 return err_info;
576 } /* setupParameters */
577
578
579
setupResultColumn(preparedStmtType preparedStmt,unsigned int column_num,MYSQL_RES * result_metadata,MYSQL_BIND * resultData)580 static errInfoType setupResultColumn (preparedStmtType preparedStmt,
581 unsigned int column_num, MYSQL_RES *result_metadata,
582 MYSQL_BIND *resultData)
583
584 {
585 MYSQL_FIELD *column;
586 memSizeType buffer_length;
587 errInfoType err_info = OKAY_NO_ERROR;
588
589 /* setupResultColumn */
590 logFunction(printf("setupResultColumn: column_num=%d\n", column_num););
591 column = mysql_fetch_field_direct(result_metadata, column_num - 1);
592 /* printf("column[%u]->type: %s\n", column_num, nameOfBufferType(column->type)); */
593 /* printf("charsetnr: %u\n", column->charsetnr); */
594 switch (column->type) {
595 case MYSQL_TYPE_TINY:
596 buffer_length = 1;
597 resultData->length = NULL;
598 break;
599 case MYSQL_TYPE_SHORT:
600 buffer_length = 2;
601 resultData->length = NULL;
602 break;
603 case MYSQL_TYPE_INT24:
604 case MYSQL_TYPE_LONG:
605 buffer_length = 4;
606 resultData->length = NULL;
607 break;
608 case MYSQL_TYPE_LONGLONG:
609 /* printf("MYSQL_LONGLONG: column->length = %lu\n", column->length);
610 printf("MYSQL_LONGLONG: column->decimals = %d\n", column->decimals); */
611 buffer_length = 8;
612 resultData->length = NULL;
613 break;
614 case MYSQL_TYPE_FLOAT:
615 /* printf("MYSQL_TYPE_FLOAT: column->length = %lu\n", column->length);
616 printf("MYSQL_TYPE_FLOAT: column->decimals = %d\n", column->decimals); */
617 buffer_length = 4;
618 resultData->length = NULL;
619 break;
620 case MYSQL_TYPE_DOUBLE:
621 /* printf("MYSQL_TYPE_DOUBLE: column->length = %lu\n", column->length);
622 printf("MYSQL_TYPE_DOUBLE: column->decimals = %d\n", column->decimals); */
623 buffer_length = 8;
624 resultData->length = NULL;
625 break;
626 case MYSQL_TYPE_DECIMAL:
627 case MYSQL_TYPE_NEWDECIMAL:
628 /* printf("MYSQL_TYPE_NEWDECIMAL: column->length = %lu\n", column->length);
629 printf("MYSQL_TYPE_NEWDECIMAL: column->decimals = %d\n", column->decimals); */
630 buffer_length = column->length;
631 resultData->length = &resultData->length_value;
632 break;
633 case MYSQL_TYPE_TIME:
634 case MYSQL_TYPE_DATE:
635 case MYSQL_TYPE_DATETIME:
636 case MYSQL_TYPE_TIMESTAMP:
637 buffer_length = sizeof(MYSQL_TIME);
638 resultData->length = NULL;
639 break;
640 case MYSQL_TYPE_STRING:
641 case MYSQL_TYPE_VAR_STRING:
642 buffer_length = column->length;
643 resultData->length = &resultData->length_value;
644 break;
645 case MYSQL_TYPE_TINY_BLOB:
646 case MYSQL_TYPE_BLOB:
647 case MYSQL_TYPE_MEDIUM_BLOB:
648 case MYSQL_TYPE_LONG_BLOB:
649 /* For BLOB types no buffer is provided (buffer == NULL). */
650 /* This way mysql_stmt_fetch() will not fetch data. Instead */
651 /* mysql_stmt_fetch() returns MYSQL_DATA_TRUNCATED, which */
652 /* is ignored by sqlFetch(). The actual BLOB data is */
653 /* fetched with mysql_stmt_fetch_column(). */
654 buffer_length = 0;
655 resultData->length = &resultData->length_value;
656 break;
657 default:
658 logError(printf("setupResultColumn: Column %s has the unknown type %s.\n",
659 column->name, nameOfBufferType(column->type)););
660 err_info = RANGE_ERROR;
661 break;
662 } /* switch */
663 /* printf("buffer_length: " FMT_U_MEM "\n", buffer_length); */
664 if (err_info == OKAY_NO_ERROR) {
665 if (buffer_length != 0) {
666 resultData->buffer = malloc(buffer_length);
667 if (unlikely(resultData->buffer == NULL)) {
668 err_info = MEMORY_ERROR;
669 } else {
670 resultData->buffer_type = column->type;
671 resultData->buffer_length = buffer_length;
672 resultData->is_unsigned = 0;
673 resultData->is_null = &resultData->is_null_value;
674 resultData->is_null_value = 0;
675 preparedStmt->result_data_array[column_num - 1].name = column->name;
676 /* A charsetnr value of 63 indicates that the */
677 /* character set is binary. This allows to distinguish */
678 /* BINARY from CHAR, and VARBINARY from VARCHAR. */
679 preparedStmt->result_data_array[column_num - 1].binary = column->charsetnr == 63;
680 } /* if */
681 } else {
682 /* This triggers that mysql_stmt_fetch() returns MYSQL_DATA_TRUNCATED. */
683 /* Only BLOBs and CLOBs will have a buffer of NULL. */
684 resultData->buffer = NULL;
685 resultData->buffer_type = column->type;
686 resultData->buffer_length = 0;
687 resultData->is_unsigned = 0;
688 resultData->is_null = &resultData->is_null_value;
689 resultData->is_null_value = 0;
690 preparedStmt->result_data_array[column_num - 1].name = column->name;
691 /* A charsetnr value of 63 indicates that the */
692 /* character set is binary. This allows to */
693 /* distinguish BLOB types from TEXT types. */
694 preparedStmt->result_data_array[column_num - 1].binary = column->charsetnr == 63;
695 } /* if */
696 } /* if */
697 logFunction(printf("setupResultColumn --> %d\n", err_info););
698 return err_info;
699 } /* setupResultColumn */
700
701
702
setupResult(preparedStmtType preparedStmt)703 static errInfoType setupResult (preparedStmtType preparedStmt)
704
705 {
706 MYSQL_RES *result_metadata;
707 unsigned int num_columns;
708 unsigned int column_index;
709 errInfoType err_info = OKAY_NO_ERROR;
710
711 /* setupResult */
712 logFunction(printf("setupResult\n"););
713 result_metadata = mysql_stmt_result_metadata(preparedStmt->ppStmt);
714 if (result_metadata == NULL) {
715 preparedStmt->result_array = NULL;
716 preparedStmt->result_array_size = 0;
717 preparedStmt->result_data_array = NULL;
718 } else {
719 num_columns = mysql_num_fields(result_metadata);
720 /* printf("num_columns: %u\n", num_columns); */
721 if (num_columns == 0) {
722 /* malloc(0) may return NULL, which would wrongly trigger a MEMORY_ERROR. */
723 preparedStmt->result_array_size = 0;
724 preparedStmt->result_array = NULL;
725 preparedStmt->result_data_array = NULL;
726 } else if (unlikely(!ALLOC_TABLE(preparedStmt->result_array,
727 MYSQL_BIND, num_columns))) {
728 err_info = MEMORY_ERROR;
729 } else if (unlikely(!ALLOC_TABLE(preparedStmt->result_data_array,
730 resultDataRecord, num_columns))) {
731 FREE_TABLE(preparedStmt->result_array, MYSQL_BIND, num_columns);
732 err_info = MEMORY_ERROR;
733 } else {
734 preparedStmt->result_array_size = num_columns;
735 memset(preparedStmt->result_array, 0, num_columns * sizeof(MYSQL_BIND));
736 memset(preparedStmt->result_data_array, 0, num_columns * sizeof(resultDataRecord));
737 for (column_index = 0; column_index < num_columns &&
738 err_info == OKAY_NO_ERROR; column_index++) {
739 err_info = setupResultColumn(preparedStmt, column_index + 1,
740 result_metadata,
741 &preparedStmt->result_array[column_index]);
742 } /* for */
743 } /* if */
744 mysql_free_result(result_metadata);
745 } /* if */
746 logFunction(printf("setupResult --> %d\n", err_info););
747 return err_info;
748 } /* setupResult */
749
750
751
allParametersBound(preparedStmtType preparedStmt)752 static boolType allParametersBound (preparedStmtType preparedStmt)
753
754 {
755 memSizeType column_index;
756 boolType okay = TRUE;
757
758 /* allParametersBound */
759 for (column_index = 0; column_index < preparedStmt->param_array_size;
760 column_index++) {
761 if (unlikely(!preparedStmt->param_data_array[column_index].bound)) {
762 logError(printf("sqlExecute: Unbound parameter " FMT_U_MEM ".\n",
763 column_index + 1););
764 okay = FALSE;
765 } /* if */
766 } /* for */
767 return okay;
768 } /* allParametersBound */
769
770
771
setBigInt(const void * buffer,const const_bigIntType bigIntValue,errInfoType * err_info)772 static unsigned int setBigInt (const void *buffer, const const_bigIntType bigIntValue,
773 errInfoType *err_info)
774
775 {
776 striType stri;
777 unsigned char *decimal;
778 unsigned int srcIndex;
779 unsigned int destIndex;
780 unsigned int length = 0;
781
782 /* setBigInt */
783 logFunction(printf("setBigInt(%s)\n", bigHexCStri(bigIntValue)););
784 stri = bigStr(bigIntValue);
785 if (unlikely(stri == NULL)) {
786 *err_info = MEMORY_ERROR;
787 } else {
788 /* printf("%s\n", striAsUnquotedCStri(stri)); */
789 decimal = (unsigned char *) buffer;
790 srcIndex = 0;
791 destIndex = 0;
792 if (stri->mem[0] == '-') {
793 decimal[0] = '-';
794 srcIndex++;
795 destIndex++;
796 } /* if */
797 if (unlikely(stri->size - srcIndex > MAX_DECIMAL_PRECISION)) {
798 logError(printf("setBigInt: Number of digits (" FMT_U_MEM
799 ") larger than the allowed maximum (%d)\n.",
800 stri->size - srcIndex, MAX_DECIMAL_PRECISION););
801 *err_info = RANGE_ERROR;
802 } else {
803 for (; srcIndex < stri->size; srcIndex++) {
804 decimal[destIndex] = (unsigned char) stri->mem[srcIndex];
805 destIndex++;
806 } /* for */
807 length = destIndex;
808 } /* if */
809 FREE_STRI(stri, stri->size);
810 } /* if */
811 logFunction(printf("setBigInt --> %u\n", length););
812 return length;
813 } /* setBigInt */
814
815
816
setBigRat(const void * buffer,const const_bigIntType numerator,const const_bigIntType denominator,errInfoType * err_info)817 static unsigned int setBigRat (const void *buffer, const const_bigIntType numerator,
818 const const_bigIntType denominator, errInfoType *err_info)
819
820 {
821 bigIntType number;
822 bigIntType mantissaValue;
823 striType stri;
824 unsigned int striSizeUsed;
825 unsigned int scale;
826 unsigned char *decimal;
827 memSizeType decimalSize;
828 unsigned int srcIndex;
829 unsigned int destIndex;
830 unsigned int length = 0;
831
832 /* setBigRat */
833 logFunction(printf("setBigRat(*, %s, %s, *)\n",
834 bigHexCStri(numerator), bigHexCStri(denominator)););
835 if (unlikely(bigEqSignedDigit(denominator, 0))) {
836 /* Decimal values do not support Infinity and NaN. */
837 logError(printf("setBigRat: Decimal values do not support Infinity and NaN.\n"););
838 raise_error(RANGE_ERROR);
839 } else {
840 number = bigIPowSignedDigit(10, MAX_DECIMAL_SCALE);
841 if (unlikely(number == NULL)) {
842 mantissaValue = NULL;
843 } else {
844 bigMultAssign(&number, numerator);
845 mantissaValue = bigDiv(number, denominator);
846 bigDestr(number);
847 } /* if */
848 if (unlikely(mantissaValue == NULL)) {
849 decimal = NULL;
850 } else if (bigEqSignedDigit(mantissaValue, 0)) {
851 memcpy((char *) buffer, "0.0", 3);
852 } else {
853 stri = bigStr(mantissaValue);
854 if (unlikely(stri == NULL)) {
855 *err_info = MEMORY_ERROR;
856 } else if (unlikely(stri->size > UINT_MAX)) {
857 /* It is not possible to cast stri->size to unsigned int. */
858 FREE_STRI(stri, stri->size);
859 *err_info = MEMORY_ERROR;
860 } else {
861 /* printf("%s\n", striAsUnquotedCStri(stri)); */
862 striSizeUsed = (unsigned int) stri->size;
863 scale = MAX_DECIMAL_SCALE;
864 while (scale >= 2 && stri->mem[striSizeUsed - 1] == '0') {
865 scale--;
866 striSizeUsed--;
867 } /* while */
868 decimalSize = striSizeUsed;
869 if (decimalSize - (stri->mem[0] == '-') > scale) {
870 /* Add one character for the decimal point. */
871 decimalSize += 1;
872 } else {
873 /* Add space for sign, zero and decimal point. */
874 decimalSize = (stri->mem[0] == '-') + scale + 2;
875 } /* if */
876 if (unlikely(decimalSize > MAX_DECIMAL_LENGTH)) {
877 logError(printf("setBigRat: decimalSize (" FMT_U_MEM
878 ") larger than maximum (%d).\n",
879 decimalSize, MAX_DECIMAL_LENGTH););
880 *err_info = RANGE_ERROR;
881 } else {
882 decimal = (unsigned char *) buffer;
883 srcIndex = 0;
884 destIndex = 0;
885 if (stri->mem[0] == '-') {
886 decimal[0] = '-';
887 srcIndex++;
888 destIndex++;
889 } /* if */
890 if (striSizeUsed - srcIndex > scale) {
891 for (; srcIndex < striSizeUsed - scale; srcIndex++) {
892 decimal[destIndex] = (unsigned char) stri->mem[srcIndex];
893 destIndex++;
894 } /* for */
895 decimal[destIndex] = '.';
896 destIndex++;
897 } else {
898 decimal[destIndex] = '0';
899 destIndex++;
900 decimal[destIndex] = '.';
901 destIndex++;
902 memset(&decimal[destIndex], '0', scale - striSizeUsed + srcIndex);
903 destIndex += scale - striSizeUsed + srcIndex;
904 } /* if */
905 for (; srcIndex < striSizeUsed; srcIndex++) {
906 decimal[destIndex] = (unsigned char) stri->mem[srcIndex];
907 destIndex++;
908 } /* for */
909 length = destIndex;
910 } /* if */
911 FREE_STRI(stri, stri->size);
912 } /* if */
913 bigDestr(mantissaValue);
914 } /* if */
915 } /* if */
916 #if 0
917 printf("length: %u\n", length);
918 for (srcIndex = 0; srcIndex < length; srcIndex++) {
919 printf(" %u", ((unsigned char *) buffer)[srcIndex]);
920 } /* for */
921 printf("\n");
922 for (srcIndex = 0; srcIndex < length; srcIndex++) {
923 printf("%c", ((unsigned char *) buffer)[srcIndex]);
924 } /* for */
925 printf("\n");
926 #endif
927 return length;
928 } /* setBigRat */
929
930
931
sqlBindBigInt(sqlStmtType sqlStatement,intType pos,const const_bigIntType value)932 static void sqlBindBigInt (sqlStmtType sqlStatement, intType pos,
933 const const_bigIntType value)
934
935 {
936 preparedStmtType preparedStmt;
937 MYSQL_BIND *param;
938 unsigned int length;
939 errInfoType err_info = OKAY_NO_ERROR;
940
941 /* sqlBindBigInt */
942 logFunction(printf("sqlBindBigInt(" FMT_U_MEM ", " FMT_D ", %s)\n",
943 (memSizeType) sqlStatement, pos, bigHexCStri(value)););
944 preparedStmt = (preparedStmtType) sqlStatement;
945 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
946 logError(printf("sqlBindBigInt: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
947 pos, preparedStmt->param_array_size););
948 raise_error(RANGE_ERROR);
949 } else {
950 param = &preparedStmt->param_array[pos - 1];
951 if (preparedStmt->param_data_array[pos - 1].buffer_capacity < MAX_DECIMAL_LENGTH) {
952 free(param->buffer);
953 if (unlikely((param->buffer = malloc(MAX_DECIMAL_LENGTH)) == NULL)) {
954 preparedStmt->param_data_array[pos - 1].buffer_capacity = 0;
955 err_info = MEMORY_ERROR;
956 } else {
957 preparedStmt->param_data_array[pos - 1].buffer_capacity = MAX_DECIMAL_LENGTH;
958 } /* if */
959 } /* if */
960 if (unlikely(err_info != OKAY_NO_ERROR)) {
961 raise_error(err_info);
962 } else {
963 length = setBigInt(param->buffer,
964 value, &err_info);
965 if (unlikely(err_info != OKAY_NO_ERROR)) {
966 raise_error(err_info);
967 } else {
968 param->buffer_type = MYSQL_TYPE_NEWDECIMAL;
969 param->is_unsigned = 0;
970 param->is_null = NULL;
971 param->length = NULL;
972 param->buffer_length = length;
973 preparedStmt->executeSuccessful = FALSE;
974 preparedStmt->fetchOkay = FALSE;
975 preparedStmt->param_data_array[pos - 1].bound = TRUE;
976 } /* if */
977 } /* if */
978 } /* if */
979 } /* sqlBindBigInt */
980
981
982
sqlBindBigRat(sqlStmtType sqlStatement,intType pos,const const_bigIntType numerator,const const_bigIntType denominator)983 static void sqlBindBigRat (sqlStmtType sqlStatement, intType pos,
984 const const_bigIntType numerator, const const_bigIntType denominator)
985
986 {
987 preparedStmtType preparedStmt;
988 MYSQL_BIND *param;
989 unsigned int length;
990 errInfoType err_info = OKAY_NO_ERROR;
991
992 /* sqlBindBigRat */
993 logFunction(printf("sqlBindBigRat(" FMT_U_MEM ", " FMT_D ", %s, %s)\n",
994 (memSizeType) sqlStatement, pos,
995 bigHexCStri(numerator), bigHexCStri(denominator)););
996 preparedStmt = (preparedStmtType) sqlStatement;
997 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
998 logError(printf("sqlBindBigRat: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
999 pos, preparedStmt->param_array_size););
1000 raise_error(RANGE_ERROR);
1001 } else {
1002 param = &preparedStmt->param_array[pos - 1];
1003 if (preparedStmt->param_data_array[pos - 1].buffer_capacity < MAX_DECIMAL_LENGTH) {
1004 free(param->buffer);
1005 if (unlikely((param->buffer = malloc(MAX_DECIMAL_LENGTH)) == NULL)) {
1006 preparedStmt->param_data_array[pos - 1].buffer_capacity = 0;
1007 err_info = MEMORY_ERROR;
1008 } else {
1009 preparedStmt->param_data_array[pos - 1].buffer_capacity = MAX_DECIMAL_LENGTH;
1010 } /* if */
1011 } /* if */
1012 if (unlikely(err_info != OKAY_NO_ERROR)) {
1013 raise_error(err_info);
1014 } else {
1015 length = setBigRat(param->buffer,
1016 numerator, denominator, &err_info);
1017 if (unlikely(err_info != OKAY_NO_ERROR)) {
1018 raise_error(err_info);
1019 } else {
1020 param->buffer_type = MYSQL_TYPE_NEWDECIMAL;
1021 param->is_unsigned = 0;
1022 param->is_null = NULL;
1023 param->length = NULL;
1024 param->buffer_length = length;
1025 preparedStmt->executeSuccessful = FALSE;
1026 preparedStmt->fetchOkay = FALSE;
1027 preparedStmt->param_data_array[pos - 1].bound = TRUE;
1028 } /* if */
1029 } /* if */
1030 } /* if */
1031 } /* sqlBindBigRat */
1032
1033
1034
sqlBindBool(sqlStmtType sqlStatement,intType pos,boolType value)1035 static void sqlBindBool (sqlStmtType sqlStatement, intType pos, boolType value)
1036
1037 {
1038 preparedStmtType preparedStmt;
1039 MYSQL_BIND *param;
1040 errInfoType err_info = OKAY_NO_ERROR;
1041
1042 /* sqlBindBool */
1043 logFunction(printf("sqlBindBool(" FMT_U_MEM ", " FMT_D ", %s)\n",
1044 (memSizeType) sqlStatement, pos, value ? "TRUE" : "FALSE"););
1045 preparedStmt = (preparedStmtType) sqlStatement;
1046 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1047 logError(printf("sqlBindBool: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1048 pos, preparedStmt->param_array_size););
1049 raise_error(RANGE_ERROR);
1050 } else {
1051 param = &preparedStmt->param_array[pos - 1];
1052 if (preparedStmt->param_data_array[pos - 1].buffer_capacity < sizeof(char)) {
1053 free(param->buffer);
1054 if (unlikely((param->buffer = malloc(sizeof(char))) == NULL)) {
1055 preparedStmt->param_data_array[pos - 1].buffer_capacity = 0;
1056 err_info = MEMORY_ERROR;
1057 } else {
1058 preparedStmt->param_data_array[pos - 1].buffer_capacity = sizeof(char);
1059 } /* if */
1060 } /* if */
1061 if (unlikely(err_info != OKAY_NO_ERROR)) {
1062 raise_error(err_info);
1063 } else {
1064 param->buffer_type = MYSQL_TYPE_STRING;
1065 param->buffer_length = 1;
1066 param->is_unsigned = 0;
1067 param->is_null = NULL;
1068 param->length = NULL;
1069 ((char *) param->buffer)[0] = (char) ('0' + value);
1070 preparedStmt->executeSuccessful = FALSE;
1071 preparedStmt->fetchOkay = FALSE;
1072 preparedStmt->param_data_array[pos - 1].bound = TRUE;
1073 } /* if */
1074 } /* if */
1075 } /* sqlBindBool */
1076
1077
1078
sqlBindBStri(sqlStmtType sqlStatement,intType pos,const const_bstriType bstri)1079 static void sqlBindBStri (sqlStmtType sqlStatement, intType pos,
1080 const const_bstriType bstri)
1081
1082 {
1083 preparedStmtType preparedStmt;
1084 MYSQL_BIND *param;
1085 errInfoType err_info = OKAY_NO_ERROR;
1086
1087 /* sqlBindBStri */
1088 logFunction(printf("sqlBindBStri(" FMT_U_MEM ", " FMT_D ", \"%s\")\n",
1089 (memSizeType) sqlStatement, pos, bstriAsUnquotedCStri(bstri)););
1090 preparedStmt = (preparedStmtType) sqlStatement;
1091 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1092 logError(printf("sqlBindBStri: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1093 pos, preparedStmt->param_array_size););
1094 raise_error(RANGE_ERROR);
1095 } else {
1096 param = &preparedStmt->param_array[pos - 1];
1097 if (unlikely(bstri->size > MAX_LONG_BLOB_LENGTH)) {
1098 raise_error(MEMORY_ERROR);
1099 } else {
1100 if (preparedStmt->param_data_array[pos - 1].buffer_capacity < bstri->size) {
1101 free(param->buffer);
1102 if (unlikely((param->buffer = malloc(bstri->size)) == NULL)) {
1103 preparedStmt->param_data_array[pos - 1].buffer_capacity = 0;
1104 err_info = MEMORY_ERROR;
1105 } else {
1106 preparedStmt->param_data_array[pos - 1].buffer_capacity = bstri->size;
1107 } /* if */
1108 } /* if */
1109 if (unlikely(err_info != OKAY_NO_ERROR)) {
1110 raise_error(err_info);
1111 } else {
1112 if (bstri->size <= MAX_TINY_BLOB_LENGTH) {
1113 param->buffer_type = MYSQL_TYPE_TINY_BLOB;
1114 } else if (bstri->size <= MAX_BLOB_LENGTH) {
1115 param->buffer_type = MYSQL_TYPE_BLOB;
1116 } else if (bstri->size <= MAX_MEDIUM_BLOB_LENGTH) {
1117 param->buffer_type = MYSQL_TYPE_MEDIUM_BLOB;
1118 } else {
1119 param->buffer_type = MYSQL_TYPE_LONG_BLOB;
1120 } /* if */
1121 /* printf("sqlBindBStri: buffer_type: %s\n",
1122 nameOfBufferType(param->buffer_type)); */
1123 param->is_unsigned = 0;
1124 param->is_null = NULL;
1125 param->length = NULL;
1126 memcpy(param->buffer, bstri->mem, bstri->size);
1127 param->buffer_length = (unsigned long) bstri->size;
1128 preparedStmt->executeSuccessful = FALSE;
1129 preparedStmt->fetchOkay = FALSE;
1130 preparedStmt->param_data_array[pos - 1].bound = TRUE;
1131 } /* if */
1132 } /* if */
1133 } /* if */
1134 } /* sqlBindBStri */
1135
1136
1137
sqlBindDuration(sqlStmtType sqlStatement,intType pos,intType year,intType month,intType day,intType hour,intType minute,intType second,intType micro_second)1138 static void sqlBindDuration (sqlStmtType sqlStatement, intType pos,
1139 intType year, intType month, intType day, intType hour,
1140 intType minute, intType second, intType micro_second)
1141
1142 {
1143 preparedStmtType preparedStmt;
1144 MYSQL_BIND *param;
1145 int64Type monthDuration;
1146 int64Type microsecDuration;
1147 MYSQL_TIME *timeValue;
1148 errInfoType err_info = OKAY_NO_ERROR;
1149
1150 /* sqlBindDuration */
1151 logFunction(printf("sqlBindDuration(" FMT_U_MEM ", " FMT_D ", P"
1152 FMT_D "Y" FMT_D "M" FMT_D "DT"
1153 FMT_D "H" FMT_D "M%s" FMT_U "." F_U(06) "S)\n",
1154 (memSizeType) sqlStatement, pos,
1155 year, month, day, hour, minute,
1156 second < 0 || micro_second < 0 ? "-" : "",
1157 intAbs(second), intAbs(micro_second)););
1158 preparedStmt = (preparedStmtType) sqlStatement;
1159 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1160 logError(printf("sqlBindDuration: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1161 pos, preparedStmt->param_array_size););
1162 raise_error(RANGE_ERROR);
1163 } else if (unlikely(year < -INT_MAX || year > INT_MAX || month < -12 || month > 12 ||
1164 day < -31 || day > 31 || hour <= -24 || hour >= 24 ||
1165 minute <= -60 || minute >= 60 || second <= -60 || second >= 60 ||
1166 micro_second <= -1000000 || micro_second >= 1000000)) {
1167 logError(printf("sqlBindDuration: Duration not in allowed range.\n"););
1168 raise_error(RANGE_ERROR);
1169 } else {
1170 param = &preparedStmt->param_array[pos - 1];
1171 if (preparedStmt->param_data_array[pos - 1].buffer_capacity < sizeof(MYSQL_TIME)) {
1172 free(param->buffer);
1173 if (unlikely((param->buffer = malloc(sizeof(MYSQL_TIME))) == NULL)) {
1174 preparedStmt->param_data_array[pos - 1].buffer_capacity = 0;
1175 err_info = MEMORY_ERROR;
1176 } else {
1177 preparedStmt->param_data_array[pos - 1].buffer_capacity = sizeof(MYSQL_TIME);
1178 } /* if */
1179 } /* if */
1180 if (unlikely(err_info != OKAY_NO_ERROR)) {
1181 raise_error(err_info);
1182 } else {
1183 monthDuration = (int64Type) year * 12 + (int64Type) month;
1184 microsecDuration = (((((int64Type) day) * 24 +
1185 (int64Type) hour) * 60 +
1186 (int64Type) minute) * 60 +
1187 (int64Type) second) * 1000000 +
1188 (int64Type) micro_second;
1189 /* printf("monthDuration: " FMT_D64 "\n", monthDuration);
1190 printf("microsecDuration: " FMT_D64 "\n", microsecDuration); */
1191 if (unlikely(!((monthDuration >= 0 && microsecDuration >= 0) ||
1192 (monthDuration <= 0 && microsecDuration <= 0)))) {
1193 logError(printf("sqlBindDuration: Duration neither clearly positive nor negative.\n"););
1194 raise_error(RANGE_ERROR);
1195 } else {
1196 param->buffer_type = MYSQL_TYPE_DATETIME;
1197 param->is_unsigned = 0;
1198 param->is_null = NULL;
1199 param->length = NULL;
1200 timeValue = (MYSQL_TIME *) param->buffer;
1201 if (monthDuration >= 0 && microsecDuration >= 0) {
1202 timeValue->neg = 0;
1203 } else {
1204 monthDuration = -monthDuration;
1205 microsecDuration = -microsecDuration;
1206 timeValue->neg = 1;
1207 } /* if */
1208 timeValue->month = (unsigned int) monthDuration % 12;
1209 timeValue->year = (unsigned int) monthDuration / 12;
1210 timeValue->second_part = (unsigned long) microsecDuration % 1000000;
1211 microsecDuration /= 1000000;
1212 timeValue->second = (unsigned int) microsecDuration % 60;
1213 microsecDuration /= 60;
1214 timeValue->minute = (unsigned int) microsecDuration % 60;
1215 microsecDuration /= 60;
1216 timeValue->hour = (unsigned int) microsecDuration % 24;
1217 timeValue->day = (unsigned int) microsecDuration / 24;
1218 timeValue->time_type = MYSQL_TIMESTAMP_DATETIME;
1219 preparedStmt->executeSuccessful = FALSE;
1220 preparedStmt->fetchOkay = FALSE;
1221 preparedStmt->param_data_array[pos - 1].bound = TRUE;
1222 } /* if */
1223 } /* if */
1224 } /* if */
1225 } /* sqlBindDuration */
1226
1227
1228
sqlBindFloat(sqlStmtType sqlStatement,intType pos,floatType value)1229 static void sqlBindFloat (sqlStmtType sqlStatement, intType pos, floatType value)
1230
1231 {
1232 preparedStmtType preparedStmt;
1233 MYSQL_BIND *param;
1234 errInfoType err_info = OKAY_NO_ERROR;
1235
1236 /* sqlBindFloat */
1237 logFunction(printf("sqlBindFloat(" FMT_U_MEM ", " FMT_D ", " FMT_E ")\n",
1238 (memSizeType) sqlStatement, pos, value););
1239 preparedStmt = (preparedStmtType) sqlStatement;
1240 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1241 logError(printf("sqlBindFloat: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1242 pos, preparedStmt->param_array_size););
1243 raise_error(RANGE_ERROR);
1244 } else {
1245 param = &preparedStmt->param_array[pos - 1];
1246 if (preparedStmt->param_data_array[pos - 1].buffer_capacity < sizeof(floatType)) {
1247 free(param->buffer);
1248 if (unlikely((param->buffer = malloc(sizeof(floatType))) == NULL)) {
1249 preparedStmt->param_data_array[pos - 1].buffer_capacity = 0;
1250 err_info = MEMORY_ERROR;
1251 } else {
1252 preparedStmt->param_data_array[pos - 1].buffer_capacity = sizeof(floatType);
1253 } /* if */
1254 } /* if */
1255 if (unlikely(err_info != OKAY_NO_ERROR)) {
1256 raise_error(err_info);
1257 } else {
1258 #if FLOATTYPE_SIZE == 32
1259 param->buffer_type = MYSQL_TYPE_FLOAT;
1260 #elif FLOATTYPE_SIZE == 64
1261 param->buffer_type = MYSQL_TYPE_DOUBLE;
1262 #endif
1263 param->is_unsigned = 0;
1264 param->is_null = NULL;
1265 param->length = NULL;
1266 *(floatType *) param->buffer = value;
1267 preparedStmt->executeSuccessful = FALSE;
1268 preparedStmt->fetchOkay = FALSE;
1269 preparedStmt->param_data_array[pos - 1].bound = TRUE;
1270 } /* if */
1271 } /* if */
1272 } /* sqlBindFloat */
1273
1274
1275
sqlBindInt(sqlStmtType sqlStatement,intType pos,intType value)1276 static void sqlBindInt (sqlStmtType sqlStatement, intType pos, intType value)
1277
1278 {
1279 preparedStmtType preparedStmt;
1280 MYSQL_BIND *param;
1281 errInfoType err_info = OKAY_NO_ERROR;
1282
1283 /* sqlBindInt */
1284 logFunction(printf("sqlBindInt(" FMT_U_MEM ", " FMT_D ", " FMT_D ")\n",
1285 (memSizeType) sqlStatement, pos, value););
1286 preparedStmt = (preparedStmtType) sqlStatement;
1287 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1288 logError(printf("sqlBindInt: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1289 pos, preparedStmt->param_array_size););
1290 raise_error(RANGE_ERROR);
1291 } else {
1292 param = &preparedStmt->param_array[pos - 1];
1293 if (preparedStmt->param_data_array[pos - 1].buffer_capacity < sizeof(intType)) {
1294 free(param->buffer);
1295 if (unlikely((param->buffer = malloc(sizeof(intType))) == NULL)) {
1296 preparedStmt->param_data_array[pos - 1].buffer_capacity = 0;
1297 err_info = MEMORY_ERROR;
1298 } else {
1299 preparedStmt->param_data_array[pos - 1].buffer_capacity = sizeof(intType);
1300 } /* if */
1301 } /* if */
1302 if (unlikely(err_info != OKAY_NO_ERROR)) {
1303 raise_error(err_info);
1304 } else {
1305 #if INTTYPE_SIZE == 32
1306 param->buffer_type = MYSQL_TYPE_LONG;
1307 #elif INTTYPE_SIZE == 64
1308 param->buffer_type = MYSQL_TYPE_LONGLONG;
1309 #endif
1310 param->is_unsigned = 0;
1311 param->is_null = NULL;
1312 param->length = NULL;
1313 *(intType *) param->buffer = value;
1314 preparedStmt->executeSuccessful = FALSE;
1315 preparedStmt->fetchOkay = FALSE;
1316 preparedStmt->param_data_array[pos - 1].bound = TRUE;
1317 } /* if */
1318 } /* if */
1319 } /* sqlBindInt */
1320
1321
1322
sqlBindNull(sqlStmtType sqlStatement,intType pos)1323 static void sqlBindNull (sqlStmtType sqlStatement, intType pos)
1324
1325 {
1326 preparedStmtType preparedStmt;
1327 MYSQL_BIND *param;
1328
1329 /* sqlBindNull */
1330 logFunction(printf("sqlBindNull(" FMT_U_MEM ", " FMT_D ")\n",
1331 (memSizeType) sqlStatement, pos););
1332 preparedStmt = (preparedStmtType) sqlStatement;
1333 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1334 logError(printf("sqlBindNull: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1335 pos, preparedStmt->param_array_size););
1336 raise_error(RANGE_ERROR);
1337 } else {
1338 param = &preparedStmt->param_array[pos - 1];
1339 param->is_null = ¶m->is_null_value;
1340 param->is_null_value = 1;
1341 preparedStmt->executeSuccessful = FALSE;
1342 preparedStmt->fetchOkay = FALSE;
1343 preparedStmt->param_data_array[pos - 1].bound = TRUE;
1344 } /* if */
1345 } /* sqlBindNull */
1346
1347
1348
sqlBindStri(sqlStmtType sqlStatement,intType pos,const const_striType stri)1349 static void sqlBindStri (sqlStmtType sqlStatement, intType pos,
1350 const const_striType stri)
1351
1352 {
1353 preparedStmtType preparedStmt;
1354 MYSQL_BIND *param;
1355 cstriType stri8;
1356 cstriType resized_stri8;
1357 memSizeType length;
1358
1359 /* sqlBindStri */
1360 logFunction(printf("sqlBindStri(" FMT_U_MEM ", " FMT_D ", \"%s\")\n",
1361 (memSizeType) sqlStatement, pos, striAsUnquotedCStri(stri)););
1362 preparedStmt = (preparedStmtType) sqlStatement;
1363 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1364 logError(printf("sqlBindStri: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1365 pos, preparedStmt->param_array_size););
1366 raise_error(RANGE_ERROR);
1367 } else {
1368 param = &preparedStmt->param_array[pos - 1];
1369 stri8 = stri_to_cstri8_buf(stri, &length);
1370 if (unlikely(stri8 == NULL)) {
1371 raise_error(MEMORY_ERROR);
1372 } else if (unlikely(length > ULONG_MAX)) {
1373 /* It is not possible to cast length to unsigned long. */
1374 free(stri8);
1375 raise_error(MEMORY_ERROR);
1376 } else {
1377 resized_stri8 = REALLOC_CSTRI(stri8, length);
1378 if (likely(resized_stri8 != NULL)) {
1379 stri8 = resized_stri8;
1380 } /* if */
1381 free(param->buffer);
1382 param->buffer_type = MYSQL_TYPE_STRING;
1383 param->is_unsigned = 0;
1384 param->is_null = NULL;
1385 param->length = NULL;
1386 param->buffer = stri8;
1387 param->buffer_length = (unsigned long) length;
1388 preparedStmt->param_data_array[pos - 1].buffer_capacity = length;
1389 preparedStmt->executeSuccessful = FALSE;
1390 preparedStmt->fetchOkay = FALSE;
1391 preparedStmt->param_data_array[pos - 1].bound = TRUE;
1392 } /* if */
1393 } /* if */
1394 } /* sqlBindStri */
1395
1396
1397
sqlBindTime(sqlStmtType sqlStatement,intType pos,intType year,intType month,intType day,intType hour,intType minute,intType second,intType micro_second,intType time_zone)1398 static void sqlBindTime (sqlStmtType sqlStatement, intType pos,
1399 intType year, intType month, intType day, intType hour,
1400 intType minute, intType second, intType micro_second,
1401 intType time_zone)
1402
1403 {
1404 preparedStmtType preparedStmt;
1405 MYSQL_BIND *param;
1406 MYSQL_TIME *timeValue;
1407 errInfoType err_info = OKAY_NO_ERROR;
1408
1409 /* sqlBindTime */
1410 logFunction(printf("sqlBindTime(" FMT_U_MEM ", " FMT_D ", "
1411 F_D(04) "-" F_D(02) "-" F_D(02) " "
1412 F_D(02) ":" F_D(02) ":" F_D(02) "." F_D(06) ", "
1413 FMT_D ")\n",
1414 (memSizeType) sqlStatement, pos,
1415 year, month, day,
1416 hour, minute, second, micro_second,
1417 time_zone););
1418 preparedStmt = (preparedStmtType) sqlStatement;
1419 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1420 logError(printf("sqlBindTime: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1421 pos, preparedStmt->param_array_size););
1422 raise_error(RANGE_ERROR);
1423 } else if (unlikely(year < -INT_MAX || year > INT_MAX || month < 1 || month > 12 ||
1424 day < 1 || day > 31 || hour < 0 || hour >= 24 ||
1425 minute < 0 || minute >= 60 || second < 0 || second >= 60 ||
1426 micro_second < 0 || micro_second >= 1000000)) {
1427 logError(printf("sqlBindTime: Time not in allowed range.\n"););
1428 raise_error(RANGE_ERROR);
1429 } else {
1430 param = &preparedStmt->param_array[pos - 1];
1431 if (preparedStmt->param_data_array[pos - 1].buffer_capacity < sizeof(MYSQL_TIME)) {
1432 free(param->buffer);
1433 if (unlikely((param->buffer = malloc(sizeof(MYSQL_TIME))) == NULL)) {
1434 preparedStmt->param_data_array[pos - 1].buffer_capacity = 0;
1435 err_info = MEMORY_ERROR;
1436 } else {
1437 preparedStmt->param_data_array[pos - 1].buffer_capacity = sizeof(MYSQL_TIME);
1438 } /* if */
1439 } /* if */
1440 if (unlikely(err_info != OKAY_NO_ERROR)) {
1441 raise_error(err_info);
1442 } else {
1443 param->buffer_type = MYSQL_TYPE_DATETIME;
1444 param->is_unsigned = 0;
1445 param->is_null = NULL;
1446 param->length = NULL;
1447 timeValue = (MYSQL_TIME *) param->buffer;
1448 if (year < 0) {
1449 timeValue->year = (unsigned int) -year;
1450 } else {
1451 timeValue->year = (unsigned int) year;
1452 } /* if */
1453 timeValue->month = (unsigned int) month;
1454 timeValue->day = (unsigned int) day;
1455 timeValue->hour = (unsigned int) hour;
1456 timeValue->minute = (unsigned int) minute;
1457 timeValue->second = (unsigned int) second;
1458 timeValue->neg = year < 0;
1459 timeValue->second_part = (unsigned long) micro_second;
1460 timeValue->time_type = MYSQL_TIMESTAMP_DATETIME;
1461 preparedStmt->executeSuccessful = FALSE;
1462 preparedStmt->fetchOkay = FALSE;
1463 preparedStmt->param_data_array[pos - 1].bound = TRUE;
1464 } /* if */
1465 } /* if */
1466 } /* sqlBindTime */
1467
1468
1469
sqlClose(databaseType database)1470 static void sqlClose (databaseType database)
1471
1472 {
1473 dbType db;
1474
1475 /* sqlClose */
1476 logFunction(printf("sqlClose(" FMT_U_MEM ")\n",
1477 (memSizeType) database););
1478 db = (dbType) database;
1479 if (db->connection != NULL) {
1480 mysql_close(db->connection);
1481 db->connection = NULL;
1482 } /* if */
1483 logFunction(printf("sqlClose -->\n"););
1484 } /* sqlClose */
1485
1486
1487
sqlColumnBigInt(sqlStmtType sqlStatement,intType column)1488 static bigIntType sqlColumnBigInt (sqlStmtType sqlStatement, intType column)
1489
1490 {
1491 preparedStmtType preparedStmt;
1492 MYSQL_BIND *columnData;
1493 bigIntType columnValue;
1494
1495 /* sqlColumnBigInt */
1496 logFunction(printf("sqlColumnBigInt(" FMT_U_MEM ", " FMT_D ")\n",
1497 (memSizeType) sqlStatement, column););
1498 preparedStmt = (preparedStmtType) sqlStatement;
1499 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
1500 (uintType) column > preparedStmt->result_array_size)) {
1501 logError(printf("sqlColumnBigInt: Fetch okay: %d, column: " FMT_D
1502 ", max column: " FMT_U_MEM ".\n",
1503 preparedStmt->fetchOkay, column,
1504 preparedStmt->result_array_size););
1505 raise_error(RANGE_ERROR);
1506 columnValue = NULL;
1507 } else {
1508 columnData = &preparedStmt->result_array[column - 1];
1509 if (columnData->is_null_value != 0) {
1510 /* printf("Column is NULL -> Use default value: 0\n"); */
1511 columnValue = bigZero();
1512 } else {
1513 /* printf("buffer_type: %s\n",
1514 nameOfBufferType(columnData->buffer_type)); */
1515 switch (columnData->buffer_type) {
1516 case MYSQL_TYPE_TINY:
1517 columnValue = bigFromInt32((int32Type)
1518 *(int8Type *) columnData->buffer);
1519 break;
1520 case MYSQL_TYPE_SHORT:
1521 columnValue = bigFromInt32((int32Type)
1522 *(int16Type *) columnData->buffer);
1523 break;
1524 case MYSQL_TYPE_INT24:
1525 case MYSQL_TYPE_LONG:
1526 columnValue = bigFromInt32(
1527 *(int32Type *) columnData->buffer);
1528 break;
1529 case MYSQL_TYPE_LONGLONG:
1530 columnValue = bigFromInt64(
1531 *(int64Type *) columnData->buffer);
1532 break;
1533 case MYSQL_TYPE_DECIMAL:
1534 case MYSQL_TYPE_NEWDECIMAL:
1535 columnValue = getDecimalBigInt(
1536 (const_ustriType) columnData->buffer,
1537 columnData->length_value);
1538 break;
1539 default:
1540 logError(printf("sqlColumnBigInt: Column " FMT_D " has the unknown type %s.\n",
1541 column, nameOfBufferType(
1542 columnData->buffer_type)););
1543 raise_error(RANGE_ERROR);
1544 columnValue = NULL;
1545 break;
1546 } /* switch */
1547 } /* if */
1548 } /* if */
1549 logFunction(printf("sqlColumnBigInt --> %s\n", bigHexCStri(columnValue)););
1550 return columnValue;
1551 } /* sqlColumnBigInt */
1552
1553
1554
sqlColumnBigRat(sqlStmtType sqlStatement,intType column,bigIntType * numerator,bigIntType * denominator)1555 static void sqlColumnBigRat (sqlStmtType sqlStatement, intType column,
1556 bigIntType *numerator, bigIntType *denominator)
1557
1558 {
1559 preparedStmtType preparedStmt;
1560 MYSQL_BIND *columnData;
1561 float floatValue;
1562 double doubleValue;
1563
1564 /* sqlColumnBigRat */
1565 logFunction(printf("sqlColumnBigRat(" FMT_U_MEM ", " FMT_D ", *, *)\n",
1566 (memSizeType) sqlStatement, column););
1567 preparedStmt = (preparedStmtType) sqlStatement;
1568 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
1569 (uintType) column > preparedStmt->result_array_size)) {
1570 logError(printf("sqlColumnBigRat: Fetch okay: %d, column: " FMT_D
1571 ", max column: " FMT_U_MEM ".\n",
1572 preparedStmt->fetchOkay, column,
1573 preparedStmt->result_array_size););
1574 raise_error(RANGE_ERROR);
1575 } else {
1576 columnData = &preparedStmt->result_array[column - 1];
1577 if (columnData->is_null_value != 0) {
1578 /* printf("Column is NULL -> Use default value: 0\n"); */
1579 *numerator = bigZero();
1580 *denominator = bigFromInt32(1);
1581 } else {
1582 /* printf("buffer_type: %s\n",
1583 nameOfBufferType(columnData->buffer_type)); */
1584 switch (columnData->buffer_type) {
1585 case MYSQL_TYPE_TINY:
1586 *numerator = bigFromInt32((int32Type)
1587 *(int8Type *) columnData->buffer);
1588 *denominator = bigFromInt32(1);
1589 break;
1590 case MYSQL_TYPE_SHORT:
1591 *numerator = bigFromInt32((int32Type)
1592 *(int16Type *) columnData->buffer);
1593 *denominator = bigFromInt32(1);
1594 break;
1595 case MYSQL_TYPE_INT24:
1596 case MYSQL_TYPE_LONG:
1597 *numerator = bigFromInt32(
1598 *(int32Type *) columnData->buffer);
1599 *denominator = bigFromInt32(1);
1600 break;
1601 case MYSQL_TYPE_LONGLONG:
1602 *numerator = bigFromInt64(
1603 *(int64Type *) columnData->buffer);
1604 *denominator = bigFromInt32(1);
1605 break;
1606 case MYSQL_TYPE_FLOAT:
1607 floatValue = *(float *) columnData->buffer;
1608 if (floatValue == MOST_POSITIVE_FLOAT) {
1609 /* The IEEE 754 value infinity is stored as the most positive value. */
1610 floatValue = (float) POSITIVE_INFINITY;
1611 } else if (floatValue == MOST_NEGATIVE_FLOAT) {
1612 /* The IEEE 754 value -infinity is stored as the most negative value. */
1613 floatValue = (float) NEGATIVE_INFINITY;
1614 } /* if */
1615 /* printf("sqlColumnBigRat: float: %f\n", floatValue); */
1616 *numerator = roundDoubleToBigRat(floatValue, FALSE, denominator);
1617 break;
1618 case MYSQL_TYPE_DOUBLE:
1619 doubleValue = *(double *) columnData->buffer;
1620 if (doubleValue == MOST_POSITIVE_DOUBLE) {
1621 /* The IEEE 754 value infinity is stored as the most positive value. */
1622 doubleValue = POSITIVE_INFINITY;
1623 } else if (doubleValue == MOST_NEGATIVE_DOUBLE) {
1624 /* The IEEE 754 value -infinity is stored as the most negative value. */
1625 doubleValue = NEGATIVE_INFINITY;
1626 } /* if */
1627 /* printf("sqlColumnBigRat: double: %f\n", doubleValue); */
1628 *numerator = roundDoubleToBigRat(doubleValue, TRUE, denominator);
1629 break;
1630 case MYSQL_TYPE_DECIMAL:
1631 case MYSQL_TYPE_NEWDECIMAL:
1632 *numerator = getDecimalBigRational(
1633 (const_ustriType) columnData->buffer,
1634 columnData->length_value, denominator);
1635 break;
1636 default:
1637 logError(printf("sqlColumnBigRat: Column " FMT_D " has the unknown type %s.\n",
1638 column, nameOfBufferType(
1639 columnData->buffer_type)););
1640 raise_error(RANGE_ERROR);
1641 break;
1642 } /* switch */
1643 } /* if */
1644 } /* if */
1645 logFunction(printf("sqlColumnBigRat(" FMT_U_MEM ", " FMT_D ", %s, %s) -->\n",
1646 (memSizeType) sqlStatement, column,
1647 bigHexCStri(*numerator), bigHexCStri(*denominator)););
1648 } /* sqlColumnBigRat */
1649
1650
1651
sqlColumnBool(sqlStmtType sqlStatement,intType column)1652 static boolType sqlColumnBool (sqlStmtType sqlStatement, intType column)
1653
1654 {
1655 preparedStmtType preparedStmt;
1656 MYSQL_BIND *columnData;
1657 int64Type columnValue;
1658
1659 /* sqlColumnBool */
1660 logFunction(printf("sqlColumnBool(" FMT_U_MEM ", " FMT_D ")\n",
1661 (memSizeType) sqlStatement, column););
1662 preparedStmt = (preparedStmtType) sqlStatement;
1663 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
1664 (uintType) column > preparedStmt->result_array_size)) {
1665 logError(printf("sqlColumnBool: Fetch okay: %d, column: " FMT_D
1666 ", max column: " FMT_U_MEM ".\n",
1667 preparedStmt->fetchOkay, column,
1668 preparedStmt->result_array_size););
1669 raise_error(RANGE_ERROR);
1670 columnValue = 0;
1671 } else {
1672 columnData = &preparedStmt->result_array[column - 1];
1673 if (columnData->is_null_value != 0) {
1674 /* printf("Column is NULL -> Use default value: FALSE\n"); */
1675 columnValue = 0;
1676 } else {
1677 /* printf("buffer_type: %s\n",
1678 nameOfBufferType(columnData->buffer_type)); */
1679 switch (columnData->buffer_type) {
1680 case MYSQL_TYPE_TINY:
1681 columnValue = *(int8Type *) columnData->buffer;
1682 break;
1683 case MYSQL_TYPE_SHORT:
1684 columnValue = *(int16Type *) columnData->buffer;
1685 break;
1686 case MYSQL_TYPE_INT24:
1687 case MYSQL_TYPE_LONG:
1688 columnValue = *(int32Type *) columnData->buffer;
1689 break;
1690 case MYSQL_TYPE_LONGLONG:
1691 columnValue = *(int64Type *) columnData->buffer;
1692 break;
1693 case MYSQL_TYPE_STRING:
1694 case MYSQL_TYPE_VAR_STRING:
1695 if (unlikely(columnData->length_value != 1)) {
1696 logError(printf("sqlColumnBool: Column " FMT_D ": "
1697 "The size of a boolean field must be 1.\n", column););
1698 raise_error(RANGE_ERROR);
1699 columnValue = 0;
1700 } else {
1701 columnValue = *(const_cstriType) columnData->buffer - '0';
1702 } /* if */
1703 break;
1704 default:
1705 logError(printf("sqlColumnBool: Column " FMT_D " has the unknown type %s.\n",
1706 column, nameOfBufferType(
1707 columnData->buffer_type)););
1708 raise_error(RANGE_ERROR);
1709 columnValue = 0;
1710 break;
1711 } /* switch */
1712 if (unlikely((uint64Type) columnValue >= 2)) {
1713 logError(printf("sqlColumnBool: Column " FMT_D ": "
1714 FMT_D " is not an allowed boolean value.\n",
1715 column, columnValue););
1716 raise_error(RANGE_ERROR);
1717 } /* if */
1718 } /* if */
1719 } /* if */
1720 logFunction(printf("sqlColumnBool --> %s\n", columnValue ? "TRUE" : "FALSE"););
1721 return columnValue != 0;
1722 } /* sqlColumnBool */
1723
1724
1725
sqlColumnBStri(sqlStmtType sqlStatement,intType column)1726 static bstriType sqlColumnBStri (sqlStmtType sqlStatement, intType column)
1727
1728 {
1729 preparedStmtType preparedStmt;
1730 MYSQL_BIND *columnData;
1731 memSizeType length;
1732 bstriType columnValue;
1733
1734 /* sqlColumnBStri */
1735 logFunction(printf("sqlColumnBStri(" FMT_U_MEM ", " FMT_D ")\n",
1736 (memSizeType) sqlStatement, column););
1737 preparedStmt = (preparedStmtType) sqlStatement;
1738 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
1739 (uintType) column > preparedStmt->result_array_size)) {
1740 logError(printf("sqlColumnBStri: Fetch okay: %d, column: " FMT_D
1741 ", max column: " FMT_U_MEM ".\n",
1742 preparedStmt->fetchOkay, column,
1743 preparedStmt->result_array_size););
1744 raise_error(RANGE_ERROR);
1745 columnValue = NULL;
1746 } else {
1747 columnData = &preparedStmt->result_array[column - 1];
1748 if (columnData->is_null_value != 0) {
1749 /* printf("Column is NULL -> Use default value: \"\"\n"); */
1750 if (unlikely(!ALLOC_BSTRI_SIZE_OK(columnValue, 0))) {
1751 raise_error(MEMORY_ERROR);
1752 } else {
1753 columnValue->size = 0;
1754 } /* if */
1755 } else {
1756 /* printf("buffer_type: %s\n",
1757 nameOfBufferType(columnData->buffer_type)); */
1758 switch (columnData->buffer_type) {
1759 case MYSQL_TYPE_TINY_BLOB:
1760 case MYSQL_TYPE_BLOB:
1761 case MYSQL_TYPE_MEDIUM_BLOB:
1762 case MYSQL_TYPE_LONG_BLOB:
1763 if (!preparedStmt->result_data_array[column - 1].binary) {
1764 logError(printf("sqlColumnBStri: Column " FMT_D " is a CLOB.\n",
1765 column););
1766 raise_error(RANGE_ERROR);
1767 columnValue = NULL;
1768 } else {
1769 length = columnData->length_value;
1770 /* printf("length: %lu\n", length); */
1771 if (length > 0) {
1772 if (unlikely(!ALLOC_BSTRI_CHECK_SIZE(columnValue, length))) {
1773 raise_error(MEMORY_ERROR);
1774 columnValue = NULL;
1775 } else {
1776 columnData->buffer = columnValue->mem;
1777 columnData->buffer_length = (unsigned long) length;
1778 if (unlikely(mysql_stmt_fetch_column(preparedStmt->ppStmt,
1779 preparedStmt->result_array,
1780 (unsigned int) column - 1,
1781 0) != 0)) {
1782 setDbErrorMsg("sqlColumnBStri", "mysql_stmt_fetch_column",
1783 mysql_stmt_errno(preparedStmt->ppStmt),
1784 mysql_stmt_error(preparedStmt->ppStmt));
1785 logError(printf("sqlColumnBStri: mysql_stmt_fetch_column error: %s\n",
1786 mysql_stmt_error(preparedStmt->ppStmt)););
1787 columnData->buffer = NULL;
1788 columnData->buffer_length = 0;
1789 FREE_BSTRI(columnValue, length);
1790 raise_error(DATABASE_ERROR);
1791 columnValue = NULL;
1792 } else {
1793 columnValue->size = length;
1794 /* Restore the state that no buffer is provided. */
1795 /* This way mysql_stmt_fetch() will not fetch */
1796 /* data. Instead mysql_stmt_fetch() returns */
1797 /* MYSQL_DATA_TRUNCATED, which is ignored by */
1798 /* sqlFetch(). */
1799 columnData->buffer = NULL;
1800 columnData->buffer_length = 0;
1801 } /* if */
1802 } /* if */
1803 } else {
1804 if (unlikely(!ALLOC_BSTRI_SIZE_OK(columnValue, 0))) {
1805 raise_error(MEMORY_ERROR);
1806 } else {
1807 columnValue->size = 0;
1808 } /* if */
1809 } /* if */
1810 } /* if */
1811 break;
1812 default:
1813 logError(printf("sqlColumnBStri: Column " FMT_D " has the unknown type %s.\n",
1814 column, nameOfBufferType(
1815 columnData->buffer_type)););
1816 raise_error(RANGE_ERROR);
1817 columnValue = NULL;
1818 break;
1819 } /* switch */
1820 } /* if */
1821 } /* if */
1822 logFunction(printf("sqlColumnBStri --> \"%s\"\n", bstriAsUnquotedCStri(columnValue)););
1823 return columnValue;
1824 } /* sqlColumnBStri */
1825
1826
1827
sqlColumnDuration(sqlStmtType sqlStatement,intType column,intType * year,intType * month,intType * day,intType * hour,intType * minute,intType * second,intType * micro_second)1828 static void sqlColumnDuration (sqlStmtType sqlStatement, intType column,
1829 intType *year, intType *month, intType *day, intType *hour,
1830 intType *minute, intType *second, intType *micro_second)
1831
1832 {
1833 preparedStmtType preparedStmt;
1834 MYSQL_BIND *columnData;
1835 MYSQL_TIME *timeValue;
1836
1837 /* sqlColumnDuration */
1838 logFunction(printf("sqlColumnDuration(" FMT_U_MEM ", " FMT_D ", *)\n",
1839 (memSizeType) sqlStatement, column););
1840 preparedStmt = (preparedStmtType) sqlStatement;
1841 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
1842 (uintType) column > preparedStmt->result_array_size)) {
1843 logError(printf("sqlColumnDuration: Fetch okay: %d, column: " FMT_D
1844 ", max column: " FMT_U_MEM ".\n",
1845 preparedStmt->fetchOkay, column,
1846 preparedStmt->result_array_size););
1847 raise_error(RANGE_ERROR);
1848 } else {
1849 columnData = &preparedStmt->result_array[column - 1];
1850 if (columnData->is_null_value != 0) {
1851 /* printf("Column is NULL -> Use default value: P0D\n"); */
1852 *year = 0;
1853 *month = 0;
1854 *day = 0;
1855 *hour = 0;
1856 *minute = 0;
1857 *second = 0;
1858 *micro_second = 0;
1859 } else {
1860 /* printf("buffer_type: %s\n",
1861 nameOfBufferType(columnData->buffer_type)); */
1862 switch (columnData->buffer_type) {
1863 case MYSQL_TYPE_TIME:
1864 case MYSQL_TYPE_DATE:
1865 case MYSQL_TYPE_DATETIME:
1866 case MYSQL_TYPE_TIMESTAMP:
1867 timeValue = (MYSQL_TIME *) columnData->buffer;
1868 if (timeValue == NULL) {
1869 *year = 0;
1870 *month = 0;
1871 *day = 0;
1872 *hour = 0;
1873 *minute = 0;
1874 *second = 0;
1875 *micro_second = 0;
1876 } else {
1877 *hour = timeValue->hour;
1878 *minute = timeValue->minute;
1879 *second = timeValue->second;
1880 *micro_second = (intType) timeValue->second_part;
1881 if (timeValue->time_type == MYSQL_TIMESTAMP_DATE ||
1882 timeValue->time_type == MYSQL_TIMESTAMP_DATETIME) {
1883 *year = timeValue->year;
1884 *month = timeValue->month;
1885 *day = timeValue->day;
1886 } else {
1887 *year = 0;
1888 *month = 0;
1889 *day = 0;
1890 } /* if */
1891 if (timeValue->neg) {
1892 *year = -*year;
1893 *month = -*month;
1894 *day = -*day;
1895 *hour = -*hour;
1896 *minute = -*minute;
1897 *second = -*second;
1898 *micro_second = -*micro_second;
1899 } /* if */
1900 } /* if */
1901 break;
1902 default:
1903 logError(printf("sqlColumnDuration: Column " FMT_D " has the unknown type %s.\n",
1904 column, nameOfBufferType(
1905 columnData->buffer_type)););
1906 raise_error(RANGE_ERROR);
1907 break;
1908 } /* switch */
1909 } /* if */
1910 } /* if */
1911 logFunction(printf("sqlColumnDuration(" FMT_U_MEM ", " FMT_D ") -> P"
1912 FMT_D "Y" FMT_D "M" FMT_D "DT"
1913 FMT_D "H" FMT_D "M%s" FMT_U "." F_U(06) "S\n",
1914 (memSizeType) sqlStatement, column,
1915 *year, *month, *day, *hour, *minute,
1916 *second < 0 || *micro_second < 0 ? "-" : "",
1917 intAbs(*second), intAbs(*micro_second)););
1918 } /* sqlColumnDuration */
1919
1920
1921
sqlColumnFloat(sqlStmtType sqlStatement,intType column)1922 static floatType sqlColumnFloat (sqlStmtType sqlStatement, intType column)
1923
1924 {
1925 preparedStmtType preparedStmt;
1926 MYSQL_BIND *columnData;
1927 floatType columnValue;
1928
1929 /* sqlColumnFloat */
1930 logFunction(printf("sqlColumnFloat(" FMT_U_MEM ", " FMT_D ")\n",
1931 (memSizeType) sqlStatement, column););
1932 preparedStmt = (preparedStmtType) sqlStatement;
1933 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
1934 (uintType) column > preparedStmt->result_array_size)) {
1935 logError(printf("sqlColumnFloat: Fetch okay: %d, column: " FMT_D
1936 ", max column: " FMT_U_MEM ".\n",
1937 preparedStmt->fetchOkay, column,
1938 preparedStmt->result_array_size););
1939 raise_error(RANGE_ERROR);
1940 columnValue = 0.0;
1941 } else {
1942 columnData = &preparedStmt->result_array[column - 1];
1943 if (columnData->is_null_value != 0) {
1944 /* printf("Column is NULL -> Use default value: 0.0\n"); */
1945 columnValue = 0.0;
1946 } else {
1947 /* printf("buffer_type: %s\n",
1948 nameOfBufferType(columnData->buffer_type)); */
1949 switch (columnData->buffer_type) {
1950 case MYSQL_TYPE_TINY:
1951 columnValue = (floatType) *(int8Type *) columnData->buffer;
1952 break;
1953 case MYSQL_TYPE_SHORT:
1954 columnValue = (floatType) *(int16Type *) columnData->buffer;
1955 break;
1956 case MYSQL_TYPE_INT24:
1957 case MYSQL_TYPE_LONG:
1958 columnValue = (floatType) *(int32Type *) columnData->buffer;
1959 break;
1960 case MYSQL_TYPE_LONGLONG:
1961 columnValue = (floatType) *(int64Type *) columnData->buffer;
1962 break;
1963 case MYSQL_TYPE_FLOAT:
1964 columnValue = *(float *) columnData->buffer;
1965 if (columnValue == MOST_POSITIVE_FLOAT) {
1966 /* The IEEE 754 value infinity is stored as the most positive value. */
1967 columnValue = POSITIVE_INFINITY;
1968 } else if (columnValue == MOST_NEGATIVE_FLOAT) {
1969 /* The IEEE 754 value -infinity is stored as the most negative value. */
1970 columnValue = NEGATIVE_INFINITY;
1971 } /* if */
1972 break;
1973 case MYSQL_TYPE_DOUBLE:
1974 columnValue = *(double *) columnData->buffer;
1975 if (columnValue == MOST_POSITIVE_DOUBLE) {
1976 /* The IEEE 754 value infinity is stored as the most positive value. */
1977 columnValue = POSITIVE_INFINITY;
1978 } else if (columnValue == MOST_NEGATIVE_DOUBLE) {
1979 /* The IEEE 754 value -infinity is stored as the most negative value. */
1980 columnValue = NEGATIVE_INFINITY;
1981 } /* if */
1982 break;
1983 case MYSQL_TYPE_DECIMAL:
1984 case MYSQL_TYPE_NEWDECIMAL:
1985 columnValue = getDecimalFloat(
1986 (const_ustriType) columnData->buffer,
1987 columnData->length_value);
1988 break;
1989 default:
1990 logError(printf("sqlColumnFloat: Column " FMT_D " has the unknown type %s.\n",
1991 column, nameOfBufferType(
1992 columnData->buffer_type)););
1993 raise_error(RANGE_ERROR);
1994 columnValue = 0.0;
1995 break;
1996 } /* switch */
1997 } /* if */
1998 } /* if */
1999 logFunction(printf("sqlColumnFloat --> " FMT_E "\n", columnValue););
2000 return columnValue;
2001 } /* sqlColumnFloat */
2002
2003
2004
sqlColumnInt(sqlStmtType sqlStatement,intType column)2005 static intType sqlColumnInt (sqlStmtType sqlStatement, intType column)
2006
2007 {
2008 preparedStmtType preparedStmt;
2009 MYSQL_BIND *columnData;
2010 intType columnValue;
2011
2012 /* sqlColumnInt */
2013 logFunction(printf("sqlColumnInt(" FMT_U_MEM ", " FMT_D ")\n",
2014 (memSizeType) sqlStatement, column););
2015 preparedStmt = (preparedStmtType) sqlStatement;
2016 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
2017 (uintType) column > preparedStmt->result_array_size)) {
2018 logError(printf("sqlColumnInt: Fetch okay: %d, column: " FMT_D
2019 ", max column: " FMT_U_MEM ".\n",
2020 preparedStmt->fetchOkay, column,
2021 preparedStmt->result_array_size););
2022 raise_error(RANGE_ERROR);
2023 columnValue = 0;
2024 } else {
2025 columnData = &preparedStmt->result_array[column - 1];
2026 if (columnData->is_null_value != 0) {
2027 /* printf("Column is NULL -> Use default value: 0\n"); */
2028 columnValue = 0;
2029 } else {
2030 /* printf("buffer_type: %s\n",
2031 nameOfBufferType(columnData->buffer_type)); */
2032 switch (columnData->buffer_type) {
2033 case MYSQL_TYPE_TINY:
2034 columnValue = *(int8Type *) columnData->buffer;
2035 break;
2036 case MYSQL_TYPE_SHORT:
2037 columnValue = *(int16Type *) columnData->buffer;
2038 break;
2039 case MYSQL_TYPE_INT24:
2040 case MYSQL_TYPE_LONG:
2041 columnValue = *(int32Type *) columnData->buffer;
2042 break;
2043 case MYSQL_TYPE_LONGLONG:
2044 columnValue = *(int64Type *) columnData->buffer;
2045 break;
2046 case MYSQL_TYPE_DECIMAL:
2047 case MYSQL_TYPE_NEWDECIMAL:
2048 columnValue = getDecimalInt(
2049 (const_ustriType) columnData->buffer,
2050 columnData->length_value);
2051 break;
2052 default:
2053 logError(printf("sqlColumnInt: Column " FMT_D " has the unknown type %s.\n",
2054 column, nameOfBufferType(
2055 columnData->buffer_type)););
2056 raise_error(RANGE_ERROR);
2057 columnValue = 0;
2058 break;
2059 } /* switch */
2060 } /* if */
2061 } /* if */
2062 logFunction(printf("sqlColumnInt --> " FMT_D "\n", columnValue););
2063 return columnValue;
2064 } /* sqlColumnInt */
2065
2066
2067
sqlColumnStri(sqlStmtType sqlStatement,intType column)2068 static striType sqlColumnStri (sqlStmtType sqlStatement, intType column)
2069
2070 {
2071 preparedStmtType preparedStmt;
2072 MYSQL_BIND *columnData;
2073 cstriType utf8_stri;
2074 memSizeType length;
2075 errInfoType err_info = OKAY_NO_ERROR;
2076 striType columnValue;
2077
2078 /* sqlColumnStri */
2079 logFunction(printf("sqlColumnStri(" FMT_U_MEM ", " FMT_D ")\n",
2080 (memSizeType) sqlStatement, column););
2081 preparedStmt = (preparedStmtType) sqlStatement;
2082 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
2083 (uintType) column > preparedStmt->result_array_size)) {
2084 logError(printf("sqlColumnStri: Fetch okay: %d, column: " FMT_D
2085 ", max column: " FMT_U_MEM ".\n",
2086 preparedStmt->fetchOkay, column,
2087 preparedStmt->result_array_size););
2088 raise_error(RANGE_ERROR);
2089 columnValue = NULL;
2090 } else {
2091 columnData = &preparedStmt->result_array[column - 1];
2092 if (columnData->is_null_value != 0) {
2093 /* printf("Column is NULL -> Use default value: \"\"\n"); */
2094 columnValue = strEmpty();
2095 } else {
2096 /* printf("buffer_type: %s\n",
2097 nameOfBufferType(columnData->buffer_type)); */
2098 switch (columnData->buffer_type) {
2099 case MYSQL_TYPE_VAR_STRING:
2100 case MYSQL_TYPE_STRING:
2101 utf8_stri = (cstriType) columnData->buffer;
2102 length = columnData->length_value;
2103 if (utf8_stri == NULL) {
2104 columnValue = strEmpty();
2105 } else {
2106 columnValue = cstri8_buf_to_stri(utf8_stri, length, &err_info);
2107 if (unlikely(columnValue == NULL)) {
2108 raise_error(err_info);
2109 } /* if */
2110 } /* if */
2111 break;
2112 case MYSQL_TYPE_TINY_BLOB:
2113 case MYSQL_TYPE_BLOB:
2114 case MYSQL_TYPE_MEDIUM_BLOB:
2115 case MYSQL_TYPE_LONG_BLOB:
2116 length = columnData->length_value;
2117 /* printf("length: %lu\n", length); */
2118 if (length > 0) {
2119 if (preparedStmt->result_data_array[column - 1].binary) {
2120 if (unlikely(!ALLOC_STRI_CHECK_SIZE(columnValue, length))) {
2121 err_info = MEMORY_ERROR;
2122 } else {
2123 columnData->buffer = columnValue->mem;
2124 columnData->buffer_length = (unsigned long) length;
2125 if (unlikely(mysql_stmt_fetch_column(preparedStmt->ppStmt,
2126 preparedStmt->result_array,
2127 (unsigned int) column - 1,
2128 0) != 0)) {
2129 setDbErrorMsg("sqlColumnStri", "mysql_stmt_fetch_column",
2130 mysql_stmt_errno(preparedStmt->ppStmt),
2131 mysql_stmt_error(preparedStmt->ppStmt));
2132 logError(printf("sqlColumnStri: mysql_stmt_fetch_column error: %s\n",
2133 mysql_stmt_error(preparedStmt->ppStmt)););
2134 FREE_STRI(columnValue, length);
2135 err_info = DATABASE_ERROR;
2136 } else {
2137 columnValue->size = length;
2138 memcpy_to_strelem(columnValue->mem,
2139 (ustriType) columnValue->mem, length);
2140 } /* if */
2141 } /* if */
2142 } else {
2143 if (unlikely(!ALLOC_BYTES(utf8_stri, length))) {
2144 err_info = MEMORY_ERROR;
2145 columnValue = NULL;
2146 } else {
2147 columnData->buffer = utf8_stri;
2148 columnData->buffer_length = (unsigned long) length;
2149 if (unlikely(mysql_stmt_fetch_column(preparedStmt->ppStmt,
2150 preparedStmt->result_array,
2151 (unsigned int) column - 1,
2152 0) != 0)) {
2153 setDbErrorMsg("sqlColumnStri", "mysql_stmt_fetch_column",
2154 mysql_stmt_errno(preparedStmt->ppStmt),
2155 mysql_stmt_error(preparedStmt->ppStmt));
2156 logError(printf("sqlColumnStri: mysql_stmt_fetch_column error: %s\n",
2157 mysql_stmt_error(preparedStmt->ppStmt)););
2158 FREE_BYTES(utf8_stri, length);
2159 err_info = DATABASE_ERROR;
2160 columnValue = NULL;
2161 } else {
2162 columnValue = cstri8_buf_to_stri(utf8_stri, length, &err_info);
2163 FREE_BYTES(utf8_stri, length);
2164 } /* if */
2165 } /* if */
2166 } /* if */
2167 /* Restore the state that no buffer is provided. */
2168 /* This way mysql_stmt_fetch() will not fetch */
2169 /* data. Instead mysql_stmt_fetch() returns */
2170 /* MYSQL_DATA_TRUNCATED, which is ignored by */
2171 /* sqlFetch(). */
2172 columnData->buffer = NULL;
2173 columnData->buffer_length = 0;
2174 if (unlikely(err_info != OKAY_NO_ERROR)) {
2175 raise_error(err_info);
2176 columnValue = NULL;
2177 } /* if */
2178 } else {
2179 columnValue = strEmpty();
2180 } /* if */
2181 break;
2182 default:
2183 logError(printf("sqlColumnStri: Column " FMT_D " has the unknown type %s.\n",
2184 column, nameOfBufferType(
2185 columnData->buffer_type)););
2186 raise_error(RANGE_ERROR);
2187 columnValue = NULL;
2188 break;
2189 } /* switch */
2190 } /* if */
2191 } /* if */
2192 logFunction(printf("sqlColumnStri --> \"%s\"\n", striAsUnquotedCStri(columnValue)););
2193 return columnValue;
2194 } /* sqlColumnStri */
2195
2196
2197
sqlColumnTime(sqlStmtType sqlStatement,intType column,intType * year,intType * month,intType * day,intType * hour,intType * minute,intType * second,intType * micro_second,intType * time_zone,boolType * is_dst)2198 static void sqlColumnTime (sqlStmtType sqlStatement, intType column,
2199 intType *year, intType *month, intType *day, intType *hour,
2200 intType *minute, intType *second, intType *micro_second,
2201 intType *time_zone, boolType *is_dst)
2202
2203 {
2204 preparedStmtType preparedStmt;
2205 MYSQL_BIND *columnData;
2206 MYSQL_TIME *timeValue;
2207
2208 /* sqlColumnTime */
2209 logFunction(printf("sqlColumnTime(" FMT_U_MEM ", " FMT_D ", *)\n",
2210 (memSizeType) sqlStatement, column););
2211 preparedStmt = (preparedStmtType) sqlStatement;
2212 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
2213 (uintType) column > preparedStmt->result_array_size)) {
2214 logError(printf("sqlColumnTime: Fetch okay: %d, column: " FMT_D
2215 ", max column: " FMT_U_MEM ".\n",
2216 preparedStmt->fetchOkay, column,
2217 preparedStmt->result_array_size););
2218 raise_error(RANGE_ERROR);
2219 } else {
2220 columnData = &preparedStmt->result_array[column - 1];
2221 if (columnData->is_null_value != 0) {
2222 /* printf("Column is NULL -> Use default value: 0-01-01 00:00:00\n"); */
2223 *year = 0;
2224 *month = 1;
2225 *day = 1;
2226 *hour = 0;
2227 *minute = 0;
2228 *second = 0;
2229 *micro_second = 0;
2230 *time_zone = 0;
2231 *is_dst = 0;
2232 } else {
2233 /* printf("buffer_type: %s\n",
2234 nameOfBufferType(columnData->buffer_type)); */
2235 switch (columnData->buffer_type) {
2236 case MYSQL_TYPE_TIME:
2237 case MYSQL_TYPE_DATE:
2238 case MYSQL_TYPE_DATETIME:
2239 case MYSQL_TYPE_TIMESTAMP:
2240 timeValue = (MYSQL_TIME *) columnData->buffer;
2241 if (timeValue == NULL) {
2242 *year = 0;
2243 *month = 1;
2244 *day = 1;
2245 *hour = 0;
2246 *minute = 0;
2247 *second = 0;
2248 *micro_second = 0;
2249 *time_zone = 0;
2250 *is_dst = 0;
2251 } else {
2252 /* printf("timeValue->time_type: %d\n", timeValue->time_type); */
2253 *hour = timeValue->hour;
2254 *minute = timeValue->minute;
2255 *second = timeValue->second;
2256 *micro_second = (intType) timeValue->second_part;
2257 if ((columnData->buffer_type != MYSQL_TYPE_TIME ||
2258 timeValue->time_type == MYSQL_TIMESTAMP_DATE ||
2259 timeValue->time_type == MYSQL_TIMESTAMP_DATETIME) &&
2260 timeValue->month != 0 && timeValue->day != 0) {
2261 /* For 00:00:00 buffer_type is always MYSQL_TYPE_TIME. But */
2262 /* for this time time_type might be MYSQL_TIMESTAMP_DATE. */
2263 /* In this case month and day are both zero. The condition */
2264 /* above corrects this bug. */
2265 *year = timeValue->year;
2266 *month = timeValue->month;
2267 *day = timeValue->day;
2268 timSetLocalTZ(*year, *month, *day, *hour, *minute, *second,
2269 time_zone, is_dst);
2270 } else {
2271 *year = 2000;
2272 *month = 1;
2273 *day = 1;
2274 /* It actually happens that hour is outside */
2275 /* of the allowed range from 0 to 23. */
2276 if (*hour >= 24) {
2277 *hour = *hour % 24;
2278 } else if (*hour < 0) {
2279 *hour = *hour % 24;
2280 if (*hour != 0) {
2281 *hour += 24;
2282 } /* if */
2283 } /* if */
2284 timSetLocalTZ(*year, *month, *day, *hour, *minute, *second,
2285 time_zone, is_dst);
2286 *year = 0;
2287 } /* if */
2288 } /* if */
2289 break;
2290 default:
2291 logError(printf("sqlColumnTime: Column " FMT_D " has the unknown type %s.\n",
2292 column, nameOfBufferType(
2293 columnData->buffer_type)););
2294 raise_error(RANGE_ERROR);
2295 break;
2296 } /* switch */
2297 } /* if */
2298 } /* if */
2299 logFunction(printf("sqlColumnTime(" FMT_U_MEM ", " FMT_D ", "
2300 F_D(04) "-" F_D(02) "-" F_D(02) " "
2301 F_D(02) ":" F_D(02) ":" F_D(02) "."
2302 F_D(06) ", " FMT_D ", %d) -->\n",
2303 (memSizeType) sqlStatement, column,
2304 *year, *month, *day, *hour, *minute, *second,
2305 *micro_second, *time_zone, *is_dst););
2306 } /* sqlColumnTime */
2307
2308
2309
sqlCommit(databaseType database)2310 static void sqlCommit (databaseType database)
2311
2312 {
2313 dbType db;
2314
2315 /* sqlCommit */
2316 logFunction(printf("sqlCommit(" FMT_U_MEM ")\n",
2317 (memSizeType) database););
2318 db = (dbType) database;
2319 if (unlikely(mysql_commit(db->connection) != 0)) {
2320 setDbErrorMsg("sqlCommit", "mysql_commit",
2321 mysql_errno(db->connection),
2322 mysql_error(db->connection));
2323 logError(printf("sqlCommit: mysql_commit error: %s\n",
2324 mysql_error(db->connection)););
2325 raise_error(DATABASE_ERROR);
2326 } /* if */
2327 logFunction(printf("sqlCommit -->\n"););
2328 } /* sqlCommit */
2329
2330
2331
sqlExecute(sqlStmtType sqlStatement)2332 static void sqlExecute (sqlStmtType sqlStatement)
2333
2334 {
2335 preparedStmtType preparedStmt;
2336
2337 /* sqlExecute */
2338 logFunction(printf("sqlExecute(" FMT_U_MEM ")\n",
2339 (memSizeType) sqlStatement););
2340 preparedStmt = (preparedStmtType) sqlStatement;
2341 if (unlikely(!allParametersBound(preparedStmt))) {
2342 dbLibError("sqlExecute", "SQLExecute",
2343 "Unbound statement parameter(s).\n");
2344 raise_error(DATABASE_ERROR);
2345 } else {
2346 /* printf("ppStmt: " FMT_U_MEM "\n", (memSizeType) preparedStmt->ppStmt); */
2347 preparedStmt->fetchOkay = FALSE;
2348 if (unlikely(mysql_stmt_bind_param(preparedStmt->ppStmt,
2349 preparedStmt->param_array) != 0)) {
2350 setDbErrorMsg("sqlExecute", "mysql_stmt_bind_param",
2351 mysql_stmt_errno(preparedStmt->ppStmt),
2352 mysql_stmt_error(preparedStmt->ppStmt));
2353 logError(printf("sqlExecute: mysql_stmt_bind_param error: %s\n",
2354 mysql_stmt_error(preparedStmt->ppStmt)););
2355 preparedStmt->executeSuccessful = FALSE;
2356 raise_error(DATABASE_ERROR);
2357 } else if (unlikely(mysql_stmt_execute(preparedStmt->ppStmt) != 0)) {
2358 setDbErrorMsg("sqlExecute", "mysql_stmt_execute",
2359 mysql_stmt_errno(preparedStmt->ppStmt),
2360 mysql_stmt_error(preparedStmt->ppStmt));
2361 logError(printf("sqlExecute: mysql_stmt_execute error: %s\n",
2362 mysql_stmt_error(preparedStmt->ppStmt)););
2363 preparedStmt->executeSuccessful = FALSE;
2364 raise_error(DATABASE_ERROR);
2365 } else if (unlikely(preparedStmt->result_array_size != 0 &&
2366 mysql_stmt_bind_result(preparedStmt->ppStmt,
2367 preparedStmt->result_array) != 0)) {
2368 setDbErrorMsg("sqlExecute", "mysql_stmt_bind_result",
2369 mysql_stmt_errno(preparedStmt->ppStmt),
2370 mysql_stmt_error(preparedStmt->ppStmt));
2371 logError(printf("sqlExecute: mysql_stmt_bind_result error: %s\n",
2372 mysql_stmt_error(preparedStmt->ppStmt)););
2373 preparedStmt->executeSuccessful = FALSE;
2374 raise_error(DATABASE_ERROR);
2375 } else if (unlikely(mysql_stmt_store_result(preparedStmt->ppStmt) != 0)) {
2376 setDbErrorMsg("sqlExecute", "mysql_stmt_store_result",
2377 mysql_stmt_errno(preparedStmt->ppStmt),
2378 mysql_stmt_error(preparedStmt->ppStmt));
2379 logError(printf("sqlExecute: mysql_stmt_store_result error: %s\n",
2380 mysql_stmt_error(preparedStmt->ppStmt)););
2381 preparedStmt->executeSuccessful = FALSE;
2382 raise_error(DATABASE_ERROR);
2383 } else {
2384 preparedStmt->executeSuccessful = TRUE;
2385 preparedStmt->fetchFinished = FALSE;
2386 } /* if */
2387 } /* if */
2388 logFunction(printf("sqlExecute -->\n"););
2389 } /* sqlExecute */
2390
2391
2392
sqlFetch(sqlStmtType sqlStatement)2393 static boolType sqlFetch (sqlStmtType sqlStatement)
2394
2395 {
2396 preparedStmtType preparedStmt;
2397 int fetch_result;
2398
2399 /* sqlFetch */
2400 logFunction(printf("sqlFetch(" FMT_U_MEM ")\n",
2401 (memSizeType) sqlStatement););
2402 preparedStmt = (preparedStmtType) sqlStatement;
2403 if (unlikely(!preparedStmt->executeSuccessful)) {
2404 dbLibError("sqlFetch", "mysql_stmt_execute",
2405 "Execute was not successful.\n");
2406 logError(printf("sqlFetch: Execute was not successful.\n"););
2407 preparedStmt->fetchOkay = FALSE;
2408 raise_error(DATABASE_ERROR);
2409 } else if (preparedStmt->result_array_size == 0) {
2410 preparedStmt->fetchOkay = FALSE;
2411 } else if (!preparedStmt->fetchFinished) {
2412 /* printf("ppStmt: " FMT_U_MEM "\n", (memSizeType) preparedStmt->ppStmt); */
2413 fetch_result = mysql_stmt_fetch(preparedStmt->ppStmt);
2414 if (fetch_result == 0) {
2415 preparedStmt->fetchOkay = TRUE;
2416 } else if (fetch_result == MYSQL_DATA_TRUNCATED) {
2417 /* For BLOBs buffer == NULL and buffer_length == 0 holds. */
2418 /* Therefore BLOBs are truncated (MYSQL_DATA_TRUNCATED). */
2419 /* Instead BLOBs are fetched with mysql_stmt_fetch_column(). */
2420 preparedStmt->fetchOkay = TRUE;
2421 } else if (fetch_result == MYSQL_NO_DATA) {
2422 preparedStmt->fetchOkay = FALSE;
2423 preparedStmt->fetchFinished = TRUE;
2424 } else {
2425 setDbErrorMsg("sqlFetch", "mysql_stmt_fetch",
2426 mysql_stmt_errno(preparedStmt->ppStmt),
2427 mysql_stmt_error(preparedStmt->ppStmt));
2428 logError(printf("sqlFetch: mysql_stmt_fetch returns %d: %s\n",
2429 fetch_result, dbError.message););
2430 preparedStmt->fetchOkay = FALSE;
2431 preparedStmt->fetchFinished = TRUE;
2432 raise_error(DATABASE_ERROR);
2433 } /* if */
2434 } /* if */
2435 logFunction(printf("sqlFetch --> %d\n", preparedStmt->fetchOkay););
2436 return preparedStmt->fetchOkay;
2437 } /* sqlFetch */
2438
2439
2440
sqlGetAutoCommit(databaseType database)2441 static boolType sqlGetAutoCommit (databaseType database)
2442
2443 {
2444 dbType db;
2445 boolType autoCommit;
2446
2447 /* sqlGetAutoCommit */
2448 logFunction(printf("sqlGetAutoCommit(" FMT_U_MEM ")\n",
2449 (memSizeType) database););
2450 db = (dbType) database;
2451 /* There seems to be no function to retrieve the current */
2452 /* autocommit mode. Therefore the mode is retrieved from the db. */
2453 autoCommit = db->autoCommit;
2454 logFunction(printf("sqlGetAutoCommit --> %d\n", autoCommit););
2455 return autoCommit;
2456 } /* sqlGetAutoCommit */
2457
2458
2459
sqlIsNull(sqlStmtType sqlStatement,intType column)2460 static boolType sqlIsNull (sqlStmtType sqlStatement, intType column)
2461
2462 {
2463 preparedStmtType preparedStmt;
2464 boolType isNull;
2465
2466 /* sqlIsNull */
2467 logFunction(printf("sqlIsNull(" FMT_U_MEM ", " FMT_D ")\n",
2468 (memSizeType) sqlStatement, column););
2469 preparedStmt = (preparedStmtType) sqlStatement;
2470 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
2471 (uintType) column > preparedStmt->result_array_size)) {
2472 logError(printf("sqlIsNull: Fetch okay: %d, column: " FMT_D
2473 ", max column: " FMT_U_MEM ".\n",
2474 preparedStmt->fetchOkay, column,
2475 preparedStmt->result_array_size););
2476 raise_error(RANGE_ERROR);
2477 isNull = FALSE;
2478 } else {
2479 isNull = preparedStmt->result_array[column - 1].is_null_value != 0;
2480 } /* if */
2481 logFunction(printf("sqlIsNull --> %s\n", isNull ? "TRUE" : "FALSE"););
2482 return isNull;
2483 } /* sqlIsNull */
2484
2485
2486
sqlPrepare(databaseType database,const const_striType sqlStatementStri)2487 static sqlStmtType sqlPrepare (databaseType database,
2488 const const_striType sqlStatementStri)
2489
2490 {
2491 dbType db;
2492 striType statementStri;
2493 cstriType query;
2494 memSizeType queryLength;
2495 int prepare_result;
2496 errInfoType err_info = OKAY_NO_ERROR;
2497 preparedStmtType preparedStmt;
2498
2499 /* sqlPrepare */
2500 logFunction(printf("sqlPrepare(" FMT_U_MEM ", \"%s\")\n",
2501 (memSizeType) database,
2502 striAsUnquotedCStri(sqlStatementStri)););
2503 db = (dbType) database;
2504 if (db->connection == NULL) {
2505 logError(printf("sqlPrepare: Database is not open.\n"););
2506 err_info = RANGE_ERROR;
2507 preparedStmt = NULL;
2508 } else {
2509 statementStri = processStatementStri(sqlStatementStri, db->backslashEscapes);
2510 if (unlikely(statementStri == NULL)) {
2511 err_info = MEMORY_ERROR;
2512 preparedStmt = NULL;
2513 } else {
2514 query = stri_to_cstri8_buf(statementStri, &queryLength);
2515 if (unlikely(query == NULL)) {
2516 err_info = MEMORY_ERROR;
2517 preparedStmt = NULL;
2518 } else {
2519 if (unlikely(queryLength > ULONG_MAX)) {
2520 /* It is not possible to cast queryLength to unsigned long. */
2521 logError(printf("sqlPrepare: Statement string too long (length = " FMT_U_MEM ")\n",
2522 queryLength););
2523 err_info = RANGE_ERROR;
2524 preparedStmt = NULL;
2525 } else if (unlikely(!ALLOC_RECORD2(preparedStmt, preparedStmtRecord,
2526 count.prepared_stmt, count.prepared_stmt_bytes))) {
2527 err_info = MEMORY_ERROR;
2528 } else {
2529 memset(preparedStmt, 0, sizeof(preparedStmtRecord));
2530 preparedStmt->ppStmt = mysql_stmt_init(db->connection);
2531 if (preparedStmt->ppStmt == NULL) {
2532 setDbErrorMsg("sqlPrepare", "mysql_stmt_init",
2533 mysql_errno(db->connection),
2534 mysql_error(db->connection));
2535 logError(printf("sqlPrepare: mysql_stmt_init error: %s\n",
2536 mysql_error(db->connection)););
2537 FREE_RECORD2(preparedStmt, preparedStmtRecord,
2538 count.prepared_stmt, count.prepared_stmt_bytes);
2539 err_info = DATABASE_ERROR;
2540 preparedStmt = NULL;
2541 } else {
2542 prepare_result = mysql_stmt_prepare(preparedStmt->ppStmt,
2543 query,
2544 (unsigned long) queryLength);
2545 if (prepare_result != 0) {
2546 setDbErrorMsg("sqlPrepare", "mysql_stmt_prepare",
2547 mysql_stmt_errno(preparedStmt->ppStmt),
2548 mysql_stmt_error(preparedStmt->ppStmt));
2549 logError(printf("sqlPrepare: mysql_stmt_prepare error: %s\n",
2550 mysql_stmt_error(preparedStmt->ppStmt)););
2551 mysql_stmt_close(preparedStmt->ppStmt);
2552 FREE_RECORD2(preparedStmt, preparedStmtRecord,
2553 count.prepared_stmt, count.prepared_stmt_bytes);
2554 err_info = DATABASE_ERROR;
2555 preparedStmt = NULL;
2556 } else {
2557 preparedStmt->usage_count = 1;
2558 preparedStmt->sqlFunc = db->sqlFunc;
2559 preparedStmt->executeSuccessful = FALSE;
2560 preparedStmt->fetchOkay = FALSE;
2561 preparedStmt->fetchFinished = TRUE;
2562 err_info = setupParameters(preparedStmt);
2563 if (unlikely(err_info != OKAY_NO_ERROR)) {
2564 preparedStmt->result_array = NULL;
2565 } else {
2566 err_info = setupResult(preparedStmt);
2567 } /* if */
2568 if (unlikely(err_info != OKAY_NO_ERROR)) {
2569 freePreparedStmt((sqlStmtType) preparedStmt);
2570 preparedStmt = NULL;
2571 } /* if */
2572 } /* if */
2573 } /* if */
2574 } /* if */
2575 free_cstri8(query, statementStri);
2576 } /* if */
2577 FREE_STRI(statementStri, sqlStatementStri->size * 2);
2578 } /* if */
2579 } /* if */
2580 if (unlikely(err_info != OKAY_NO_ERROR)) {
2581 raise_error(err_info);
2582 } /* if */
2583 logFunction(printf("sqlPrepare --> " FMT_U_MEM "\n",
2584 (memSizeType) preparedStmt););
2585 return (sqlStmtType) preparedStmt;
2586 } /* sqlPrepare */
2587
2588
2589
sqlRollback(databaseType database)2590 static void sqlRollback (databaseType database)
2591
2592 {
2593 dbType db;
2594
2595 /* sqlRollback */
2596 logFunction(printf("sqlRollback(" FMT_U_MEM ")\n",
2597 (memSizeType) database););
2598 db = (dbType) database;
2599 if (unlikely(mysql_rollback(db->connection) != 0)) {
2600 setDbErrorMsg("sqlRollback", "mysql_rollback",
2601 mysql_errno(db->connection),
2602 mysql_error(db->connection));
2603 logError(printf("sqlRollback: mysql_rollback error: %s\n",
2604 mysql_error(db->connection)););
2605 raise_error(DATABASE_ERROR);
2606 } /* if */
2607 logFunction(printf("sqlRollback -->\n"););
2608 } /* sqlRollback */
2609
2610
2611
sqlSetAutoCommit(databaseType database,boolType autoCommit)2612 static void sqlSetAutoCommit (databaseType database, boolType autoCommit)
2613
2614 {
2615 dbType db;
2616
2617 /* sqlSetAutoCommit */
2618 logFunction(printf("sqlSetAutoCommit(" FMT_U_MEM ", %d)\n",
2619 (memSizeType) database, autoCommit););
2620 db = (dbType) database;
2621 if (unlikely(mysql_autocommit(db->connection, autoCommit) != 0)) {
2622 setDbErrorMsg("sqlSetAutoCommit", "mysql_autocommit",
2623 mysql_errno(db->connection),
2624 mysql_error(db->connection));
2625 logError(printf("sqlSetAutoCommit: mysql_autocommit: %s\n",
2626 mysql_error(db->connection)););
2627 raise_error(DATABASE_ERROR);
2628 } else {
2629 /* There seems to be no function to retrieve the current */
2630 /* autocommit mode. Therefore the mode is stored in the db. */
2631 db->autoCommit = autoCommit;
2632 } /* if */
2633 logFunction(printf("sqlSetAutoCommit -->\n"););
2634 } /* sqlSetAutoCommit */
2635
2636
2637
sqlStmtColumnCount(sqlStmtType sqlStatement)2638 static intType sqlStmtColumnCount (sqlStmtType sqlStatement)
2639
2640 {
2641 preparedStmtType preparedStmt;
2642 intType columnCount;
2643
2644 /* sqlStmtColumnCount */
2645 logFunction(printf("sqlStmtColumnCount(" FMT_U_MEM ")\n",
2646 (memSizeType) sqlStatement););
2647 preparedStmt = (preparedStmtType) sqlStatement;
2648 if (unlikely(preparedStmt->result_array_size > INTTYPE_MAX)) {
2649 logError(printf("sqlStmtColumnCount: "
2650 "Result_array_size does not fit into an integer.\n"););
2651 raise_error(RANGE_ERROR);
2652 columnCount = 0;
2653 } else {
2654 columnCount = (intType) preparedStmt->result_array_size;
2655 } /* if */
2656 logFunction(printf("sqlStmtColumnCount --> " FMT_D "\n", columnCount););
2657 return columnCount;
2658 } /* sqlStmtColumnCount */
2659
2660
2661
sqlStmtColumnName(sqlStmtType sqlStatement,intType column)2662 static striType sqlStmtColumnName (sqlStmtType sqlStatement, intType column)
2663
2664 {
2665 preparedStmtType preparedStmt;
2666 const_cstriType col_name;
2667 errInfoType err_info = OKAY_NO_ERROR;
2668 striType name;
2669
2670 /* sqlStmtColumnName */
2671 logFunction(printf("sqlStmtColumnName(" FMT_U_MEM ", " FMT_D ")\n",
2672 (memSizeType) sqlStatement, column););
2673 preparedStmt = (preparedStmtType) sqlStatement;
2674 if (unlikely(column < 1 ||
2675 (uintType) column > preparedStmt->result_array_size)) {
2676 logError(printf("sqlStmtColumnName: column: " FMT_D
2677 ", max column: " FMT_U_MEM ".\n",
2678 column, preparedStmt->result_array_size););
2679 raise_error(RANGE_ERROR);
2680 name = NULL;
2681 } else {
2682 col_name = preparedStmt->result_data_array[column - 1].name;
2683 if (unlikely(col_name == NULL)) {
2684 dbInconsistent("sqlStmtColumnName", "mysql_fetch_field_direct");
2685 logError(printf("sqlStmtColumnName: Column " FMT_D ": "
2686 "Column name is NULL.\n", column););
2687 raise_error(DATABASE_ERROR);
2688 name = NULL;
2689 } else {
2690 name = cstri8_to_stri(col_name, &err_info);
2691 if (unlikely(name == NULL)) {
2692 raise_error(err_info);
2693 } /* if */
2694 } /* if */
2695 } /* if */
2696 logFunction(printf("sqlStmtColumnName --> \"%s\"\n",
2697 striAsUnquotedCStri(name)););
2698 return name;
2699 } /* sqlStmtColumnName */
2700
2701
2702
2703 #if 0
2704 static rtlTypeType sqlStmtColumnType (sqlStmtType sqlStatement, intType column)
2705
2706 {
2707 preparedStmtType preparedStmt;
2708 const_cstriType col_name;
2709 errInfoType err_info = OKAY_NO_ERROR;
2710 rtlTypeType columnType;
2711
2712 /* sqlStmtColumnType */
2713 logFunction(printf("sqlStmtColumnType(" FMT_U_MEM ", " FMT_D ")\n",
2714 (memSizeType) sqlStatement, column); */
2715 preparedStmt = (preparedStmtType) sqlStatement;
2716 if (unlikely(column < 1 ||
2717 (uintType) column > preparedStmt->result_array_size)) {
2718 logError(printf("sqlStmtColumnType: column: " FMT_D
2719 ", max column: " FMT_U_MEM ".\n",
2720 column, preparedStmt->result_array_size););
2721 raise_error(RANGE_ERROR);
2722 columnType = SYS_VOID_TYPE;
2723 } else {
2724 columnData = &preparedStmt->result_array[column - 1];
2725 switch (columnData->buffer_type) {
2726 case MYSQL_TYPE_TINY:
2727 case MYSQL_TYPE_SHORT:
2728 case MYSQL_TYPE_INT24:
2729 case MYSQL_TYPE_LONG:
2730 case MYSQL_TYPE_LONGLONG:
2731 columnType = SYS_INT_TYPE;
2732 break;
2733 case MYSQL_TYPE_FLOAT:
2734 case MYSQL_TYPE_DOUBLE:
2735 columnType = SYS_FLOAT_TYPE;
2736 break;
2737 case MYSQL_TYPE_DECIMAL:
2738 case MYSQL_TYPE_NEWDECIMAL:
2739 columnType = SYS_BIGINT_TYPE;
2740 break;
2741 case MYSQL_TYPE_TIME:
2742 case MYSQL_TYPE_DATE:
2743 case MYSQL_TYPE_NEWDATE:
2744 case MYSQL_TYPE_DATETIME:
2745 case MYSQL_TYPE_TIMESTAMP:
2746 columnType = SYS_VOID_TYPE;
2747 break;
2748 case MYSQL_TYPE_VARCHAR:
2749 case MYSQL_TYPE_STRING:
2750 case MYSQL_TYPE_VAR_STRING:
2751 columnType = SYS_STRI_TYPE;
2752 break;
2753 case MYSQL_TYPE_TINY_BLOB:
2754 case MYSQL_TYPE_BLOB:
2755 case MYSQL_TYPE_MEDIUM_BLOB:
2756 case MYSQL_TYPE_LONG_BLOB:
2757 columnType = SYS_BSTRI_TYPE;
2758 break;
2759 case MYSQL_TYPE_BIT:
2760 case MYSQL_TYPE_YEAR:
2761 case MYSQL_TYPE_SET:
2762 case MYSQL_TYPE_ENUM:
2763 case MYSQL_TYPE_GEOMETRY:
2764 case MYSQL_TYPE_NULL:
2765 columnType = SYS_VOID_TYPE;
2766 break;
2767 default:
2768 logError(printf("sqlStmtColumnType: Column " FMT_D " has the unknown type %s.\n",
2769 column, nameOfBufferType(
2770 columnData->buffer_type)););
2771 raise_error(RANGE_ERROR);
2772 columnType = SYS_VOID_TYPE;
2773 break;
2774 } /* switch */
2775 } /* if */
2776 return columnType;
2777 } /* sqlStmtColumnType */
2778 #endif
2779
2780
2781
setupFuncTable(void)2782 static boolType setupFuncTable (void)
2783
2784 { /* setupFuncTable */
2785 if (sqlFunc == NULL) {
2786 if (ALLOC_RECORD(sqlFunc, sqlFuncRecord, count.sql_func)) {
2787 memset(sqlFunc, 0, sizeof(sqlFuncRecord));
2788 sqlFunc->freeDatabase = &freeDatabase;
2789 sqlFunc->freePreparedStmt = &freePreparedStmt;
2790 sqlFunc->sqlBindBigInt = &sqlBindBigInt;
2791 sqlFunc->sqlBindBigRat = &sqlBindBigRat;
2792 sqlFunc->sqlBindBool = &sqlBindBool;
2793 sqlFunc->sqlBindBStri = &sqlBindBStri;
2794 sqlFunc->sqlBindDuration = &sqlBindDuration;
2795 sqlFunc->sqlBindFloat = &sqlBindFloat;
2796 sqlFunc->sqlBindInt = &sqlBindInt;
2797 sqlFunc->sqlBindNull = &sqlBindNull;
2798 sqlFunc->sqlBindStri = &sqlBindStri;
2799 sqlFunc->sqlBindTime = &sqlBindTime;
2800 sqlFunc->sqlClose = &sqlClose;
2801 sqlFunc->sqlColumnBigInt = &sqlColumnBigInt;
2802 sqlFunc->sqlColumnBigRat = &sqlColumnBigRat;
2803 sqlFunc->sqlColumnBool = &sqlColumnBool;
2804 sqlFunc->sqlColumnBStri = &sqlColumnBStri;
2805 sqlFunc->sqlColumnDuration = &sqlColumnDuration;
2806 sqlFunc->sqlColumnFloat = &sqlColumnFloat;
2807 sqlFunc->sqlColumnInt = &sqlColumnInt;
2808 sqlFunc->sqlColumnStri = &sqlColumnStri;
2809 sqlFunc->sqlColumnTime = &sqlColumnTime;
2810 sqlFunc->sqlCommit = &sqlCommit;
2811 sqlFunc->sqlExecute = &sqlExecute;
2812 sqlFunc->sqlFetch = &sqlFetch;
2813 sqlFunc->sqlGetAutoCommit = &sqlGetAutoCommit;
2814 sqlFunc->sqlIsNull = &sqlIsNull;
2815 sqlFunc->sqlPrepare = &sqlPrepare;
2816 sqlFunc->sqlRollback = &sqlRollback;
2817 sqlFunc->sqlSetAutoCommit = &sqlSetAutoCommit;
2818 sqlFunc->sqlStmtColumnCount = &sqlStmtColumnCount;
2819 sqlFunc->sqlStmtColumnName = &sqlStmtColumnName;
2820 } /* if */
2821 } /* if */
2822 return sqlFunc != NULL;
2823 } /* setupFuncTable */
2824
2825
2826
determineIfBackslashEscapes(dbType database)2827 static void determineIfBackslashEscapes (dbType database)
2828
2829 {
2830 striType statementStri;
2831 sqlStmtType preparedStmt;
2832 striType data;
2833
2834 /* determineIfBackslashEscapes */
2835 database->backslashEscapes = FALSE;
2836 statementStri = cstri_to_stri("SELECT '\\\\'");
2837 if (likely(statementStri != NULL)) {
2838 preparedStmt = sqlPrepare((databaseType) database, statementStri);
2839 if (likely(preparedStmt != NULL)) {
2840 sqlExecute(preparedStmt);
2841 if (likely(sqlFetch(preparedStmt))) {
2842 data = sqlColumnStri(preparedStmt, 1);
2843 if (data->size == 1 && data->mem[0] == '\\') {
2844 /* A select for two backslashes returns just one backslash. */
2845 /* This happens if the database uses backslash as escape char. */
2846 database->backslashEscapes = TRUE;
2847 } /* if */
2848 FREE_STRI(data, data->size);
2849 } /* if */
2850 freePreparedStmt(preparedStmt);
2851 } /* if */
2852 FREE_STRI(statementStri, statementStri->size);
2853 } /* if */
2854 /* printf("backslashEscapes: %d\n", database->backslashEscapes); */
2855 } /* determineIfBackslashEscapes */
2856
2857
2858
sqlOpenMy(const const_striType host,intType port,const const_striType dbName,const const_striType user,const const_striType password)2859 databaseType sqlOpenMy (const const_striType host, intType port,
2860 const const_striType dbName, const const_striType user,
2861 const const_striType password)
2862
2863 {
2864 const_cstriType host8;
2865 const_cstriType dbName8;
2866 const_cstriType user8;
2867 const_cstriType password8;
2868 MYSQL *connection;
2869 MYSQL *connect_result;
2870 errInfoType err_info = OKAY_NO_ERROR;
2871 dbType database;
2872
2873 /* sqlOpenMy */
2874 logFunction(printf("sqlOpenMy(\"%s\", ",
2875 striAsUnquotedCStri(host));
2876 printf(FMT_D ", \"%s\", ",
2877 port, striAsUnquotedCStri(dbName));
2878 printf("\"%s\", ", striAsUnquotedCStri(user));
2879 printf("\"%s\")\n", striAsUnquotedCStri(password)););
2880 if (!findDll()) {
2881 logError(printf("sqlOpenMy: findDll() failed\n"););
2882 err_info = DATABASE_ERROR;
2883 database = NULL;
2884 } else if (unlikely(port < 0 || port > UINT_MAX)) {
2885 err_info = RANGE_ERROR;
2886 database = NULL;
2887 } else if (unlikely((host8 = stri_to_cstri8(host, &err_info)) == NULL)) {
2888 database = NULL;
2889 } else {
2890 dbName8 = stri_to_cstri8(dbName, &err_info);
2891 if (unlikely(dbName8 == NULL)) {
2892 database = NULL;
2893 } else {
2894 user8 = stri_to_cstri8(user, &err_info);
2895 if (unlikely(user8 == NULL)) {
2896 database = NULL;
2897 } else {
2898 password8 = stri_to_cstri8(password, &err_info);
2899 if (unlikely(password8 == NULL)) {
2900 database = NULL;
2901 } else {
2902 connection = mysql_init(NULL);
2903 if (unlikely(connection == NULL)) {
2904 err_info = MEMORY_ERROR;
2905 database = NULL;
2906 } else {
2907 if (mysql_options(connection, MYSQL_SET_CHARSET_NAME, "utf8") != 0) {
2908 logError(printf("sqlOpenMy: Unable to set charset to UTF-8.\n"););
2909 err_info = RANGE_ERROR;
2910 mysql_close(connection);
2911 database = NULL;
2912 } else {
2913 /* A host of NULL means "localhost" and a port of 0 means DEFAULT_PORT. */
2914 connect_result = mysql_real_connect(connection, host8[0] == '\0' ? NULL : host8,
2915 user8, password8, dbName8,
2916 (unsigned int) port, NULL, 0);
2917 if (connect_result == NULL) {
2918 setDbErrorMsg("sqlOpenMy", "mysql_real_connect",
2919 mysql_errno(connection),
2920 mysql_error(connection));
2921 logError(printf("sqlOpenMy: mysql_real_connect(conn, "
2922 "\"%s\", \"%s\", \"%s\", \"%s\", " FMT_D ") error:\n%s\n",
2923 host8[0] == '\0' ? "NULL" : host8,
2924 user8, password8, dbName8, port,
2925 mysql_error(connection)););
2926 err_info = DATABASE_ERROR;
2927 mysql_close(connection);
2928 database = NULL;
2929 } else if (mysql_set_character_set(connection, "utf8") != 0) {
2930 setDbErrorMsg("sqlOpenMy", "mysql_set_character_set",
2931 mysql_errno(connection),
2932 mysql_error(connection));
2933 logError(printf("sqlOpenMy: mysql_set_character_set error: %s\n",
2934 mysql_error(connection)););
2935 err_info = DATABASE_ERROR;
2936 mysql_close(connection);
2937 database = NULL;
2938 } else if (unlikely(!setupFuncTable() ||
2939 !ALLOC_RECORD2(database, dbRecord,
2940 count.database, count.database_bytes))) {
2941 err_info = MEMORY_ERROR;
2942 mysql_close(connection);
2943 database = NULL;
2944 } else {
2945 memset(database, 0, sizeof(dbRecord));
2946 database->usage_count = 1;
2947 database->sqlFunc = sqlFunc;
2948 database->driver = DB_CATEGORY_MYSQL;
2949 database->connection = connection;
2950 database->autoCommit = TRUE;
2951 determineIfBackslashEscapes(database);
2952 } /* if */
2953 } /* if */
2954 } /* if */
2955 free_cstri8(password8, password);
2956 } /* if */
2957 free_cstri8(user8, user);
2958 } /* if */
2959 free_cstri8(dbName8, dbName);
2960 } /* if */
2961 free_cstri8(host8, host);
2962 } /* if */
2963 if (unlikely(err_info != OKAY_NO_ERROR)) {
2964 raise_error(err_info);
2965 } /* if */
2966 logFunction(printf("sqlOpenMy --> " FMT_U_MEM "\n",
2967 (memSizeType) database););
2968 return (databaseType) database;
2969 } /* sqlOpenMy */
2970
2971 #else
2972
2973
2974
sqlOpenMy(const const_striType host,intType port,const const_striType dbName,const const_striType user,const const_striType password)2975 databaseType sqlOpenMy (const const_striType host, intType port,
2976 const const_striType dbName, const const_striType user,
2977 const const_striType password)
2978
2979 { /* sqlOpenMy */
2980 logError(printf("sqlOpenMy(\"%s\", ",
2981 striAsUnquotedCStri(host));
2982 printf(FMT_D ", \"%s\", ",
2983 port, striAsUnquotedCStri(dbName));
2984 printf("\"%s\", ", striAsUnquotedCStri(user));
2985 printf("\"%s\"): MariaDB/MySQL driver not present.\n",
2986 striAsUnquotedCStri(password)););
2987 raise_error(RANGE_ERROR);
2988 return NULL;
2989 } /* sqlOpenMy */
2990
2991 #endif
2992