1 /************************************************************************************
2    Copyright (C) 2013,2016 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 #ifndef _ma_odbc_h_
20 #define _ma_odbc_h_
21 
22 #include <ma_odbc_version.h>
23 
24 #ifdef _WIN32
25 # include "ma_platform_win32.h"
26 #else
27 # include "ma_platform_posix.h"
28 #endif
29 
30 #include <stdlib.h>
31 
32 #include <mysql.h>
33 
34 #include <ma_legacy_helpers.h>
35 
36 #include <sql.h>
37 #include <sqlext.h>
38 #include <odbcinst.h>
39 
40 #include <errmsg.h>
41 #include <string.h>
42 #include <stdio.h>
43 #include <math.h>
44 #include <stddef.h>
45 #include <assert.h>
46 #include <time.h>
47 
48 
49 typedef struct st_ma_odbc_connection MADB_Dbc;
50 typedef struct st_ma_odbc_stmt MADB_Stmt;
51 
52 typedef struct st_ma_odbc_error
53 {
54   char SqlState[SQL_SQLSTATE_SIZE + 1];
55   char SqlStateV2[SQLSTATE_LENGTH + 1];
56   char SqlErrorMsg[SQL_MAX_MESSAGE_LENGTH + 1];
57   SQLRETURN ReturnValue;
58 } MADB_ERROR;
59 
60 typedef struct
61 {
62   size_t PrefixLen;
63   MADB_ERROR *ErrRecord;
64   SQLINTEGER NativeError;
65   /* Order number of last requested error record */
66   unsigned int ErrorNum;
67   char SqlState[SQLSTATE_LENGTH + 1];
68   SQLRETURN ReturnValue;
69   char SqlErrorMsg[SQL_MAX_MESSAGE_LENGTH + 1];
70 } MADB_Error;
71 
72 typedef struct
73 {
74   SQLUINTEGER TargetType;
75   SQLPOINTER TargetValuePtr;
76   SQLLEN BufferLength;
77   SQLLEN Utf8BufferLength;
78   SQLLEN *StrLen_or_Ind;
79   void *InternalBuffer; /* used for conversion */
80 } MADB_ColBind;
81 
82 typedef struct
83 {
84   SQLSMALLINT InputOutputType;
85   SQLSMALLINT ValueType;
86   SQLSMALLINT ParameterType;
87   SQLULEN ColumnSize;
88   SQLSMALLINT DecimalDigits;
89   SQLPOINTER ParameterValuePtr;
90   SQLLEN BufferLength;
91   SQLLEN *StrLen_or_IndPtr;
92   void *InternalBuffer; /* used for conversion */
93 } MADB_ParmBind;
94 
95 typedef struct
96 {
97   /* Header */
98   SQLSMALLINT   AllocType;
99   SQLULEN       ArraySize;
100   SQLUSMALLINT *ArrayStatusPtr;
101   SQLULEN      *BindOffsetPtr;
102   SQLULEN       BindType;
103   SQLSMALLINT   Count;
104   /* TODO: In IPD this is SQLUINTEGER* field */
105   SQLULEN      *RowsProcessedPtr;
106   /* Header end */
107 } MADB_Header;
108 
109 typedef struct
110 {
111 	SQLUINTEGER	BindSize;	/* size of each structure if using * Row-wise Binding */
112 	SQLUSMALLINT	*RowOperationPtr;
113 	SQLULEN		*RowOffsetPtr;
114   MADB_ColBind *ColumnBind;
115 	MYSQL_BIND *Bind;
116 	SQLSMALLINT	Allocated;
117 } MADB_Ard;
118 
119 typedef struct
120 {
121 	SQLLEN ParamsetSize;
122 	SQLUINTEGER	ParamBindType;
123 	SQLUSMALLINT *ParamOperationPtr;
124 	SQLULEN *ParamOffsetPtr;
125 	MADB_ParmBind *ParamBind;
126 	MYSQL_BIND *Bind;
127 	SQLSMALLINT	Allocated;
128 	SQLLEN Dummy; /* dummy item to fit APD to ARD */
129 } MADB_Apd;
130 
131 typedef struct
132 {
133   MADB_Stmt *stmt;
134 	SQLULEN *RowsFetched;
135 	SQLUSMALLINT *RowStatusArray;
136 	SQLUINTEGER FieldCount;
137 	SQLSMALLINT	Allocated;
138 	MYSQL_FIELD *Fields;
139 } MADB_Ird;
140 
141 typedef struct
142 {
143   MADB_Header Header;
144 #if (ODBCVER >= 0x0300)
145 	SQLUINTEGER *ParamProcessedPtr;
146 #else
147 	SQLULEN *ParamProcessedPtr; /* SQLParamOptions */
148 #endif /* ODBCVER */
149 	SQLUSMALLINT *ParamStatusPtr;
150 	SQLSMALLINT Allocated;
151 	MADB_ParmBind *Parameters;
152 } MADB_Ipd;
153 
154 typedef struct {
155   SQLINTEGER  AutoUniqueValue;
156   char        *BaseCatalogName;
157   char        *BaseColumnName;
158   char        *BaseTableName;
159   SQLINTEGER  CaseSensitive;
160   char        *CatalogName;
161   char        *ColumnName;
162   SQLSMALLINT ConciseType;
163   SQLPOINTER  DataPtr;
164   SQLSMALLINT DateTimeIntervalCode;
165   SQLINTEGER  DateTimeIntervalPrecision;
166   SQLINTEGER  DescLength;
167   SQLLEN      DisplaySize;
168   SQLSMALLINT FixedPrecScale;
169   SQLLEN      *IndicatorPtr;
170   char        *Label;
171   SQLULEN     Length;
172   char        *LiteralPrefix;
173   char        *LiteralSuffix;
174   char        *LocalTypeName;
175   SQLSMALLINT Nullable;
176   SQLINTEGER  NumPrecRadix;
177   SQLLEN      OctetLength;
178   SQLLEN      *OctetLengthPtr;
179   SQLSMALLINT ParameterType;
180   SQLSMALLINT Precision;
181   SQLSMALLINT RowVer;
182   SQLSMALLINT Scale;
183   char        *SchemaName;
184   SQLSMALLINT Searchable;
185   char        *TableName;
186   SQLSMALLINT Type;
187   char        *TypeName;
188   SQLSMALLINT Unnamed;
189   SQLSMALLINT Unsigned;
190   SQLSMALLINT Updateable;
191   unsigned long InternalLength; /* This to be used in the MYSQL_BIND. Thus is the type */
192   char        *InternalBuffer;  /* used for internal conversion */
193   char        *DefaultValue;
194   char        *DaeData;
195   SQLULEN     DaeDataLength;    /* Doesn't seem to be used anywhere */
196   my_bool     PutData;
197   my_bool     inUse;
198   my_bool     TruncError;
199 } MADB_DescRecord;
200 
201 typedef struct
202 {
203   MADB_Header Header;
204   SQLINTEGER DescType;  /* SQL_ATTR_APP_ROW_DESC or SQL_ATTR_APP_PARAM_DESC */
205   my_bool AppType;      /* Allocated by Application ? */
206   MADB_DynArray Records;
207   MADB_DynArray Stmts;
208   MADB_Error Error;
209   MADB_Dbc * Dbc;       /* Disconnect must automatically free allocated descriptors. Thus
210                            descriptor has to know the connection it is allocated on */
211   MADB_List ListItem;        /* To store in the dbc */
212   union {
213     MADB_Ard Ard;
214     MADB_Apd Apd;
215     MADB_Ipd Ipd;
216     MADB_Ird Ird;
217   } Fields;
218 } MADB_Desc;
219 
220 struct st_ma_desc_fldid
221 {
222   SQLSMALLINT FieldIdentifier;
223   SQLSMALLINT Access[4];
224 };
225 
226 struct st_ma_stmt_methods;
227 
228 typedef struct
229 {
230  	SQLLEN MaxRows;
231 	SQLLEN MaxLength;
232 	SQLLEN KeysetSize;
233   SQLUINTEGER CursorType;
234 	SQLUINTEGER	ScrollConcurrency;
235   SQLUINTEGER RetrieveData;
236 	SQLUINTEGER UseBookmarks;
237 	void* BookmarkPtr;
238   SQLLEN BookmarkLength;
239   SQLSMALLINT BookmarkType;
240   SQLULEN	MetadataId;
241   SQLULEN SimulateCursor;
242 } MADB_StmtOptions;
243 
244 /* TODO: To check is it 0 or 1 based? not quite clear from its usage */
245 typedef struct
246 {
247   char            *Name;
248   SQLLEN           Position;
249   SQLLEN           RowsetSize;
250   MYSQL_ROW_OFFSET Next;
251 } MADB_Cursor;
252 
253 enum MADB_DaeType {MADB_DAE_NORMAL=0, MADB_DAE_ADD=1, MADB_DAE_UPDATE=2, MADB_DAE_DELETE=3};
254 
255 #define RESET_DAE_STATUS(Stmt_Hndl) (Stmt_Hndl)->Status=0; (Stmt_Hndl)->PutParam= -1
256 #define MARK_DAE_DONE(Stmt_Hndl)    (Stmt_Hndl)->Status=0; (Stmt_Hndl)->PutParam= (Stmt_Hndl)->ParamCount
257 
258 #define PARAM_IS_DAE(Len_Ptr) ((Len_Ptr) && (*(Len_Ptr) == SQL_DATA_AT_EXEC || *(Len_Ptr) <= SQL_LEN_DATA_AT_EXEC_OFFSET))
259 #define DAE_DONE(Stmt_Hndl) ((Stmt_Hndl)->PutParam >= (Stmt_Hndl)->ParamCount)
260 
261 enum MADB_StmtState {MADB_SS_INITED= 0, MADB_SS_EMULATED= 1, MADB_SS_PREPARED= 2, MADB_SS_EXECUTED= 3, MADB_SS_OUTPARAMSFETCHED= 4};
262 
263 #define STMT_WAS_PREPARED(Stmt_Hndl) (Stmt_Hndl->State >= MADB_SS_EMULATED)
264 #define RESET_STMT_STATE(Stmt_Hndl) Stmt_Hndl->State= STMT_WAS_PREPARED(Stmt_Hndl) ?\
265   (Stmt_Hndl->State == MADB_SS_EMULATED ? MADB_SS_EMULATED : MADB_SS_PREPARED) :\
266   MADB_SS_INITED
267 
268 /* Struct used to define column type when driver has to fix it (in catalog functions + SQLGetTypeInfo) */
269 typedef struct
270 {
271   SQLSMALLINT SqlType;
272   my_bool     Unsigned;
273   SQLSMALLINT Nullable;
274   SQLLEN      OctetLength;
275 
276 } MADB_ShortTypeInfo;
277 
278 typedef struct
279 {
280   unsigned int  ArraySize;
281   my_bool       HasRowsToSkip;
282 
283 } MADB_BulkOperationInfo;
284 
285 /* Stmt struct needs definitions from my_parse.h */
286 #include <ma_parse.h>
287 
288 #define STMT_STRING(STMT) (STMT)->Query.Original
289 
290 struct st_ma_odbc_stmt
291 {
292   MADB_Dbc                  *Connection;
293   struct st_ma_stmt_methods *Methods;
294   MADB_StmtOptions          Options;
295   MADB_Error                Error;
296   MADB_Cursor               Cursor;
297   MYSQL_STMT                *stmt;
298   MYSQL_RES                 *metadata;
299   MADB_List                 ListItem;
300   MADB_QUERY                Query;
301   SQLSMALLINT               ParamCount;
302   enum MADB_DaeType         DataExecutionType;
303   MYSQL_RES                 *DefaultsResult;
304   int                       ArrayOffset;
305   SQLSETPOSIROW             DaeRowNumber;
306   int                       Status;
307   MADB_DescRecord           *PutDataRec;
308   MADB_Stmt                 *DaeStmt;
309   MADB_Stmt                 *PositionedCursor;
310   my_bool                   PositionedCommand;
311   enum MADB_StmtState       State;
312   MYSQL_STMT                **MultiStmts;
313   unsigned int              MultiStmtNr;
314   unsigned int              MultiStmtMaxParam;
315   SQLLEN                    LastRowFetched;
316   MYSQL_BIND                *result;
317   MYSQL_BIND                *params;
318   int                       PutParam;
319   my_bool                   RebindParams;
320   my_bool                   bind_done;
321   long long                 AffectedRows;
322   unsigned long             *CharOffset;
323   unsigned long             *Lengths;
324   char                      *TableName;
325   char                      *CatalogName;
326   MADB_ShortTypeInfo        *ColsTypeFixArr;
327   MADB_BulkOperationInfo    Bulk;
328   /* Application Descriptors */
329   MADB_Desc *Apd;
330   MADB_Desc *Ard;
331   MADB_Desc *Ird;
332   MADB_Desc *Ipd;
333   /* Internal Descriptors */
334   MADB_Desc *IApd;
335   MADB_Desc *IArd;
336   MADB_Desc *IIrd;
337   MADB_Desc *IIpd;
338 };
339 
340 enum MADB_AppType{
341   ATypeGeneral= 0,
342   ATypeMSAccess= 1
343 };
344 
345 typedef struct st_ma_odbc_environment {
346   MADB_Error Error;
347   CRITICAL_SECTION cs;
348   MADB_List *Dbcs;
349   SQLWCHAR *TraceFile;
350   SQLUINTEGER Trace;
351   SQLINTEGER OdbcVersion;
352   SQLINTEGER OutputNTS;
353   enum MADB_AppType AppType;
354 } MADB_Env;
355 
356 //const size_t sizeOfT = sizeof(MADB_Env);
357 
358 #include <ma_dsn.h>
359 
360 
361 typedef struct st_client_charset
362 {
363   unsigned int CodePage;
364   MARIADB_CHARSET_INFO *cs_info;
365 } Client_Charset;
366 
367 struct st_ma_odbc_connection
368 {
369   MADB_Error Error;
370   CRITICAL_SECTION cs;           /* mutex for mariadb handle, i.e. for server communications */
371   CRITICAL_SECTION ListsCs;      /*       for operations with lists */
372   MADB_List ListItem;
373   Client_Charset Charset;
374   MYSQL *mariadb;                /* handle to a mariadb connection */
375   MADB_Env *Environment;         /* global environment */
376   MADB_Dsn *Dsn;
377   struct st_ma_connection_methods *Methods;
378 
379   Client_Charset *ConnOrSrcCharset; /* "Source" here stands for which charset Windows DM was using as source, when converted to unicode.
380                                   We have to use same charset to recode from unicode to get same string as application sent it.
381                                   For Unicode application that is the same as "Charset", or in case of ANSI on Windows - defaulst system codepage */
382   char *CurrentSchema; /* Used to store current schema if the seesion tracking is possible */
383   MADB_List *Stmts;
384   MADB_List *Descrs;
385   /* Attributes */
386   char *CatalogName;
387   HWND QuietMode;
388   char *TraceFile;
389 
390   SQLULEN AsyncEnable;
391   SQLPOINTER EnlistInDtc;
392   SQLULEN OdbcCursors;
393   unsigned long Options;
394   SQLUINTEGER AutoIpd;
395   SQLUINTEGER AutoCommit;
396   SQLUINTEGER ConnectionDead;
397   SQLUINTEGER ConnectionTimeout;
398   SQLUINTEGER ReadTimeout;
399   SQLUINTEGER WriteTimeout;
400   SQLUINTEGER PacketSize;
401   SQLINTEGER AccessMode;
402   SQLINTEGER IsolationLevel;     /* tx_isolation */
403   SQLUINTEGER Trace;
404   SQLUINTEGER LoginTimeout;
405   SQLUINTEGER MetadataId;
406   SQLINTEGER TxnIsolation;
407   SQLINTEGER CursorCount;
408   char ServerCapabilities;
409   my_bool IsAnsi;
410   my_bool IsMySQL;
411 };
412 
413 typedef BOOL (__stdcall *PromptDSN)(HWND hwnd, MADB_Dsn *Dsn);
414 
415 typedef struct
416 {
417   void     *LibraryHandle;
418   PromptDSN Call;
419 } MADB_Prompt;
420 
421 #define MADB_PROMPT_NOT_SUPPORTED 1
422 #define MADB_PROMPT_COULDNT_LOAD  2
423 int DSNPrompt_Lookup(MADB_Prompt *prompt, const char *SetupLibName);
424 
425 int DSNPrompt_Free  (MADB_Prompt *prompt);
426 
427 int   InitClientCharset (Client_Charset *cc, const char *name);
428 void  CopyClientCharset (Client_Charset *Src, Client_Charset *Dst);
429 void  CloseClientCharset(Client_Charset *cc);
430 
431 /* Default precision of SQL_NUMERIC */
432 #define MADB_DEFAULT_PRECISION 38
433 #define MADB_MAX_SCALE         MADB_DEFAULT_PRECISION
434 #define BINARY_CHARSETNR       63
435 /* Inexistent param id */
436 #define MADB_NOPARAM           -1
437 /* Macros to guard communications with the server.
438    TODO: make it(locking) optional depending on designated connection string option */
439 #define LOCK_MARIADB(Dbc)   EnterCriticalSection(&(Dbc)->cs)
440 #define UNLOCK_MARIADB(Dbc) LeaveCriticalSection(&(Dbc)->cs)
441 
442 /* Enabling tracing */
443 #define MAODBC_DEBUG 1
444 /* Macro checks return of the suplied SQLRETURN function call, checks if it is succeeded, and in case of error pushes error up */
445 #define RETURN_ERROR_OR_CONTINUE(sqlreturn_func_call) {\
446   SQLRETURN rc= (sqlreturn_func_call);\
447   if (!SQL_SUCCEEDED(rc)) return rc;\
448 } while(0)
449 
450 #define iOdbc() (sizeof(SQLWCHAR)==4)
451 
452 #include <ma_error.h>
453 #include <ma_info.h>
454 #include <ma_environment.h>
455 #include <ma_connection.h>
456 #include <ma_debug.h>
457 #include <ma_desc.h>
458 #include <ma_statement.h>
459 #include <ma_string.h>
460 #include <ma_result.h>
461 #include <ma_driver.h>
462 #include <ma_helper.h>
463 #include <ma_server.h>
464 #include <ma_typeconv.h>
465 #include <ma_bulk.h>
466 
467 #include "ma_api_internal.h"
468 
469 SQLRETURN MADB_GetBookmark(MADB_Stmt  *StatementHandle,
470                            SQLSMALLINT TargetType,
471                            SQLPOINTER  TargetValuePtr,
472                            SQLLEN      BufferLength,
473                            SQLLEN     *StrLen_or_IndPtr);
474 
475 SQLRETURN MADB_StmtColAttr(MADB_Stmt *Stmt, SQLUSMALLINT ColumnNumber, SQLUSMALLINT FieldIdentifier, SQLPOINTER CharacterAttributePtr,
476              SQLSMALLINT BufferLength, SQLSMALLINT *StringLengthPtr, SQLLEN *NumericAttributePtr, my_bool IsWchar);
477 
478 SQLRETURN MADB_StmtColAttr(MADB_Stmt *Stmt, SQLUSMALLINT ColumnNumber, SQLUSMALLINT FieldIdentifier, SQLPOINTER CharacterAttributePtr,
479              SQLSMALLINT BufferLength, SQLSMALLINT *StringLengthPtr, SQLLEN *NumericAttributePtr, my_bool IsWchar);
480 #endif /* _ma_odbc_h_ */
481