1 /************************************************************************************
2 Copyright (C) 2013,2019 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 #include <ma_odbc.h>
20
21 extern MARIADB_CHARSET_INFO* DmUnicodeCs;
22
MADB_GetTableName(MADB_Stmt * Stmt)23 char *MADB_GetTableName(MADB_Stmt *Stmt)
24 {
25 char *TableName= NULL;
26 unsigned int i= 0;
27 if (Stmt->TableName && Stmt->TableName[0])
28 return Stmt->TableName;
29 if (!mysql_stmt_field_count(Stmt->stmt))
30 return NULL;
31
32 for (i=0; i < mysql_stmt_field_count(Stmt->stmt); i++)
33 {
34 if (Stmt->stmt->fields[i].org_table)
35 {
36 if (!TableName)
37 TableName= Stmt->stmt->fields[i].org_table;
38 if (strcmp(TableName, Stmt->stmt->fields[i].org_table))
39 {
40 MADB_SetError(&Stmt->Error, MADB_ERR_HY000, "Couldn't identify unique table name", 0);
41 return NULL;
42 }
43 }
44 }
45 if (TableName)
46 Stmt->TableName= _strdup(TableName);
47 return TableName;
48 }
49
MADB_GetCatalogName(MADB_Stmt * Stmt)50 char *MADB_GetCatalogName(MADB_Stmt *Stmt)
51 {
52 char *CatalogName= NULL;
53 unsigned int i= 0;
54 if (Stmt->CatalogName && Stmt->CatalogName[0])
55 return Stmt->CatalogName;
56 if (!mysql_stmt_field_count(Stmt->stmt))
57 return NULL;
58
59 for (i=0; i < mysql_stmt_field_count(Stmt->stmt); i++)
60 {
61 if (Stmt->stmt->fields[i].org_table)
62 {
63 if (!CatalogName)
64 CatalogName= Stmt->stmt->fields[i].db;
65 if (strcmp(CatalogName, Stmt->stmt->fields[i].db))
66 {
67 MADB_SetError(&Stmt->Error, MADB_ERR_HY000, "Couldn't identify unique catalog name", 0);
68 return NULL;
69 }
70 }
71 }
72 if (CatalogName)
73 Stmt->CatalogName= _strdup(CatalogName);
74 return CatalogName;
75 }
76
MADB_DynStrAppendQuoted(MADB_DynString * DynString,char * String)77 my_bool MADB_DynStrAppendQuoted(MADB_DynString *DynString, char *String)
78 {
79 if (MADB_DynstrAppendMem(DynString, "`", 1) ||
80 MADB_DynstrAppend(DynString, String) ||
81 MADB_DynstrAppendMem(DynString, "`", 1))
82 {
83 return TRUE;
84 }
85 return FALSE;
86 }
87
MADB_DynStrUpdateSet(MADB_Stmt * Stmt,MADB_DynString * DynString)88 my_bool MADB_DynStrUpdateSet(MADB_Stmt *Stmt, MADB_DynString *DynString)
89 {
90 int i, IgnoredColumns= 0;
91 MADB_DescRecord *Record;
92
93 if (MADB_DYNAPPENDCONST(DynString, " SET "))
94 {
95 MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
96 return TRUE;
97 }
98 // ???? memcpy(&Stmt->Da->Apd->Header, &Stmt->Ard->Header, sizeof(MADB_Header));
99 for (i=0; i < MADB_STMT_COLUMN_COUNT(Stmt); i++)
100 {
101 SQLLEN *IndicatorPtr= NULL;
102 Record= MADB_DescGetInternalRecord(Stmt->Ard, i, MADB_DESC_READ);
103 if (Record->IndicatorPtr)
104 IndicatorPtr= (SQLLEN *)GetBindOffset(Stmt->Ard, Record, Record->IndicatorPtr, Stmt->DaeRowNumber > 1 ? Stmt->DaeRowNumber-1 : 0,
105 sizeof(SQLLEN)/*Record->OctetLength*/);
106 if ((IndicatorPtr && *IndicatorPtr == SQL_COLUMN_IGNORE) || !Record->inUse)
107 {
108 IgnoredColumns++;
109 continue;
110 }
111
112 if ((i - IgnoredColumns) && MADB_DYNAPPENDCONST(DynString, ","))
113 {
114 MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
115 return TRUE;
116 }
117 if (MADB_DynStrAppendQuoted(DynString, Stmt->stmt->fields[i].org_name))
118 {
119 MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
120 return TRUE;
121 }
122 if (MADB_DYNAPPENDCONST(DynString, "=?"))
123 {
124 MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
125 return TRUE;
126 }
127 }
128 if (IgnoredColumns == mysql_stmt_field_count(Stmt->stmt))
129 {
130 MADB_SetError(&Stmt->Error, MADB_ERR_21S02, NULL, 0);
131 return TRUE;
132 }
133 return FALSE;
134 }
135
MADB_DynStrInsertSet(MADB_Stmt * Stmt,MADB_DynString * DynString)136 my_bool MADB_DynStrInsertSet(MADB_Stmt *Stmt, MADB_DynString *DynString)
137 {
138 MADB_DynString ColVals;
139 int i, NeedComma= 0;
140 MADB_DescRecord *Record;
141
142 MADB_InitDynamicString(&ColVals, "VALUES (", 32, 32);
143 if (MADB_DYNAPPENDCONST(DynString, " ("))
144 {
145 goto dynerror;
146
147 return TRUE;
148 }
149
150 /* We use only columns, that have been bound, and are not IGNORED */
151 for (i= 0; i < MADB_STMT_COLUMN_COUNT(Stmt); i++)
152 {
153 Record= MADB_DescGetInternalRecord(Stmt->Ard, i, MADB_DESC_READ);
154 if (!Record->inUse || MADB_ColumnIgnoredInAllRows(Stmt->Ard, Record) == TRUE)
155 {
156 continue;
157 }
158
159 if ((NeedComma) &&
160 (MADB_DYNAPPENDCONST(DynString, ",") || MADB_DYNAPPENDCONST(&ColVals, ",")))
161 goto dynerror;
162
163 if (MADB_DynStrAppendQuoted(DynString, Stmt->stmt->fields[i].org_name) ||
164 MADB_DYNAPPENDCONST(&ColVals, "?"))
165 goto dynerror;
166
167 NeedComma= 1;
168 }
169 if (MADB_DYNAPPENDCONST(DynString, ") " ) ||
170 MADB_DYNAPPENDCONST(&ColVals, ")") ||
171 MADB_DynstrAppend(DynString, ColVals.str))
172 goto dynerror;
173 MADB_DynstrFree(&ColVals);
174 return FALSE;
175 dynerror:
176 MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
177 MADB_DynstrFree(&ColVals);
178 return TRUE;
179 }
180
MADB_DynStrGetColumns(MADB_Stmt * Stmt,MADB_DynString * DynString)181 my_bool MADB_DynStrGetColumns(MADB_Stmt *Stmt, MADB_DynString *DynString)
182 {
183 unsigned int i;
184 if (MADB_DYNAPPENDCONST(DynString, " ("))
185 {
186 MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
187 return TRUE;
188 }
189 for (i=0; i < mysql_stmt_field_count(Stmt->stmt); i++)
190 {
191 if (i && MADB_DYNAPPENDCONST(DynString, ", "))
192 {
193 MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
194 return TRUE;
195 }
196 if (MADB_DynStrAppendQuoted(DynString, Stmt->stmt->fields[i].org_name))
197 {
198 MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
199 return TRUE;
200 }
201 }
202 if (MADB_DYNAPPENDCONST(DynString, " )"))
203 {
204 MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
205 return TRUE;
206 }
207 return FALSE;
208 }
209
MADB_DynStrGetWhere(MADB_Stmt * Stmt,MADB_DynString * DynString,char * TableName,my_bool ParameterMarkers)210 my_bool MADB_DynStrGetWhere(MADB_Stmt *Stmt, MADB_DynString *DynString, char *TableName, my_bool ParameterMarkers)
211 {
212 int UniqueCount=0, PrimaryCount= 0;
213 int i, Flag= 0;
214 char *Column= NULL, *Escaped= NULL;
215 SQLLEN StrLength;
216 unsigned long EscapedLength;
217
218 for (i= 0; i < MADB_STMT_COLUMN_COUNT(Stmt); i++)
219 {
220 MYSQL_FIELD *field= mysql_fetch_field_direct(FetchMetadata(Stmt), i);
221 if (field->flags & PRI_KEY_FLAG)
222 PrimaryCount++;
223 if (field->flags & UNIQUE_KEY_FLAG)
224 UniqueCount++;
225 }
226 /* We need to use all columns, otherwise it will be difficult to map fields for Positioned Update */
227 if (PrimaryCount && PrimaryCount != MADB_KeyTypeCount(Stmt->Connection, TableName, PRI_KEY_FLAG))
228 PrimaryCount= 0;
229 if (UniqueCount && UniqueCount != MADB_KeyTypeCount(Stmt->Connection, TableName, UNIQUE_KEY_FLAG))
230 UniqueCount= 0;
231
232 /* if no primary or unique key is in the cursor, the cursor must contain all
233 columns from table in TableName */
234 if (!PrimaryCount && !UniqueCount)
235 {
236 char StmtStr[256];
237 MADB_Stmt *CountStmt;
238 int FieldCount= 0;
239
240 MA_SQLAllocHandle(SQL_HANDLE_STMT, Stmt->Connection, (SQLHANDLE*)&CountStmt);
241 _snprintf(StmtStr, 256, "SELECT * FROM `%s` LIMIT 0", TableName);
242 CountStmt->Methods->ExecDirect(CountStmt, (char *)StmtStr, SQL_NTS);
243 FieldCount= mysql_stmt_field_count(((MADB_Stmt *)CountStmt)->stmt);
244 CountStmt->Methods->StmtFree(CountStmt, SQL_DROP);
245
246 if (FieldCount != MADB_STMT_COLUMN_COUNT(Stmt))
247 {
248 MADB_SetError(&Stmt->Error, MADB_ERR_S1000, "Can't build index for update/delete", 0);
249 return TRUE;
250 }
251 }
252 if (MADB_DYNAPPENDCONST(DynString, " WHERE 1"))
253 goto memerror;
254 for (i= 0; i < MADB_STMT_COLUMN_COUNT(Stmt); i++)
255 {
256 MYSQL_FIELD *field= mysql_fetch_field_direct(Stmt->metadata, i);
257 if (field->flags & Flag || !Flag)
258 {
259 if (MADB_DYNAPPENDCONST(DynString, " AND ") ||
260 MADB_DynStrAppendQuoted(DynString, field->org_name))
261 goto memerror;
262 if (ParameterMarkers)
263 {
264 if (MADB_DYNAPPENDCONST(DynString, "=?"))
265 goto memerror;
266 }
267 else
268 {
269 if (!SQL_SUCCEEDED(Stmt->Methods->GetData(Stmt, i+1, SQL_C_CHAR, NULL, 0, &StrLength, TRUE)))
270 {
271 MADB_FREE(Column);
272 return TRUE;
273 }
274 if (StrLength < 0)
275 {
276 if (MADB_DYNAPPENDCONST(DynString, " IS NULL"))
277 goto memerror;
278 }
279 else
280 {
281 Column= MADB_CALLOC(StrLength + 1);
282 Stmt->Methods->GetData(Stmt,i+1, SQL_C_CHAR, Column, StrLength + 1, &StrLength, TRUE);
283 Escaped = MADB_CALLOC(2 * StrLength + 1);
284 EscapedLength= mysql_real_escape_string(Stmt->Connection->mariadb, Escaped, Column, (unsigned long)StrLength);
285
286 if (MADB_DYNAPPENDCONST(DynString, "= '") ||
287 MADB_DynstrAppend(DynString, Escaped) ||//, EscapedLength) ||
288 MADB_DYNAPPENDCONST(DynString, "'"))
289 {
290 goto memerror;
291 }
292 MADB_FREE(Column);
293 MADB_FREE(Escaped);
294 }
295 }
296 }
297 }
298 if (MADB_DYNAPPENDCONST(DynString, " LIMIT 1"))
299 goto memerror;
300 MADB_FREE(Column);
301
302 return FALSE;
303
304 memerror:
305 MADB_FREE(Column);
306 MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
307
308 return TRUE;
309 }
310
311
MADB_DynStrGetValues(MADB_Stmt * Stmt,MADB_DynString * DynString)312 my_bool MADB_DynStrGetValues(MADB_Stmt *Stmt, MADB_DynString *DynString)
313 {
314 unsigned int i;
315 if (MADB_DYNAPPENDCONST(DynString, " VALUES("))
316 {
317 MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
318 return TRUE;
319 }
320 for (i=0; i < mysql_stmt_field_count(Stmt->stmt); i++)
321 {
322 if (MADB_DynstrAppend(DynString, (i) ? ",?" : "?"))
323 {
324 MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
325 return TRUE;
326 }
327 }
328 if (MADB_DYNAPPENDCONST(DynString, ")"))
329 {
330 MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
331 return TRUE;
332 }
333 return FALSE;
334 }
335
MADB_GetInsertStatement(MADB_Stmt * Stmt)336 char *MADB_GetInsertStatement(MADB_Stmt *Stmt)
337 {
338 char *StmtStr;
339 size_t Length= 1024;
340 char *p;
341 char *TableName;
342 unsigned int i;
343
344 if (!(StmtStr= MADB_CALLOC(1024)))
345 {
346 MADB_SetError(&Stmt->Error, MADB_ERR_HY013, NULL, 0);
347 return NULL;
348 }
349 if (!(TableName= MADB_GetTableName(Stmt)))
350 goto error;
351 p= StmtStr;
352
353 p+= _snprintf(StmtStr, 1024, "INSERT INTO `%s` (", TableName);
354 for (i=0; i < mysql_stmt_field_count(Stmt->stmt); i++)
355 {
356 if (strlen(StmtStr) > Length - NAME_LEN - 4/* comma + 2 ticks + terminating NULL */)
357 {
358 Length+= 1024;
359 if (!(StmtStr= MADB_REALLOC(StmtStr, Length)))
360 {
361 MADB_SetError(&Stmt->Error, MADB_ERR_HY013, NULL, 0);
362 goto error;
363 }
364 }
365 p+= _snprintf(p, Length - strlen(StmtStr), "%s`%s`", (i==0) ? "" : ",", Stmt->stmt->fields[i].org_name);
366 }
367 p+= _snprintf(p, Length - strlen(StmtStr), ") VALUES (");
368
369 if (strlen(StmtStr) > Length - mysql_stmt_field_count(Stmt->stmt)*2 - 1)/* , and ? for each column + (- 1 comma for 1st column + closing ')')
370 + terminating NULL */
371 {
372 Length= strlen(StmtStr) + mysql_stmt_field_count(Stmt->stmt)*2 + 1;
373 if (!(StmtStr= MADB_REALLOC(StmtStr, Length)))
374 {
375 MADB_SetError(&Stmt->Error, MADB_ERR_HY013, NULL, 0);
376 goto error;
377 }
378 }
379
380 for (i=0; i < mysql_stmt_field_count(Stmt->stmt); i++)
381 {
382 p+= _snprintf(p, Length - strlen(StmtStr), "%s?", (i==0) ? "" : ",");
383 }
384 p+= _snprintf(p, Length - strlen(StmtStr), ")");
385 return StmtStr;
386
387 error:
388 if (StmtStr)
389 MADB_FREE(StmtStr);
390 return NULL;
391 }
392
393
MADB_ValidateStmt(MADB_QUERY * Query)394 my_bool MADB_ValidateStmt(MADB_QUERY *Query)
395 {
396 return Query->QueryType != MADB_QUERY_SET_NAMES;
397 }
398
399
MADB_ToLower(const char * src,char * buff,size_t buff_size)400 char *MADB_ToLower(const char *src, char *buff, size_t buff_size)
401 {
402 size_t i= 0;
403
404 if (buff_size > 0)
405 {
406 while (*src && i < buff_size)
407 {
408 buff[i++]= tolower(*src++);
409 }
410
411 buff[i == buff_size ? i - 1 : i]= '\0';
412 }
413 return buff;
414 }
415
416
InitClientCharset(Client_Charset * cc,const char * name)417 int InitClientCharset(Client_Charset *cc, const char * name)
418 {
419 /* There is no legal charset names longer than 31 chars */
420 char lowered[32];
421 cc->cs_info= mariadb_get_charset_by_name(MADB_ToLower(name, lowered, sizeof(lowered)));
422
423 if (cc->cs_info == NULL)
424 {
425 return 1;
426 }
427
428 cc->CodePage= cc->cs_info->codepage;
429
430 return 0;
431 }
432
433
CopyClientCharset(Client_Charset * Src,Client_Charset * Dst)434 void CopyClientCharset(Client_Charset * Src, Client_Charset * Dst)
435 {
436 Dst->CodePage= Src->CodePage;
437 Dst->cs_info= Src->cs_info;
438 }
439
440
CloseClientCharset(Client_Charset * cc)441 void CloseClientCharset(Client_Charset *cc)
442 {
443 }
444
445
446 /* Hmmm... Length in characters is SQLLEN, octet length SQLINTEGER */
MbstrOctetLen(const char * str,SQLLEN * CharLen,MARIADB_CHARSET_INFO * cs)447 SQLLEN MbstrOctetLen(const char *str, SQLLEN *CharLen, MARIADB_CHARSET_INFO *cs)
448 {
449 SQLLEN result= 0, inChars= *CharLen;
450
451 if (str)
452 {
453 if (cs->mb_charlen == NULL)
454 {
455 /* Charset uses no more than a byte per char. Result is strlen or umber of chars */
456 if (*CharLen < 0)
457 {
458 result= (SQLLEN)strlen(str);
459 *CharLen= result;
460 }
461 else
462 {
463 result= *CharLen;
464 }
465 return result;
466 }
467 else
468 {
469 while (inChars > 0 || (inChars < 0 && *str))
470 {
471 result+= cs->mb_charlen(0 + *str);
472 --inChars;
473 str+= cs->mb_charlen(*str);
474 }
475 }
476 }
477
478 if (*CharLen < 0)
479 {
480 *CharLen-= inChars;
481 }
482 return result;
483 }
484
485
486 /* Number of characters in given number of bytes */
MbstrCharLen(const char * str,SQLINTEGER OctetLen,MARIADB_CHARSET_INFO * cs)487 SQLLEN MbstrCharLen(const char *str, SQLINTEGER OctetLen, MARIADB_CHARSET_INFO *cs)
488 {
489 SQLLEN result= 0;
490 const char *ptr= str;
491 unsigned int charlen;
492
493 if (str)
494 {
495 if (cs->mb_charlen == NULL || cs->char_maxlen == 1)
496 {
497 return OctetLen;
498 }
499 while (ptr < str + OctetLen)
500 {
501 charlen= cs->mb_charlen((unsigned char)*ptr);
502 if (charlen == 0)
503 {
504 /* Dirty hack to avoid dead loop - Has to be the error! */
505 charlen= 1;
506 }
507
508 /* Skipping thru 0 bytes */
509 while (charlen > 0 && *ptr == '\0')
510 {
511 --charlen;
512 ++ptr;
513 }
514
515 /* Stopping if current character is terminating NULL - charlen == 0 means all bytes of current char was 0 */
516 if (charlen == 0)
517 {
518 return result;
519 }
520 /* else we increment ptr for number of left bytes */
521 ptr+= charlen;
522 ++result;
523 }
524 }
525
526 return result;
527 }
528
529
530 /* Length of NT SQLWCHAR string in characters */
SqlwcsCharLen(SQLWCHAR * str,SQLLEN octets)531 SQLINTEGER SqlwcsCharLen(SQLWCHAR *str, SQLLEN octets)
532 {
533 SQLINTEGER result= 0;
534 SQLWCHAR *end= octets != (SQLLEN)-1 ? str + octets/sizeof(SQLWCHAR) : (SQLWCHAR*)octets /*for simplicity - the address to be always bigger */;
535
536 if (str)
537 {
538 while (str < end && *str)
539 {
540 str+= (DmUnicodeCs->mb_charlen(*str))/sizeof(SQLWCHAR);
541
542 if (str > end)
543 {
544 break;
545 }
546 ++result;
547 }
548 }
549 return result;
550 }
551
552
553 /* Length in SQLWCHAR units
554 @buff_length[in] - size of the str buffer or negative number */
SqlwcsLen(SQLWCHAR * str,SQLLEN buff_length)555 SQLLEN SqlwcsLen(SQLWCHAR *str, SQLLEN buff_length)
556 {
557 SQLINTEGER result= 0;
558
559 if (str)
560 {
561 /* If buff_length is negative - we will never hit 1st condition, otherwise we hit it after last character
562 of the buffer is processed */
563 while ((--buff_length) != -1 && *str)
564 {
565 ++result;
566 ++str;
567 }
568 }
569 return result;
570 }
571
572 /* Length of a string with respect to specified buffer size
573 @buff_length[in] - size of the str buffer or negative number */
SafeStrlen(SQLCHAR * str,SQLLEN buff_length)574 SQLLEN SafeStrlen(SQLCHAR *str, SQLLEN buff_length)
575 {
576 SQLINTEGER result= 0;
577
578 if (str)
579 {
580 /* If buff_length is negative - we will never hit 1st condition, otherwise we hit it after last character
581 of the buffer is processed */
582 while ((--buff_length) != -1 && *str)
583 {
584 ++result;
585 ++str;
586 }
587 }
588 return result;
589 }