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 = &param->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