1 /************************************************************************************
2    Copyright (C) 2020 MariaDB Corporation AB
3 
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    This library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13 
14    You should have received a copy of the GNU Library General Public
15    License along with this library; if not see <http://www.gnu.org/licenses>
16    or write to the Free Software Foundation, Inc.,
17    51 Franklin St., Fifth Floor, Boston, MA 02110, USA
18 *************************************************************************************/
19 
20 /**
21  * "Internal" ODBC API functions - functions, that have to be called internally if API
22  * function needs to be executed
23  *
24  * Calling SQLFunction itself inside the connector on non-Windows platforms will result
25  * in the driver manager function instead of our own function.
26  */
27 
28 #include <ma_odbc.h>
29 
30 
31 /* {{{ MA_SQLAllocHandle */
32 SQLRETURN MA_SQLAllocHandle(SQLSMALLINT HandleType,
33     SQLHANDLE InputHandle,
34     SQLHANDLE *OutputHandlePtr)
35 {
36   SQLRETURN ret= SQL_ERROR;
37 
38   switch(HandleType) {
39     case SQL_HANDLE_DBC:
40       EnterCriticalSection(&((MADB_Env *)InputHandle)->cs);
41       MADB_CLEAR_ERROR(&((MADB_Env *)InputHandle)->Error);
42       if ((*OutputHandlePtr= (SQLHANDLE)MADB_DbcInit((MADB_Env *)InputHandle)) != NULL)
43       {
44         ret= SQL_SUCCESS;
45       }
46       LeaveCriticalSection(&((MADB_Env *)InputHandle)->cs);
47       break;
48     case SQL_HANDLE_DESC:
49       EnterCriticalSection(&((MADB_Dbc *)InputHandle)->cs);
50       MADB_CLEAR_ERROR(&((MADB_Dbc *)InputHandle)->Error);
51       if ((*OutputHandlePtr= (SQLHANDLE)MADB_DescInit((MADB_Dbc *)InputHandle, MADB_DESC_UNKNOWN, TRUE)) != NULL)
52       {
53         ret= SQL_SUCCESS;
54       }
55       LeaveCriticalSection(&((MADB_Dbc *)InputHandle)->cs);
56       break;
57     case SQL_HANDLE_ENV:
58       if ((*OutputHandlePtr= (SQLHANDLE)MADB_EnvInit()) != NULL)
59       {
60         ret= SQL_SUCCESS;
61       }
62       break;
63     case SQL_HANDLE_STMT:
64       {
65         MADB_Dbc *Connection= (MADB_Dbc *)InputHandle;
66         MDBUG_C_ENTER(InputHandle, "MA_SQLAllocHandle(Stmt)");
67         MDBUG_C_DUMP(InputHandle, InputHandle, 0x);
68         MDBUG_C_DUMP(InputHandle, OutputHandlePtr, 0x);
69 
70         MADB_CLEAR_ERROR(&Connection->Error);
71 
72         if (!CheckConnection(Connection))
73         {
74           MADB_SetError(&Connection->Error, MADB_ERR_08003, NULL, 0);
75           break;
76         }
77 
78         ret= MADB_StmtInit(Connection, OutputHandlePtr);
79         MDBUG_C_DUMP(InputHandle, *OutputHandlePtr, 0x);
80         MDBUG_C_RETURN(InputHandle,ret, &Connection->Error);
81       }
82       break;
83     default:
84       /* todo: set error message */
85       break;
86   }
87   return ret;
88 }
89 /* }}} */
90 
91 /* {{{ MA_SQLBindParameter */
92 SQLRETURN MA_SQLBindParameter(SQLHSTMT StatementHandle,
93     SQLUSMALLINT ParameterNumber,
94     SQLSMALLINT InputOutputType,
95     SQLSMALLINT ValueType,
96     SQLSMALLINT ParameterType,
97     SQLULEN ColumnSize,
98     SQLSMALLINT DecimalDigits,
99     SQLPOINTER ParameterValuePtr,
100     SQLLEN BufferLength,
101     SQLLEN *StrLen_or_IndPtr)
102 {
103   MADB_Stmt *Stmt= (MADB_Stmt *)StatementHandle;
104   SQLRETURN ret;
105 
106   if (!Stmt)
107     return SQL_INVALID_HANDLE;
108 
109   MDBUG_C_ENTER(Stmt->Connection, "SQLBindParameter");
110   MDBUG_C_DUMP(Stmt->Connection, Stmt, 0x);
111   MDBUG_C_DUMP(Stmt->Connection, ParameterNumber, u);
112   MDBUG_C_DUMP(Stmt->Connection, InputOutputType, d);
113   MDBUG_C_DUMP(Stmt->Connection, ValueType, d);
114   MDBUG_C_DUMP(Stmt->Connection, ParameterType, d);
115   MDBUG_C_DUMP(Stmt->Connection, ColumnSize, u);
116   MDBUG_C_DUMP(Stmt->Connection, DecimalDigits, d);
117   MDBUG_C_DUMP(Stmt->Connection, ParameterValuePtr, 0x);
118   MDBUG_C_DUMP(Stmt->Connection, BufferLength, d);
119   MDBUG_C_DUMP(Stmt->Connection, StrLen_or_IndPtr, 0x);
120 
121   MADB_CHECK_STMT_HANDLE(Stmt,stmt);
122   ret= Stmt->Methods->BindParam(Stmt, ParameterNumber, InputOutputType, ValueType, ParameterType, ColumnSize, DecimalDigits,
123                                   ParameterValuePtr, BufferLength, StrLen_or_IndPtr);
124 
125   MDBUG_C_RETURN(Stmt->Connection, ret, &Stmt->Error);
126 }
127 /* }}} */
128 
129 
130 /* {{{ MA_SQLCancel */
131 SQLRETURN MA_SQLCancel(SQLHSTMT StatementHandle)
132 {
133   MADB_Stmt *Stmt= (MADB_Stmt *)StatementHandle;
134   SQLRETURN ret= SQL_ERROR;
135 
136   if (!Stmt)
137     return SQL_INVALID_HANDLE;
138 
139   MADB_CLEAR_ERROR(&Stmt->Error);
140 
141   MDBUG_C_ENTER(Stmt->Connection, "SQLCancel");
142   MDBUG_C_DUMP(Stmt->Connection, Stmt, 0x);
143 
144   if (TryEnterCriticalSection(&Stmt->Connection->cs))
145   {
146     LeaveCriticalSection(&Stmt->Connection->cs);
147     ret= Stmt->Methods->StmtFree(Stmt, SQL_CLOSE);
148 
149     MDBUG_C_RETURN(Stmt->Connection, ret, &Stmt->Error);
150   } else
151   {
152     MYSQL *MariaDb, *Kill=Stmt->Connection->mariadb;
153 
154     char StmtStr[30];
155 
156     if (!(MariaDb= mysql_init(NULL)))
157     {
158       ret= SQL_ERROR;
159       goto end;
160     }
161     if (!(mysql_real_connect(MariaDb, Kill->host, Kill->user, Kill->passwd,
162                              "", Kill->port, Kill->unix_socket, 0)))
163     {
164       mysql_close(MariaDb);
165       goto end;
166     }
167 
168     _snprintf(StmtStr, 30, "KILL QUERY %ld", mysql_thread_id(Kill));
169     if (mysql_query(MariaDb, StmtStr))
170     {
171       mysql_close(MariaDb);
172       goto end;
173     }
174     mysql_close(MariaDb);
175     ret= SQL_SUCCESS;
176   }
177 end:
178   LeaveCriticalSection(&Stmt->Connection->cs);
179 
180   MDBUG_C_RETURN(Stmt->Connection, ret, &Stmt->Error);
181 }
182 
183 /* {{{ MA_SQLEndTran */
184 SQLRETURN MA_SQLEndTran(SQLSMALLINT HandleType,
185     SQLHANDLE Handle,
186     SQLSMALLINT CompletionType)
187 {
188   SQLRETURN ret= SQL_SUCCESS;
189   switch (HandleType) {
190   case SQL_HANDLE_ENV:
191     {
192       MADB_Env *Env= (MADB_Env *)Handle;
193       MADB_List *List= Env->Dbcs;
194 
195       for (List= Env->Dbcs; List; List= List->next)
196         ((MADB_Dbc *)List->data)->Methods->EndTran((MADB_Dbc *)List->data, CompletionType);
197     }
198     break;
199   case SQL_HANDLE_DBC:
200     {
201       MADB_Dbc *Dbc= (MADB_Dbc *)Handle;
202       if (!Dbc->mariadb)
203         MADB_SetError(&Dbc->Error, MADB_ERR_08002, NULL, 0);
204       else
205         Dbc->Methods->EndTran(Dbc, CompletionType);
206       ret= Dbc->Error.ReturnValue;
207     }
208     break;
209   default:
210     /* todo: Do we need to set an error ?! */
211     break;
212   }
213 
214   return ret;
215 }
216 /* }}} */
217 
218 /* {{{ MA_SQLGetDiagRecW */
219 SQLRETURN SQL_API MA_SQLGetDiagRecW(SQLSMALLINT HandleType,
220     SQLHANDLE Handle,
221     SQLSMALLINT RecNumber,
222     SQLWCHAR *SQLState,
223     SQLINTEGER *NativeErrorPtr,
224     SQLWCHAR *MessageText,
225     SQLSMALLINT BufferLength,
226     SQLSMALLINT *TextLengthPtr)
227 {
228   if (!Handle)
229     return SQL_INVALID_HANDLE;
230 
231   /* Maria ODBC driver doesn't support error lists, so only the first record can be retrieved */
232   if (RecNumber != 1)
233     return SQL_NO_DATA_FOUND;
234 
235   switch (HandleType) {
236     case SQL_HANDLE_DBC:
237       {
238         MADB_Dbc *Dbc= (MADB_Dbc *)Handle;
239         return MADB_GetDiagRec(&Dbc->Error, RecNumber, (void *)SQLState, NativeErrorPtr,
240                                (void *)MessageText, BufferLength, TextLengthPtr, TRUE,
241                                Dbc->Environment->OdbcVersion);
242       }
243       break;
244     case SQL_HANDLE_STMT:
245       {
246         MADB_Stmt *Stmt= (MADB_Stmt *)Handle;
247         return MADB_GetDiagRec(&Stmt->Error, RecNumber, (void *)SQLState, NativeErrorPtr,
248                                (void *)MessageText, BufferLength, TextLengthPtr, TRUE,
249                                Stmt->Connection->Environment->OdbcVersion);
250       }
251       break;
252     case SQL_HANDLE_DESC:
253       {
254         MADB_Desc *Desc= (MADB_Desc *)Handle;
255         return MADB_GetDiagRec(&Desc->Error, RecNumber, (void *)SQLState, NativeErrorPtr,
256                                (void *)MessageText, BufferLength, TextLengthPtr, TRUE,
257                                SQL_OV_ODBC3);
258       }
259       break;
260     case SQL_HANDLE_ENV:
261       {
262         MADB_Env *Env= (MADB_Env *)Handle;
263         return MADB_GetDiagRec(&Env->Error, RecNumber, (void *)SQLState, NativeErrorPtr,
264                                (void *)MessageText, BufferLength, TextLengthPtr, TRUE,
265                                Env->OdbcVersion);
266       }
267     default:
268       return SQL_ERROR;
269       break;
270   }
271 }
272 /* }}} */
273 
274 /* {{{ MA_SQLGetConnectAttr */
275 SQLRETURN MA_SQLGetConnectAttr(SQLHDBC ConnectionHandle,
276     SQLINTEGER Attribute,
277     SQLPOINTER ValuePtr,
278     SQLINTEGER BufferLength,
279     SQLINTEGER *StringLengthPtr)
280 {
281   MADB_Dbc *Dbc= (MADB_Dbc *)ConnectionHandle;
282   SQLRETURN ret;
283 
284   if (!Dbc)
285     return SQL_INVALID_HANDLE;
286 
287   MDBUG_C_ENTER(Dbc, "SQLGetConnectAttr");
288   MDBUG_C_DUMP(Dbc, Attribute, d);
289   MDBUG_C_DUMP(Dbc, ValuePtr, 0x);
290   MDBUG_C_DUMP(Dbc, BufferLength, d);
291   MDBUG_C_DUMP(Dbc, StringLengthPtr, 0x);
292 
293   ret= Dbc->Methods->GetAttr(Dbc, Attribute, ValuePtr, BufferLength, StringLengthPtr, FALSE);
294 
295   MDBUG_C_RETURN(Dbc, ret, &Dbc->Error);
296 }
297 /* }}} */
298 
299 /* {{{ SQLGetDiagRec */
300 SQLRETURN MA_SQLGetDiagRec(SQLSMALLINT HandleType,
301     SQLHANDLE Handle,
302     SQLSMALLINT RecNumber,
303     SQLCHAR *SQLState,
304     SQLINTEGER *NativeErrorPtr,
305     SQLCHAR *MessageText,
306     SQLSMALLINT BufferLength,
307     SQLSMALLINT *TextLengthPtr)
308 {
309   SQLRETURN ret= SQL_ERROR;
310 
311   if (!Handle)
312     MDBUG_RETURN(SQL_INVALID_HANDLE);
313 
314   if (RecNumber < 1 || BufferLength < 0)
315     MDBUG_RETURN(SQL_ERROR);
316 
317   /* Maria ODBC driver doesn't support error lists, so only the first record can be retrieved */
318   if (RecNumber != 1)
319     MDBUG_RETURN(SQL_NO_DATA_FOUND);
320 
321   switch (HandleType) {
322     case SQL_HANDLE_DBC:
323       {
324         MADB_Dbc *Dbc= (MADB_Dbc *)Handle;
325 
326         MDBUG_C_ENTER(Dbc, "SQLGetDiagRec");
327         MDBUG_C_DUMP(Dbc, HandleType, d);
328         MDBUG_C_DUMP(Dbc, Handle, 0x);
329         MDBUG_C_DUMP(Dbc, MessageText, 0x);
330         MDBUG_C_DUMP(Dbc, BufferLength, d);
331         MDBUG_C_DUMP(Dbc, TextLengthPtr, 0x);
332 
333         ret= MADB_GetDiagRec(&Dbc->Error, RecNumber, (void *)SQLState, NativeErrorPtr,
334                               (void *) MessageText, BufferLength, TextLengthPtr, FALSE,
335                               Dbc->Environment->OdbcVersion);
336       }
337       break;
338     case SQL_HANDLE_STMT:
339       {
340         MADB_Stmt *Stmt= (MADB_Stmt *)Handle;
341 
342         MDBUG_C_ENTER(Stmt->Connection, "SQLGetDiagRec");
343         MDBUG_C_DUMP(Stmt->Connection, HandleType, d);
344         MDBUG_C_DUMP(Stmt->Connection, Handle, 0x);
345         MDBUG_C_DUMP(Stmt->Connection, MessageText, 0x);
346         MDBUG_C_DUMP(Stmt->Connection, BufferLength, d);
347         MDBUG_C_DUMP(Stmt->Connection, TextLengthPtr, 0x);
348 
349         ret= MADB_GetDiagRec(&Stmt->Error, RecNumber, (void *)SQLState, NativeErrorPtr,
350                                (void *)MessageText, BufferLength, TextLengthPtr, FALSE,
351                                Stmt->Connection->Environment->OdbcVersion);
352       }
353       break;
354     case SQL_HANDLE_DESC:
355       {
356         MADB_Desc *Desc= (MADB_Desc *)Handle;
357 
358         MDBUG_C_ENTER(Desc->Dbc, "SQLGetDiagRec");
359         MDBUG_C_DUMP(Desc->Dbc, HandleType, d);
360         MDBUG_C_DUMP(Desc->Dbc, Handle, 0x);
361         MDBUG_C_DUMP(Desc->Dbc, MessageText, 0x);
362         MDBUG_C_DUMP(Desc->Dbc, BufferLength, d);
363         MDBUG_C_DUMP(Desc->Dbc, TextLengthPtr, 0x);
364 
365         ret= MADB_GetDiagRec(&Desc->Error, RecNumber, (void *)SQLState, NativeErrorPtr,
366                                (void *)MessageText, BufferLength, TextLengthPtr, FALSE,
367                                SQL_OV_ODBC3);
368       }
369       break;
370     case SQL_HANDLE_ENV:
371       {
372         MADB_Env *Env= (MADB_Env *)Handle;
373         ret= MADB_GetDiagRec(&Env->Error, RecNumber, (void *)SQLState, NativeErrorPtr,
374                                (void *)MessageText, BufferLength, TextLengthPtr, FALSE,
375                                Env->OdbcVersion);
376       }
377       break;
378   }
379 
380   MDBUG_RETURN(ret);
381 }
382 /* }}} */
383 
384 /* {{{ MA_SQLGetStmtAttr */
385 SQLRETURN MA_SQLGetStmtAttr(SQLHSTMT StatementHandle,
386     SQLINTEGER Attribute,
387     SQLPOINTER ValuePtr,
388     SQLINTEGER BufferLength,
389     SQLINTEGER *StringLengthPtr)
390 {
391   MADB_Stmt *Stmt= (MADB_Stmt *)StatementHandle;
392   if (!Stmt)
393     return SQL_INVALID_HANDLE;
394   return Stmt->Methods->GetAttr(Stmt, Attribute, ValuePtr, BufferLength, StringLengthPtr);
395 }
396 /* }}} */
397 
398 /* {{{ SQLSetConnectAttr */
399 SQLRETURN MA_SQLSetConnectAttr(SQLHDBC ConnectionHandle,
400     SQLINTEGER Attribute,
401     SQLPOINTER ValuePtr,
402     SQLINTEGER StringLength)
403 {
404   MADB_Dbc *Dbc= (MADB_Dbc *)ConnectionHandle;
405   SQLRETURN ret;
406 
407   if (!Dbc)
408     return SQL_INVALID_HANDLE;
409 
410   MDBUG_C_ENTER(Dbc, "SQLSetConnectAttr");
411   MDBUG_C_DUMP(Dbc, Attribute, d);
412   MDBUG_C_DUMP(Dbc, ValuePtr, 0x);
413   MDBUG_C_DUMP(Dbc, StringLength, d);
414 
415   ret= Dbc->Methods->SetAttr(Dbc, Attribute, ValuePtr, StringLength, FALSE);
416 
417   MDBUG_C_RETURN(Dbc, ret, &Dbc->Error);
418 }
419 /* }}} */
420 
421 /* {{{ SQLSetStmtAttr */
422 SQLRETURN MA_SQLSetStmtAttr(SQLHSTMT StatementHandle,
423     SQLINTEGER Attribute,
424     SQLPOINTER ValuePtr,
425     SQLINTEGER StringLength)
426 {
427   MADB_Stmt *Stmt= (MADB_Stmt *)StatementHandle;
428   SQLRETURN ret;
429 
430   if (!Stmt)
431     return SQL_INVALID_HANDLE;
432 
433   MDBUG_C_ENTER(Stmt->Connection, "SQLSetStmtAttr");
434   MDBUG_C_DUMP(Stmt->Connection, Attribute, d);
435   MDBUG_C_DUMP(Stmt->Connection, ValuePtr, 0x);
436   MDBUG_C_DUMP(Stmt->Connection, StringLength, d);
437 
438   ret= Stmt->Methods->SetAttr(Stmt, Attribute, ValuePtr, StringLength);
439 
440   MDBUG_C_RETURN(Stmt->Connection, ret, &Stmt->Error);
441 }
442 /* }}} */
443 
444