1 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Brian Bruns
3 * Copyright (C) 2005-2015 Frediano Ziglio
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
20
21 #include <config.h>
22
23 #include <stdlib.h>
24
25 #if HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif /* HAVE_UNISTD_H */
28
29 #include <assert.h>
30
31 #include <freetds/tds.h>
32 #include <freetds/iconv.h>
33 #include <freetds/tls.h>
34 #include <freetds/checks.h>
35 #include <freetds/utils/string.h>
36 #include <freetds/replacements.h>
37 #include <freetds/enum_cap.h>
38 #include <freetds/utils.h>
39
40 #if HAVE_SYS_SOCKET_H
41 #include <sys/socket.h>
42 #endif
43
44 #ifdef HAVE_STRING_H
45 #include <string.h>
46 #endif
47
48 #ifdef HAVE_LOCALE_H
49 #include <locale.h>
50 #endif /* HAVE_LOCALE_H */
51
52 #ifdef HAVE_LANGINFO_H
53 #include <langinfo.h>
54 #endif /* HAVE_LANGINFO_H */
55
56 static void tds_free_env(TDSCONNECTION * conn);
57 static void tds_free_compute_results(TDSSOCKET * tds);
58 static void tds_free_compute_result(TDSCOMPUTEINFO * comp_info);
59
60 #undef TEST_MALLOC
61 #define TEST_MALLOC(dest,type) \
62 {if (!(dest = (type*)calloc(1, sizeof(type)))) goto Cleanup;}
63
64 #undef TEST_CALLOC
65 #define TEST_CALLOC(dest,type,n) \
66 {if (!(dest = (type*)calloc((n), sizeof(type)))) goto Cleanup;}
67
68 /**
69 * \ingroup libtds
70 * \defgroup mem Memory allocation
71 * Allocate or free resources. Allocation can fail only on out of memory.
72 * In such case they return NULL and leave the state as before call.
73 * Mainly function names are in the form tds_alloc_XX or tds_free_XXX.
74 * tds_alloc_XXX functions allocate structures and return pointer to allocated
75 * data while tds_free_XXX take structure pointers and free them. Some functions
76 * require additional parameters to initialize structure correctly.
77 * The main exception are structures that use reference counting. These structures
78 * have tds_alloc_XXX functions but instead of tds_free_XXX use tds_release_XXX.
79 */
80
81 /**
82 * \addtogroup mem
83 * @{
84 */
85
86 static volatile unsigned int inc_num = 1;
87
88 /**
89 * Get an id for dynamic query based on TDS information
90 * \param conn state information for the connection and the TDS protocol
91 * \return TDS_FAIL or TDS_SUCCESS
92 */
93 static char *
tds_get_dynid(TDSCONNECTION * conn,char * id)94 tds_get_dynid(TDSCONNECTION * conn, char *id)
95 {
96 unsigned long n;
97 int i;
98 char *p;
99 char c;
100
101 CHECK_CONN_EXTRA(conn);
102
103 inc_num = (inc_num + 1) & 0xffff;
104 /* some version of Sybase require length <= 10, so we code id */
105 n = (unsigned long) (TDS_INTPTR) conn;
106 p = id;
107 *p++ = (char) ('a' + (n % 26u));
108 n /= 26u;
109 for (i = 0; i < 9; ++i) {
110 c = (char) ('0' + (n % 36u));
111 *p++ = (c < ('0' + 10)) ? c : c + ('a' - '0' - 10);
112 /* printf("%d -> %d(%c)\n",n%36u,p[-1],p[-1]); */
113 n /= 36u;
114 if (i == 4)
115 n += 3u * inc_num;
116 }
117 *p = 0;
118 return id;
119 }
120
121 #include <freetds/pushvis.h>
122 extern const TDSCOLUMNFUNCS tds_invalid_funcs;
123 #include <freetds/popvis.h>
124
125 static TDSCOLUMN *
tds_alloc_column(void)126 tds_alloc_column(void)
127 {
128 TDSCOLUMN *col;
129
130 TEST_MALLOC(col, TDSCOLUMN);
131 tds_dstr_init(&col->table_name);
132 tds_dstr_init(&col->column_name);
133 tds_dstr_init(&col->table_column_name);
134 col->funcs = &tds_invalid_funcs;
135
136 Cleanup:
137 return col;
138 }
139
140 static void
tds_free_column(TDSCOLUMN * col)141 tds_free_column(TDSCOLUMN *col)
142 {
143 tds_dstr_free(&col->table_name);
144 tds_dstr_free(&col->column_name);
145 tds_dstr_free(&col->table_column_name);
146 free(col);
147 }
148
149
150 /**
151 * \fn TDSDYNAMIC *tds_alloc_dynamic(TDSCONNECTION *conn, const char *id)
152 * \brief Allocate a dynamic statement.
153 * \param conn the connection within which to allocate the statement.
154 * \param id a character label identifying the statement.
155 * \return a pointer to the allocated structure (NULL on failure).
156 *
157 * tds_alloc_dynamic is used to implement placeholder code under TDS 5.0
158 */
159 TDSDYNAMIC *
tds_alloc_dynamic(TDSCONNECTION * conn,const char * id)160 tds_alloc_dynamic(TDSCONNECTION * conn, const char *id)
161 {
162 TDSDYNAMIC *dyn;
163 char tmp_id[30];
164
165 if (id) {
166 /* check to see if id already exists (shouldn't) */
167 if (tds_lookup_dynamic(conn, id))
168 return NULL;
169 } else {
170 unsigned int n;
171 id = tmp_id;
172
173 for (n = 0;;) {
174 if (!tds_lookup_dynamic(conn, tds_get_dynid(conn, tmp_id)))
175 break;
176 if (++n == 256)
177 return NULL;
178 }
179 }
180
181 TEST_MALLOC(dyn, TDSDYNAMIC);
182
183 /* take into account pointer in list */
184 dyn->ref_count = 2;
185
186 /* insert into list */
187 dyn->next = conn->dyns;
188 conn->dyns = dyn;
189
190 strlcpy(dyn->id, id, TDS_MAX_DYNID_LEN);
191
192 return dyn;
193
194 Cleanup:
195 return NULL;
196 }
197
198 /**
199 * \fn void tds_free_input_params(TDSDYNAMIC *dyn)
200 * \brief Frees all allocated input parameters of a dynamic statement.
201 * \param dyn the dynamic statement whose input parameter are to be freed
202 *
203 * tds_free_input_params frees all parameters for the give dynamic statement
204 */
205 void
tds_free_input_params(TDSDYNAMIC * dyn)206 tds_free_input_params(TDSDYNAMIC * dyn)
207 {
208 TDSPARAMINFO *info;
209
210 info = dyn->params;
211 if (info) {
212 tds_free_param_results(info);
213 dyn->params = NULL;
214 }
215 }
216
217 /*
218 * Called when dynamic got deallocated from server
219 */
220 void
tds_dynamic_deallocated(TDSCONNECTION * conn,TDSDYNAMIC * dyn)221 tds_dynamic_deallocated(TDSCONNECTION *conn, TDSDYNAMIC *dyn)
222 {
223 TDSDYNAMIC **victim;
224
225 tdsdump_log(TDS_DBG_FUNC, "tds_dynamic_deallocated() : freeing dynamic_id %s\n", dyn->id);
226
227 victim = &conn->dyns;
228 while (*victim != dyn) {
229 if (*victim == NULL) {
230 tdsdump_log(TDS_DBG_FUNC, "tds_dynamic_deallocated() : cannot find id %s\n", dyn->id);
231 return;
232 }
233 victim = &(*victim)->next;
234 }
235
236 /* remove from list */
237 *victim = dyn->next;
238 dyn->next = NULL;
239
240 /* assure there is no id left */
241 dyn->num_id = 0;
242
243 tds_release_dynamic(&dyn);
244 }
245
246
247 /**
248 * \fn void tds_release_dynamic(TDSDYNAMIC **pdyn)
249 * \brief Frees dynamic statement
250 * \param pdyn pointer to dynamic statement to be freed.
251 */
252 void
tds_release_dynamic(TDSDYNAMIC ** pdyn)253 tds_release_dynamic(TDSDYNAMIC ** pdyn)
254 {
255 TDSDYNAMIC *dyn;
256
257 dyn = *pdyn;
258 *pdyn = NULL;
259 if (!dyn || --dyn->ref_count > 0)
260 return;
261
262 tds_detach_results(dyn->res_info);
263
264 tds_free_results(dyn->res_info);
265 tds_free_input_params(dyn);
266 free(dyn->query);
267 free(dyn);
268 }
269
270 /**
271 * \fn TDSPARAMINFO *tds_alloc_param_result(TDSPARAMINFO *old_param)
272 * \brief Adds a output parameter to TDSPARAMINFO.
273 * \param old_param a pointer to the TDSPARAMINFO structure containing the
274 * current set of output parameter, or NULL if none exists.
275 * \return a pointer to the new TDSPARAMINFO structure.
276 *
277 * tds_alloc_param_result() works a bit differently than the other alloc result
278 * functions. Output parameters come in individually with no total number
279 * given in advance, so we simply call this func every time with get a
280 * TDS_PARAM_TOKEN and let it realloc the columns struct one bigger.
281 * tds_free_all_results() usually cleans up after us.
282 */
283 TDSPARAMINFO *
tds_alloc_param_result(TDSPARAMINFO * old_param)284 tds_alloc_param_result(TDSPARAMINFO * old_param)
285 {
286 TDSPARAMINFO *param_info;
287 TDSCOLUMN *colinfo;
288
289 /* parameters cannot have row associated */
290 if (old_param && (old_param->current_row || old_param->row_free))
291 return NULL;
292
293 colinfo = tds_alloc_column();
294 if (!colinfo)
295 return NULL;
296
297 param_info = old_param;
298 if (!param_info) {
299 TEST_MALLOC(param_info, TDSPARAMINFO);
300 param_info->ref_count = 1;
301 }
302
303 if (!TDS_RESIZE(param_info->columns, param_info->num_cols + 1u))
304 goto Cleanup;
305
306 param_info->columns[param_info->num_cols++] = colinfo;
307 return param_info;
308
309 Cleanup:
310 if (!old_param)
311 free(param_info);
312 free(colinfo);
313 return NULL;
314 }
315
316 /**
317 * Delete latest parameter
318 */
319 void
tds_free_param_result(TDSPARAMINFO * param_info)320 tds_free_param_result(TDSPARAMINFO * param_info)
321 {
322 TDSCOLUMN *col;
323
324 if (!param_info || param_info->num_cols <= 0)
325 return;
326
327 col = param_info->columns[--param_info->num_cols];
328 if (col->column_data && col->column_data_free)
329 col->column_data_free(col);
330
331 if (param_info->num_cols == 0)
332 TDS_ZERO_FREE(param_info->columns);
333
334 /*
335 * NOTE some informations should be freed too but when this function
336 * is called are not used. I hope to remove the need for this
337 * function ASAP
338 * A better way is to support different way to allocate and get
339 * parameters
340 * -- freddy77
341 */
342 tds_free_column(col);
343 }
344
345 static void
tds_param_free(TDSCOLUMN * col)346 tds_param_free(TDSCOLUMN *col)
347 {
348 if (!col->column_data)
349 return;
350
351 if (is_blob_col(col)) {
352 TDSBLOB *blob = (TDSBLOB *) col->column_data;
353 free(blob->textvalue);
354 }
355 TDS_ZERO_FREE(col->column_data);
356 }
357
358 /**
359 * Allocate data for a parameter.
360 * @param curparam parameter to retrieve size information
361 * @return NULL on failure or new data
362 */
363 void *
tds_alloc_param_data(TDSCOLUMN * curparam)364 tds_alloc_param_data(TDSCOLUMN * curparam)
365 {
366 TDS_INT data_size;
367 void *data;
368
369 CHECK_COLUMN_EXTRA(curparam);
370
371 data_size = curparam->funcs->row_len(curparam);
372
373 /* allocate data */
374 if (curparam->column_data && curparam->column_data_free)
375 curparam->column_data_free(curparam);
376 curparam->column_data_free = tds_param_free;
377
378 data = malloc(data_size);
379 curparam->column_data = (unsigned char*) data;
380 if (!data)
381 return NULL;
382 /* if is a blob reset buffer */
383 if (is_blob_col(curparam))
384 memset(data, 0, sizeof(TDSBLOB));
385
386 return data;
387 }
388
389 /**
390 * Allocate memory for storing compute info
391 * return NULL on out of memory
392 */
393
394 static TDSCOMPUTEINFO *
tds_alloc_compute_result(TDS_USMALLINT num_cols,TDS_USMALLINT by_cols)395 tds_alloc_compute_result(TDS_USMALLINT num_cols, TDS_USMALLINT by_cols)
396 {
397 TDS_USMALLINT col;
398 TDSCOMPUTEINFO *info;
399
400 TEST_MALLOC(info, TDSCOMPUTEINFO);
401 info->ref_count = 1;
402
403 TEST_CALLOC(info->columns, TDSCOLUMN *, num_cols);
404
405 info->num_cols = num_cols;
406 for (col = 0; col < num_cols; col++)
407 if (!(info->columns[col] = tds_alloc_column()))
408 goto Cleanup;
409
410 if (by_cols) {
411 TEST_CALLOC(info->bycolumns, TDS_SMALLINT, by_cols);
412 info->by_cols = by_cols;
413 }
414
415 return info;
416 Cleanup:
417 tds_free_compute_result(info);
418 return NULL;
419 }
420
421 TDSCOMPUTEINFO **
tds_alloc_compute_results(TDSSOCKET * tds,TDS_USMALLINT num_cols,TDS_USMALLINT by_cols)422 tds_alloc_compute_results(TDSSOCKET * tds, TDS_USMALLINT num_cols, TDS_USMALLINT by_cols)
423 {
424 TDS_UINT n;
425 TDSCOMPUTEINFO **comp_info;
426 TDSCOMPUTEINFO *cur_comp_info;
427
428 tdsdump_log(TDS_DBG_FUNC, "alloc_compute_result. num_cols = %d bycols = %d\n", num_cols, by_cols);
429 tdsdump_log(TDS_DBG_FUNC, "alloc_compute_result. num_comp_info = %d\n", tds->num_comp_info);
430
431 cur_comp_info = tds_alloc_compute_result(num_cols, by_cols);
432 if (!cur_comp_info)
433 return NULL;
434
435 n = tds->num_comp_info;
436 comp_info = (TDSCOMPUTEINFO **) TDS_RESIZE(tds->comp_info, n + 1u);
437 if (!comp_info) {
438 tds_free_compute_result(cur_comp_info);
439 return NULL;
440 }
441
442 tds->comp_info = comp_info;
443 comp_info[n] = cur_comp_info;
444 tds->num_comp_info = n + 1u;
445
446 tdsdump_log(TDS_DBG_FUNC, "alloc_compute_result. num_comp_info = %d\n", tds->num_comp_info);
447
448 return comp_info;
449 }
450
451 TDSRESULTINFO *
tds_alloc_results(TDS_USMALLINT num_cols)452 tds_alloc_results(TDS_USMALLINT num_cols)
453 {
454 TDSRESULTINFO *res_info;
455 TDS_USMALLINT col;
456
457 TEST_MALLOC(res_info, TDSRESULTINFO);
458 res_info->ref_count = 1;
459 if (num_cols)
460 TEST_CALLOC(res_info->columns, TDSCOLUMN *, num_cols);
461 for (col = 0; col < num_cols; col++)
462 if (!(res_info->columns[col] = tds_alloc_column()))
463 goto Cleanup;
464 res_info->num_cols = num_cols;
465 res_info->row_size = 0;
466 return res_info;
467 Cleanup:
468 tds_free_results(res_info);
469 return NULL;
470 }
471
472 void
tds_set_current_results(TDSSOCKET * tds,TDSRESULTINFO * info)473 tds_set_current_results(TDSSOCKET *tds, TDSRESULTINFO *info)
474 {
475 tds_detach_results(info);
476 if (tds->current_results)
477 tds->current_results->attached_to = NULL;
478 if (info)
479 info->attached_to = tds;
480 tds->in_row = (info != NULL);
481 tds->current_results = info;
482 }
483
484 /**
485 * Detach result info from it current socket
486 */
487 void
tds_detach_results(TDSRESULTINFO * info)488 tds_detach_results(TDSRESULTINFO *info)
489 {
490 if (info && info->attached_to) {
491 info->attached_to->current_results = NULL;
492 info->attached_to->in_row = false;
493 info->attached_to = NULL;
494 }
495 }
496
497 static void
tds_row_free(TDSRESULTINFO * res_info,unsigned char * row)498 tds_row_free(TDSRESULTINFO *res_info, unsigned char *row)
499 {
500 int i;
501 const TDSCOLUMN *col;
502
503 if (!res_info || !row)
504 return;
505
506 for (i = 0; i < res_info->num_cols; ++i) {
507 col = res_info->columns[i];
508
509 if (is_blob_col(col)) {
510 TDSBLOB *blob = (TDSBLOB *) &row[col->column_data - res_info->current_row];
511 if (blob->textvalue)
512 TDS_ZERO_FREE(blob->textvalue);
513 }
514 }
515
516 free(row);
517 }
518
519 /**
520 * Allocate space for row store
521 * return NULL on out of memory
522 */
523 TDSRET
tds_alloc_row(TDSRESULTINFO * res_info)524 tds_alloc_row(TDSRESULTINFO * res_info)
525 {
526 int i, num_cols = res_info->num_cols;
527 unsigned char *ptr;
528 TDSCOLUMN *col;
529 TDS_UINT row_size;
530
531 /* compute row size */
532 row_size = 0;
533 for (i = 0; i < num_cols; ++i) {
534 col = res_info->columns[i];
535
536 col->column_data_free = NULL;
537
538 row_size += col->funcs->row_len(col);
539 row_size += (TDS_ALIGN_SIZE - 1);
540 row_size -= row_size % TDS_ALIGN_SIZE;
541 }
542 res_info->row_size = row_size;
543
544 ptr = tds_new0(unsigned char, res_info->row_size);
545 res_info->current_row = ptr;
546 if (!ptr)
547 return TDS_FAIL;
548 res_info->row_free = tds_row_free;
549
550 /* fill column_data */
551 row_size = 0;
552 for (i = 0; i < num_cols; ++i) {
553 col = res_info->columns[i];
554
555 col->column_data = ptr + row_size;
556
557 row_size += col->funcs->row_len(col);
558 row_size += (TDS_ALIGN_SIZE - 1);
559 row_size -= row_size % TDS_ALIGN_SIZE;
560 }
561
562 return TDS_SUCCESS;
563 }
564
565 TDSRET
tds_alloc_compute_row(TDSCOMPUTEINFO * res_info)566 tds_alloc_compute_row(TDSCOMPUTEINFO * res_info)
567 {
568 return tds_alloc_row(res_info);
569 }
570
571 void
tds_free_param_results(TDSPARAMINFO * param_info)572 tds_free_param_results(TDSPARAMINFO * param_info)
573 {
574 tds_free_results(param_info);
575 }
576
577 static void
tds_free_compute_result(TDSCOMPUTEINFO * comp_info)578 tds_free_compute_result(TDSCOMPUTEINFO * comp_info)
579 {
580 tds_free_results(comp_info);
581 }
582
583 static void
tds_free_compute_results(TDSSOCKET * tds)584 tds_free_compute_results(TDSSOCKET * tds)
585 {
586 TDSCOMPUTEINFO ** comp_info = tds->comp_info;
587 TDS_UINT i, num_comp = tds->num_comp_info;
588
589 tds->comp_info = NULL;
590 tds->num_comp_info = 0;
591
592 for (i = 0; i < num_comp; i++) {
593 if (comp_info && comp_info[i]) {
594 tds_detach_results(comp_info[i]);
595 tds_free_compute_result(comp_info[i]);
596 }
597 }
598 if (num_comp)
599 free(comp_info);
600 }
601
602 void
tds_free_row(TDSRESULTINFO * res_info,unsigned char * row)603 tds_free_row(TDSRESULTINFO * res_info, unsigned char *row)
604 {
605 assert(res_info);
606 if (!row || !res_info->row_free)
607 return;
608
609 res_info->row_free(res_info, row);
610 }
611
612 void
tds_free_results(TDSRESULTINFO * res_info)613 tds_free_results(TDSRESULTINFO * res_info)
614 {
615 int i;
616 TDSCOLUMN *curcol;
617
618 if (!res_info)
619 return;
620
621 if (--res_info->ref_count != 0)
622 return;
623
624 tds_detach_results(res_info);
625
626 if (res_info->num_cols && res_info->columns) {
627 for (i = 0; i < res_info->num_cols; i++)
628 if ((curcol = res_info->columns[i]) != NULL) {
629 if (curcol->bcp_terminator)
630 TDS_ZERO_FREE(curcol->bcp_terminator);
631 tds_free_bcp_column_data(curcol->bcp_column_data);
632 curcol->bcp_column_data = NULL;
633 if (curcol->column_data && curcol->column_data_free)
634 curcol->column_data_free(curcol);
635 }
636 }
637
638 if (res_info->current_row && res_info->row_free)
639 res_info->row_free(res_info, res_info->current_row);
640
641 if (res_info->num_cols && res_info->columns) {
642 for (i = 0; i < res_info->num_cols; i++)
643 if ((curcol = res_info->columns[i]) != NULL)
644 tds_free_column(curcol);
645 free(res_info->columns);
646 }
647
648 free(res_info->bycolumns);
649
650 free(res_info);
651 }
652
653 void
tds_free_all_results(TDSSOCKET * tds)654 tds_free_all_results(TDSSOCKET * tds)
655 {
656 tdsdump_log(TDS_DBG_FUNC, "tds_free_all_results()\n");
657 tds_detach_results(tds->res_info);
658 tds_free_results(tds->res_info);
659 tds->res_info = NULL;
660 tds_detach_results(tds->param_info);
661 tds_free_param_results(tds->param_info);
662 tds->param_info = NULL;
663 tds_free_compute_results(tds);
664 tds->has_status = false;
665 tds->in_row = false;
666 tds->ret_status = 0;
667 if (tds->cur_dyn)
668 tds_detach_results(tds->cur_dyn->res_info);
669 }
670
671 /*
672 * Return 1 if winsock is initialized, else 0.
673 */
674 static int
winsock_initialized(void)675 winsock_initialized(void)
676 {
677 #if defined(_WIN32) || defined(_WIN64)
678 static bool initialized = false;
679 static tds_mutex mtx = TDS_MUTEX_INITIALIZER;
680
681 WSADATA wsa_data;
682 int erc;
683
684 if (initialized)
685 return 1;
686
687 tds_mutex_lock(&mtx);
688 /* same check inside the mutex */
689 if (initialized) {
690 tds_mutex_unlock(&mtx);
691 return 1;
692 }
693
694 /* initialize the socket layer */
695 erc = WSAStartup(MAKEWORD(2, 2), &wsa_data);
696 initialized = (erc == 0);
697 tds_mutex_unlock(&mtx);
698
699 if (erc != 0) {
700 char *errstr = sock_strerror(erc);
701 tdsdump_log(TDS_DBG_ERROR, "tds_init_winsock: WSAStartup failed with %d (%s)\n", erc, errstr);
702 sock_strerror_free(errstr);
703 return 0;
704 }
705 #endif
706 return 1;
707 }
708
709 TDSCONTEXT *
tds_alloc_context(void * parent)710 tds_alloc_context(void * parent)
711 {
712 TDSCONTEXT *context;
713 TDSLOCALE *locale;
714
715 if (!winsock_initialized())
716 return NULL;
717
718 if ((locale = tds_get_locale()) == NULL)
719 return NULL;
720
721 if ((context = tds_new0(TDSCONTEXT, 1)) == NULL) {
722 tds_free_locale(locale);
723 return NULL;
724 }
725 context->locale = locale;
726 context->parent = parent;
727 context->money_use_2_digits = false;
728
729 return context;
730 }
731
732 void
tds_free_context(TDSCONTEXT * context)733 tds_free_context(TDSCONTEXT * context)
734 {
735 if (!context)
736 return;
737
738 tds_free_locale(context->locale);
739 free(context);
740 }
741
742 TDSLOCALE *
tds_alloc_locale(void)743 tds_alloc_locale(void)
744 {
745 TDSLOCALE *locale;
746
747 TEST_MALLOC(locale, TDSLOCALE);
748
749 return locale;
750
751 Cleanup:
752 tds_free_locale(locale);
753 return NULL;
754 }
755
756 /*
757 * Default capabilities.
758 */
759 #undef REQ
760 #define SUPPORTED_REQ_CAP(i) \
761 REQ(i,LANG) REQ(i,RPC) REQ(i,EVT) REQ(i,MSTMT) REQ(i,BCP) REQ(i,CURSOR) REQ(i,DYNF) \
762 REQ(i,MSG) REQ(i,PARAM) REQ(i,DATA_INT1) REQ(i,DATA_INT2) REQ(i,DATA_INT4) REQ(i,DATA_BIT) \
763 REQ(i,DATA_CHAR) REQ(i,DATA_VCHAR) REQ(i,DATA_BIN) REQ(i,DATA_VBIN) REQ(i,DATA_MNY8) \
764 REQ(i,DATA_MNY4) REQ(i,DATA_DATE8) REQ(i,DATA_DATE4) REQ(i,DATA_FLT4) REQ(i,DATA_FLT8) \
765 REQ(i,DATA_NUM) REQ(i,DATA_TEXT) REQ(i,DATA_IMAGE) REQ(i,DATA_DEC) REQ(i,DATA_LCHAR) \
766 REQ(i,DATA_LBIN) REQ(i,DATA_INTN) REQ(i,DATA_DATETIMEN) REQ(i,DATA_MONEYN) \
767 REQ(i,CSR_PREV) REQ(i,CSR_FIRST) REQ(i,CSR_LAST) REQ(i,CSR_ABS) REQ(i,CSR_REL) \
768 REQ(i,CSR_MULTI) REQ(i,CON_INBAND) REQ(i,PROTO_TEXT) REQ(i,PROTO_BULK) \
769 REQ(i,DATA_SENSITIVITY) REQ(i,DATA_BOUNDARY) REQ(i,PROTO_DYNPROC) REQ(i,DATA_FLTN) \
770 REQ(i,DATA_BITN) REQ(i,DATA_INT8) REQ(i,WIDETABLE) \
771 REQ(i,DATA_UINT2) REQ(i,DATA_UINT4) REQ(i,DATA_UINT8) REQ(i,DATA_UINTN) REQ(i,LARGEIDENT) \
772 REQ(i,SRVPKTSIZE) REQ(i,DATA_DATE) REQ(i,DATA_TIME) REQ(i,DATA_BIGTIME) REQ(i,DATA_BIGDATETIME)
773 #define REQ(i,n) |(((TDS_REQ_ ## n / 8) == i)?(1<<(TDS_REQ_ ## n & 7)):0)
774 #define REQB(i) 0 SUPPORTED_REQ_CAP(i)
775
776 #undef RES
777 #define SUPPORTED_RES_CAP(i) \
778 RES(i,CON_NOOOB) RES(i,PROTO_NOTEXT) RES(i,PROTO_NOBULK) RES(i,NOTDSDEBUG)
779 #define RES(i,n) |(((TDS_RES_ ## n / 8) == i)?(1<<(TDS_RES_ ## n & 7)):0)
780 #define RESB(i) 0 SUPPORTED_RES_CAP(i)
781
782 static const TDS_CAPABILITIES defaultcaps = { {
783 /* type, len, data, data, data, data, data, data, data, data, data, data, data, data, data, data (14 bytes) */
784 { 1, 14, { REQB(13), REQB(12), REQB(11), REQB(10), REQB(9), REQB(8), REQB(7),
785 REQB(6), REQB(5), REQB(4), REQB(3), REQB(2), REQB(1), REQB(0) } },
786 { 2, 14, { RESB(13), RESB(12), RESB(11), RESB(10), RESB(9), RESB(8), RESB(7),
787 RESB(6), RESB(5), RESB(4), RESB(3), RESB(2), RESB(1), RESB(0) } }
788 } };
789 /* check we match the values size */
790 TDS_COMPILE_CHECK(tds_values_len, sizeof(defaultcaps.types[0].values) == 14);
791 /* check we match the default size */
792 TDS_COMPILE_CHECK(tds_cap_len, sizeof(defaultcaps) == TDS_MAX_CAPABILITY);
793
794 /**
795 * Initialize login structure with locale information and other stuff for connection
796 * @param locale locale information (copied to configuration information)
797 * @result login structure or NULL if initialization error
798 */
799 TDSLOGIN*
tds_init_login(TDSLOGIN * login,TDSLOCALE * locale)800 tds_init_login(TDSLOGIN *login, TDSLOCALE * locale)
801 {
802 char hostname[128];
803 #if HAVE_NL_LANGINFO && defined(CODESET)
804 const char *charset;
805 #else
806 char *lc_all, *tok = NULL;
807 #endif
808
809 /*
810 * TDS 7.0:
811 * ODBC driver settings.
812 * Change to initial language must succeed.
813 */
814 login->option_flag2 = TDS_INIT_LANG_REQUIRED|TDS_ODBC_ON;
815 login->tds_version = TDS_DEFAULT_VERSION;
816 login->block_size = 0;
817
818 #if HAVE_NL_LANGINFO && defined(CODESET)
819 charset = nl_langinfo(CODESET);
820 if (strcmp(tds_canonical_charset_name(charset), "US-ASCII") == 0)
821 charset = "ISO-8859-1";
822 if (!tds_dstr_copy(&login->client_charset, charset))
823 return NULL;
824 #else
825 if (!tds_dstr_copy(&login->client_charset, "ISO-8859-1"))
826 return NULL;
827
828 if ((lc_all = strdup(setlocale(LC_ALL, NULL))) == NULL)
829 return NULL;
830
831 if (strtok_r(lc_all, ".", &tok)) {
832 char *encoding = strtok_r(NULL, "@", &tok);
833 #ifdef _WIN32
834 /* windows give numeric codepage*/
835 if (encoding && atoi(encoding) > 0) {
836 char *p;
837 if (asprintf(&p, "CP%s", encoding) >= 0) {
838 free(lc_all);
839 lc_all = encoding = p;
840 }
841 }
842 #endif
843 if (encoding) {
844 if (!tds_dstr_copy(&login->client_charset, encoding))
845 return NULL;
846 }
847 }
848 free(lc_all);
849 #endif
850
851 if (locale) {
852 if (locale->language)
853 if (!tds_dstr_copy(&login->language, locale->language))
854 return NULL;
855 if (locale->server_charset)
856 if (!tds_dstr_copy(&login->server_charset, locale->server_charset))
857 return NULL;
858 }
859 if (tds_dstr_isempty(&login->language)) {
860 if (!tds_dstr_copy(&login->language, TDS_DEF_LANG))
861 return NULL;
862 }
863 memset(hostname, '\0', sizeof(hostname));
864 gethostname(hostname, sizeof(hostname));
865 hostname[sizeof(hostname) - 1] = '\0'; /* make sure it's terminated */
866 if (!tds_dstr_copy(&login->client_host_name, hostname))
867 return NULL;
868
869 login->valid_configuration = 1;
870 login->check_ssl_hostname = 1;
871
872 return login;
873 }
874
875 TDSCURSOR *
tds_alloc_cursor(TDSSOCKET * tds,const char * name,TDS_INT namelen,const char * query,TDS_INT querylen)876 tds_alloc_cursor(TDSSOCKET *tds, const char *name, TDS_INT namelen, const char *query, TDS_INT querylen)
877 {
878 TDSCURSOR *cursor;
879 TDSCURSOR *pcursor;
880
881 TEST_MALLOC(cursor, TDSCURSOR);
882 cursor->ref_count = 1;
883
884 cursor->type = TDS_CUR_TYPE_KEYSET;
885 cursor->concurrency = TDS_CUR_CONCUR_OPTIMISTIC;
886
887 TEST_CALLOC(cursor->cursor_name, char, namelen + 1);
888 memcpy(cursor->cursor_name, name, namelen);
889
890 TEST_CALLOC(cursor->query, char, querylen + 1);
891 memcpy(cursor->query, query, querylen);
892
893 if (tds->conn->cursors == NULL) {
894 tds->conn->cursors = cursor;
895 } else {
896 for (pcursor = tds->conn->cursors; pcursor->next; pcursor = pcursor->next)
897 continue;
898 pcursor->next = cursor;
899 }
900 /* take into account reference in connection list */
901 ++cursor->ref_count;
902
903 return cursor;
904
905 Cleanup:
906 tds_release_cursor(&cursor);
907 return NULL;
908 }
909
910 /*
911 * Called when cursor got deallocated from server
912 */
913 void
tds_cursor_deallocated(TDSCONNECTION * conn,TDSCURSOR * cursor)914 tds_cursor_deallocated(TDSCONNECTION *conn, TDSCURSOR *cursor)
915 {
916 TDSCURSOR **victim;
917
918 tdsdump_log(TDS_DBG_FUNC, "tds_cursor_deallocated() : freeing cursor_id %d\n", cursor->cursor_id);
919
920 victim = &conn->cursors;
921 while (*victim != cursor) {
922 if (*victim == NULL) {
923 tdsdump_log(TDS_DBG_FUNC, "tds_cursor_deallocated() : cannot find cursor_id %d\n", cursor->cursor_id);
924 return;
925 }
926 victim = &(*victim)->next;
927 }
928
929 /* remove from list */
930 *victim = cursor->next;
931 cursor->next = NULL;
932
933 tds_release_cursor(&cursor);
934 }
935
936 /*
937 * Decrement reference counter and free if necessary.
938 * Called internally by libTDS and by upper library when you don't need
939 * cursor reference anymore
940 */
941 void
tds_release_cursor(TDSCURSOR ** pcursor)942 tds_release_cursor(TDSCURSOR **pcursor)
943 {
944 TDSCURSOR *cursor = *pcursor;
945 *pcursor = NULL;
946 if (!cursor || --cursor->ref_count > 0)
947 return;
948
949 tdsdump_log(TDS_DBG_FUNC, "tds_release_cursor() : freeing cursor_id %d\n", cursor->cursor_id);
950
951 tdsdump_log(TDS_DBG_FUNC, "tds_release_cursor() : freeing cursor results\n");
952 tds_detach_results(cursor->res_info);
953 tds_free_results(cursor->res_info);
954
955 if (cursor->cursor_name) {
956 tdsdump_log(TDS_DBG_FUNC, "tds_release_cursor() : freeing cursor name\n");
957 free(cursor->cursor_name);
958 }
959
960 if (cursor->query) {
961 tdsdump_log(TDS_DBG_FUNC, "tds_release_cursor() : freeing cursor query\n");
962 free(cursor->query);
963 }
964
965 tdsdump_log(TDS_DBG_FUNC, "tds_release_cursor() : cursor_id %d freed\n", cursor->cursor_id);
966 free(cursor);
967 }
968
969 TDSLOGIN *
tds_alloc_login(int use_environment)970 tds_alloc_login(int use_environment)
971 {
972 TDSLOGIN *login = NULL;
973 const char *server_name = TDS_DEF_SERVER;
974
975 TEST_MALLOC(login, TDSLOGIN);
976 login->check_ssl_hostname = 1;
977 login->use_utf16 = 1;
978 login->bulk_copy = 1;
979 tds_dstr_init(&login->server_name);
980 tds_dstr_init(&login->language);
981 tds_dstr_init(&login->server_charset);
982 tds_dstr_init(&login->client_host_name);
983 tds_dstr_init(&login->server_host_name);
984 tds_dstr_init(&login->app_name);
985 tds_dstr_init(&login->user_name);
986 tds_dstr_init(&login->password);
987 tds_dstr_init(&login->library);
988 tds_dstr_init(&login->new_password);
989
990 login->ip_addrs = NULL;
991
992 tds_dstr_init(&login->database);
993 tds_dstr_init(&login->dump_file);
994 tds_dstr_init(&login->client_charset);
995 tds_dstr_init(&login->instance_name);
996 tds_dstr_init(&login->server_realm_name);
997 tds_dstr_init(&login->server_spn);
998 tds_dstr_init(&login->cafile);
999 tds_dstr_init(&login->crlfile);
1000 tds_dstr_init(&login->db_filename);
1001 tds_dstr_init(&login->openssl_ciphers);
1002 tds_dstr_init(&login->routing_address);
1003
1004 if (use_environment) {
1005 const char *s;
1006 if ((s=getenv("DSQUERY")) != NULL)
1007 server_name = s;
1008
1009 if ((s=getenv("TDSQUERY")) != NULL)
1010 server_name = s;
1011 }
1012
1013 if (!tds_dstr_copy(&login->server_name, server_name)) {
1014 free(login);
1015 return NULL;
1016 }
1017
1018 login->capabilities = defaultcaps;
1019 login->use_ntlmv2_specified = 0;
1020 login->use_ntlmv2 = 1;
1021 login->enable_tls_v1 = 1;
1022
1023 Cleanup:
1024 return login;
1025 }
1026
1027 void
tds_free_login(TDSLOGIN * login)1028 tds_free_login(TDSLOGIN * login)
1029 {
1030 if (!login)
1031 return;
1032
1033 /* for security reason clear memory */
1034 tds_dstr_zero(&login->password);
1035 tds_dstr_free(&login->password);
1036 tds_dstr_zero(&login->new_password);
1037 tds_dstr_free(&login->new_password);
1038 tds_dstr_free(&login->server_name);
1039 tds_dstr_free(&login->language);
1040 tds_dstr_free(&login->server_charset);
1041 tds_dstr_free(&login->client_host_name);
1042 tds_dstr_free(&login->app_name);
1043 tds_dstr_free(&login->user_name);
1044 tds_dstr_free(&login->library);
1045 tds_dstr_free(&login->client_charset);
1046 tds_dstr_free(&login->server_host_name);
1047
1048 if (login->ip_addrs != NULL)
1049 freeaddrinfo(login->ip_addrs);
1050
1051 tds_dstr_free(&login->database);
1052 tds_dstr_free(&login->dump_file);
1053 tds_dstr_free(&login->instance_name);
1054 tds_dstr_free(&login->server_realm_name);
1055 tds_dstr_free(&login->server_spn);
1056 tds_dstr_free(&login->cafile);
1057 tds_dstr_free(&login->crlfile);
1058 tds_dstr_free(&login->db_filename);
1059 tds_dstr_free(&login->openssl_ciphers);
1060 tds_dstr_free(&login->routing_address);
1061 free(login);
1062 }
1063
1064 TDSPACKET *
tds_alloc_packet(void * buf,unsigned len)1065 tds_alloc_packet(void *buf, unsigned len)
1066 {
1067 TDSPACKET *packet = (TDSPACKET *) malloc(len + TDS_OFFSET(TDSPACKET, buf));
1068 if (TDS_LIKELY(packet)) {
1069 tds_packet_zero_data_start(packet);
1070 packet->data_len = 0;
1071 packet->capacity = len;
1072 packet->sid = 0;
1073 packet->next = NULL;
1074 if (buf) {
1075 memcpy(packet->buf, buf, len);
1076 packet->data_len = len;
1077 }
1078 }
1079 return packet;
1080 }
1081
1082 TDSPACKET *
tds_realloc_packet(TDSPACKET * packet,unsigned len)1083 tds_realloc_packet(TDSPACKET *packet, unsigned len)
1084 {
1085 if (packet->capacity < len) {
1086 packet = (TDSPACKET *) realloc(packet, len + TDS_OFFSET(TDSPACKET, buf));
1087 if (TDS_LIKELY(packet))
1088 packet->capacity = len;
1089 }
1090 return packet;
1091 }
1092
1093 void
tds_free_packets(TDSPACKET * packet)1094 tds_free_packets(TDSPACKET *packet)
1095 {
1096 TDSPACKET *next;
1097 for (; packet; packet = next) {
1098 next = packet->next;
1099 free(packet);
1100 }
1101 }
1102
1103 static void
tds_deinit_connection(TDSCONNECTION * conn)1104 tds_deinit_connection(TDSCONNECTION *conn)
1105 {
1106 if (conn->authentication)
1107 conn->authentication->free(conn, conn->authentication);
1108 conn->authentication = NULL;
1109 while (conn->dyns)
1110 tds_dynamic_deallocated(conn, conn->dyns);
1111 while (conn->cursors)
1112 tds_cursor_deallocated(conn, conn->cursors);
1113 tds_ssl_deinit(conn);
1114 /* close connection and free inactive sockets */
1115 tds_connection_close(conn);
1116 tds_wakeup_close(&conn->wakeup);
1117 tds_iconv_free(conn);
1118 free(conn->product_name);
1119 free(conn->server);
1120 tds_free_env(conn);
1121 tds_free_packets(conn->packet_cache);
1122 tds_mutex_free(&conn->list_mtx);
1123 #if ENABLE_ODBC_MARS
1124 tds_free_packets(conn->packets);
1125 tds_free_packets(conn->recv_packet);
1126 tds_free_packets(conn->send_packets);
1127 free(conn->sessions);
1128 #endif
1129 }
1130
1131 static TDSCONNECTION *
tds_init_connection(TDSCONNECTION * conn,TDSCONTEXT * context,unsigned int bufsize)1132 tds_init_connection(TDSCONNECTION *conn, TDSCONTEXT *context, unsigned int bufsize)
1133 {
1134 conn->env.block_size = bufsize;
1135 conn->s = INVALID_SOCKET;
1136 conn->use_iconv = 1;
1137 conn->tds_ctx = context;
1138
1139 if (tds_wakeup_init(&conn->wakeup))
1140 goto Cleanup;
1141
1142 if (tds_iconv_alloc(conn))
1143 goto Cleanup;
1144
1145 if (tds_mutex_init(&conn->list_mtx))
1146 goto Cleanup;
1147
1148 #if ENABLE_ODBC_MARS
1149 TEST_CALLOC(conn->sessions, TDSSOCKET*, 64);
1150 conn->num_sessions = 64;
1151 #endif
1152 return conn;
1153
1154 Cleanup:
1155 tds_wakeup_close(&conn->wakeup);
1156 tds_iconv_free(conn);
1157 return NULL;
1158 }
1159
1160 static TDSSOCKET *
tds_init_socket(TDSSOCKET * tds_socket,unsigned int bufsize)1161 tds_init_socket(TDSSOCKET * tds_socket, unsigned int bufsize)
1162 {
1163 TDSPACKET *pkt;
1164
1165 tds_socket->parent = NULL;
1166
1167 tds_socket->recv_packet = tds_alloc_packet(NULL, bufsize);
1168 if (!tds_socket->recv_packet)
1169 goto Cleanup;
1170 tds_socket->in_buf = tds_socket->recv_packet->buf;
1171
1172 pkt = tds_alloc_packet(NULL, bufsize + TDS_ADDITIONAL_SPACE);
1173 if (!pkt)
1174 goto Cleanup;
1175 tds_set_current_send_packet(tds_socket, pkt);
1176
1177 tds_socket->out_buf_max = bufsize;
1178
1179 /* Jeff's hack, init to no timeout */
1180 tds_socket->query_timeout = 0;
1181 tds_init_write_buf(tds_socket);
1182 tds_socket->state = TDS_DEAD;
1183 tds_socket->env_chg_func = NULL;
1184 if (tds_mutex_init(&tds_socket->wire_mtx))
1185 goto Cleanup;
1186
1187 #ifdef ENABLE_ODBC_MARS
1188 tds_socket->sid = 0;
1189 if (tds_cond_init(&tds_socket->packet_cond))
1190 goto Cleanup;
1191
1192 tds_socket->recv_seq = 0;
1193 tds_socket->send_seq = 0;
1194 tds_socket->recv_wnd = 4;
1195 tds_socket->send_wnd = 4;
1196 #endif
1197 return tds_socket;
1198
1199 Cleanup:
1200 return NULL;
1201 }
1202
1203
1204 #if ENABLE_ODBC_MARS
1205 static void
tds_free_connection(TDSCONNECTION * conn)1206 tds_free_connection(TDSCONNECTION *conn)
1207 {
1208 if (!conn) return;
1209 assert(conn->in_net_tds == NULL);
1210 tds_deinit_connection(conn);
1211 free(conn);
1212 }
1213
1214 static TDSCONNECTION *
tds_alloc_connection(TDSCONTEXT * context,unsigned int bufsize)1215 tds_alloc_connection(TDSCONTEXT *context, unsigned int bufsize)
1216 {
1217 TDSCONNECTION *conn;
1218
1219 TEST_MALLOC(conn, TDSCONNECTION);
1220 if (!tds_init_connection(conn, context, bufsize))
1221 goto Cleanup;
1222 return conn;
1223
1224 Cleanup:
1225 tds_free_connection(conn);
1226 return NULL;
1227 }
1228
1229 static TDSSOCKET *
tds_alloc_socket_base(unsigned int bufsize)1230 tds_alloc_socket_base(unsigned int bufsize)
1231 {
1232 TDSSOCKET *tds_socket;
1233
1234 TEST_MALLOC(tds_socket, TDSSOCKET);
1235 if (!tds_init_socket(tds_socket, bufsize))
1236 goto Cleanup;
1237 return tds_socket;
1238
1239 Cleanup:
1240 tds_free_socket(tds_socket);
1241 return NULL;
1242 }
1243
1244 TDSSOCKET *
tds_alloc_socket(TDSCONTEXT * context,unsigned int bufsize)1245 tds_alloc_socket(TDSCONTEXT * context, unsigned int bufsize)
1246 {
1247 TDSCONNECTION *conn = tds_alloc_connection(context, bufsize);
1248 TDSSOCKET *tds;
1249
1250 if (!conn)
1251 return NULL;
1252
1253 tds = tds_alloc_socket_base(bufsize);
1254 if (tds) {
1255 conn->sessions[0] = tds;
1256 tds->conn = conn;
1257 return tds;
1258 }
1259 tds_free_connection(conn);
1260 return NULL;
1261 }
1262
1263 static bool
tds_alloc_new_sid(TDSSOCKET * tds)1264 tds_alloc_new_sid(TDSSOCKET *tds)
1265 {
1266 uint16_t sid;
1267 TDSCONNECTION *conn = tds->conn;
1268
1269 tds_mutex_lock(&conn->list_mtx);
1270 for (sid = 1; sid < conn->num_sessions; ++sid)
1271 if (!conn->sessions[sid])
1272 break;
1273 if (sid == conn->num_sessions) {
1274 /* extend array */
1275 TDSSOCKET **s = (TDSSOCKET **) TDS_RESIZE(conn->sessions, sid+64);
1276 if (!s)
1277 goto error;
1278 memset(s + conn->num_sessions, 0, sizeof(*s) * 64);
1279 conn->num_sessions += 64;
1280 }
1281 conn->sessions[sid] = tds;
1282 tds->sid = sid;
1283 error:
1284 tds_mutex_unlock(&conn->list_mtx);
1285 return tds->sid != 0;
1286 }
1287
1288 TDSSOCKET *
tds_alloc_additional_socket(TDSCONNECTION * conn)1289 tds_alloc_additional_socket(TDSCONNECTION *conn)
1290 {
1291 TDSSOCKET *tds;
1292 if (!IS_TDS72_PLUS(conn) || !conn->mars)
1293 return NULL;
1294
1295 tds = tds_alloc_socket_base(sizeof(TDS72_SMP_HEADER) + conn->env.block_size);
1296 if (!tds)
1297 return NULL;
1298 tds->send_packet->data_start = sizeof(TDS72_SMP_HEADER);
1299 tds->out_buf = tds->send_packet->buf + sizeof(TDS72_SMP_HEADER);
1300 tds->out_buf_max -= sizeof(TDS72_SMP_HEADER);
1301
1302 tds->conn = conn;
1303 if (!tds_alloc_new_sid(tds))
1304 goto Cleanup;
1305
1306 tds->state = TDS_IDLE;
1307 if (TDS_FAILED(tds_append_syn(tds)))
1308 goto Cleanup;
1309
1310 return tds;
1311
1312 Cleanup:
1313 tds_free_socket(tds);
1314 return NULL;
1315 }
1316 #else /* !ENABLE_ODBC_MARS */
1317 TDSSOCKET *
tds_alloc_socket(TDSCONTEXT * context,unsigned int bufsize)1318 tds_alloc_socket(TDSCONTEXT * context, unsigned int bufsize)
1319 {
1320 TDSSOCKET *tds_socket;
1321
1322 TEST_MALLOC(tds_socket, TDSSOCKET);
1323 if (!tds_init_connection(tds_socket->conn, context, bufsize))
1324 goto Cleanup;
1325 if (!tds_init_socket(tds_socket, bufsize))
1326 goto Cleanup;
1327 return tds_socket;
1328
1329 Cleanup:
1330 tds_free_socket(tds_socket);
1331 return NULL;
1332 }
1333 #endif /* !ENABLE_ODBC_MARS */
1334
1335 TDSSOCKET *
tds_realloc_socket(TDSSOCKET * tds,size_t bufsize)1336 tds_realloc_socket(TDSSOCKET * tds, size_t bufsize)
1337 {
1338 TDSPACKET *packet;
1339 #if ENABLE_ODBC_MARS
1340 size_t smp_hdr_len = tds->conn->mars ? sizeof(TDS72_SMP_HEADER) : 0;
1341 #else
1342 enum { smp_hdr_len = 0 };
1343 #endif
1344
1345 assert(tds && tds->out_buf && tds->send_packet);
1346
1347 if (bufsize < 512)
1348 bufsize = 512;
1349
1350 /* prevent nasty memory conditions, server should send the request at
1351 * the beginning only */
1352 if (tds->out_pos > bufsize || tds->frozen)
1353 return NULL;
1354
1355 tds->conn->env.block_size = bufsize;
1356
1357 packet = tds_realloc_packet(tds->send_packet, smp_hdr_len + bufsize + TDS_ADDITIONAL_SPACE);
1358 if (packet == NULL)
1359 return NULL;
1360
1361 #if ENABLE_ODBC_MARS
1362 packet->data_start = smp_hdr_len;
1363 #endif
1364 tds->out_buf_max = bufsize;
1365 tds_set_current_send_packet(tds, packet);
1366 return tds;
1367 }
1368
1369 #if ENABLE_ODBC_MARS
1370 static void
tds_connection_remove_socket(TDSCONNECTION * conn,TDSSOCKET * tds)1371 tds_connection_remove_socket(TDSCONNECTION *conn, TDSSOCKET *tds)
1372 {
1373 unsigned n;
1374 bool must_free_connection = true;
1375 tds_mutex_lock(&conn->list_mtx);
1376 if (tds->sid < conn->num_sessions)
1377 conn->sessions[tds->sid] = NULL;
1378 for (n = 0; n < conn->num_sessions; ++n)
1379 if (TDSSOCKET_VALID(conn->sessions[n])) {
1380 must_free_connection = false;
1381 break;
1382 }
1383 if (!must_free_connection) {
1384 /* tds use connection member so must be valid */
1385 tds_append_fin(tds);
1386 }
1387 tds_mutex_unlock(&conn->list_mtx);
1388
1389 /* detach entirely */
1390 tds->conn = NULL;
1391
1392 if (must_free_connection)
1393 tds_free_connection(conn);
1394 }
1395 #else
1396 static void inline
tds_connection_remove_socket(TDSCONNECTION * conn,TDSSOCKET * tds)1397 tds_connection_remove_socket(TDSCONNECTION *conn, TDSSOCKET *tds)
1398 {
1399 tds_deinit_connection(conn);
1400 }
1401 #endif
1402
1403 void
tds_free_socket(TDSSOCKET * tds)1404 tds_free_socket(TDSSOCKET * tds)
1405 {
1406 #if ENABLE_EXTRA_CHECKS
1407 TDSDYNAMIC *dyn;
1408 TDSCURSOR *cur;
1409 #endif
1410
1411 if (!tds)
1412 return;
1413
1414 /* detach this socket */
1415 tds_release_cur_dyn(tds);
1416 tds_release_cursor(&tds->cur_cursor);
1417 tds_detach_results(tds->current_results);
1418 #if ENABLE_EXTRA_CHECKS
1419 for (dyn = tds->conn->dyns; dyn; dyn = dyn->next) {
1420 if (dyn->res_info && dyn->res_info->attached_to == tds) {
1421 assert(0);
1422 }
1423 }
1424 for (cur = tds->conn->cursors; cur; cur = cur->next) {
1425 if (cur->res_info && cur->res_info->attached_to == tds) {
1426 assert(0);
1427 }
1428 }
1429 #endif
1430 tds_free_all_results(tds);
1431 #if ENABLE_ODBC_MARS
1432 tds_cond_destroy(&tds->packet_cond);
1433 #endif
1434
1435 tds_connection_remove_socket(tds->conn, tds);
1436 tds_free_packets(tds->recv_packet);
1437 if (tds->frozen_packets)
1438 tds_free_packets(tds->frozen_packets);
1439 else
1440 tds_free_packets(tds->send_packet);
1441 free(tds);
1442 }
1443
1444 void
tds_free_locale(TDSLOCALE * locale)1445 tds_free_locale(TDSLOCALE * locale)
1446 {
1447 if (!locale)
1448 return;
1449
1450 free(locale->language);
1451 free(locale->server_charset);
1452 free(locale->date_fmt);
1453 free(locale);
1454 }
1455
1456 static void
tds_free_env(TDSCONNECTION * conn)1457 tds_free_env(TDSCONNECTION* conn)
1458 {
1459 if (conn->env.language)
1460 TDS_ZERO_FREE(conn->env.language);
1461 if (conn->env.charset)
1462 TDS_ZERO_FREE(conn->env.charset);
1463 if (conn->env.database)
1464 TDS_ZERO_FREE(conn->env.database);
1465 }
1466
1467 void
tds_free_msg(TDSMESSAGE * message)1468 tds_free_msg(TDSMESSAGE * message)
1469 {
1470 if (message) {
1471 message->priv_msg_type = 0;
1472 message->msgno = 0;
1473 message->state = 0;
1474 message->severity = 0;
1475 message->line_number = 0;
1476 TDS_ZERO_FREE(message->message);
1477 TDS_ZERO_FREE(message->server);
1478 TDS_ZERO_FREE(message->proc_name);
1479 TDS_ZERO_FREE(message->sql_state);
1480 }
1481 }
1482
1483 #define SQLS_ENTRY(number,state) case number: p = state; break
1484
1485 char *
tds_alloc_client_sqlstate(int msgno)1486 tds_alloc_client_sqlstate(int msgno)
1487 {
1488 const char *p = NULL;
1489
1490 switch (msgno) {
1491 SQLS_ENTRY(17000, "S1T00"); /* timeouts ??? */
1492 SQLS_ENTRY(20004, "08S01"); /* Communication link failure */
1493 SQLS_ENTRY(20006, "08S01");
1494 SQLS_ENTRY(20009, "08S01");
1495 SQLS_ENTRY(20020, "08S01");
1496 SQLS_ENTRY(20019, "24000"); /* Invalid cursor state */
1497 SQLS_ENTRY(20014, "28000"); /* Invalid authorization specification */
1498 SQLS_ENTRY(2400, "42000"); /* Syntax error or access violation */
1499 SQLS_ENTRY(2401, "42000");
1500 SQLS_ENTRY(2403, "42000");
1501 SQLS_ENTRY(2404, "42000");
1502 SQLS_ENTRY(2402, "S1000"); /* General error */
1503 }
1504
1505 if (p != NULL)
1506 return strdup(p);
1507 else
1508 return NULL;
1509 }
1510
1511 char *
tds_alloc_lookup_sqlstate(TDSSOCKET * tds,int msgno)1512 tds_alloc_lookup_sqlstate(TDSSOCKET * tds, int msgno)
1513 {
1514 const char *p = NULL;
1515 char *q = NULL;
1516
1517 if (TDS_IS_MSSQL(tds)) {
1518 switch (msgno) { /* MSSQL Server */
1519
1520 SQLS_ENTRY(3621,"01000");
1521 SQLS_ENTRY(8153,"01003"); /* Null in aggregate */
1522 SQLS_ENTRY(911, "08004"); /* Server rejected connection */
1523 SQLS_ENTRY(512, "21000"); /* Subquery returns more than one value */
1524 SQLS_ENTRY(213, "21S01"); /* Insert column list mismatch */
1525 SQLS_ENTRY(109, "21S01");
1526 SQLS_ENTRY(110, "21S01");
1527 SQLS_ENTRY(1774,"21S02"); /* Ref column mismatch */
1528 SQLS_ENTRY(8152,"22001"); /* String data would be truncated */
1529 SQLS_ENTRY(5146,"22003"); /* Numeric value out of range */
1530 SQLS_ENTRY(168, "22003"); /* Arithmetic overflow */
1531 SQLS_ENTRY(220, "22003");
1532 SQLS_ENTRY(232, "22003");
1533 SQLS_ENTRY(234, "22003");
1534 SQLS_ENTRY(236, "22003");
1535 SQLS_ENTRY(238, "22003");
1536 SQLS_ENTRY(244, "22003");
1537 SQLS_ENTRY(246, "22003");
1538 SQLS_ENTRY(248, "22003");
1539 SQLS_ENTRY(519, "22003");
1540 SQLS_ENTRY(520, "22003");
1541 SQLS_ENTRY(521, "22003");
1542 SQLS_ENTRY(522, "22003");
1543 SQLS_ENTRY(523, "22003");
1544 SQLS_ENTRY(524, "22003");
1545 SQLS_ENTRY(1007,"22003");
1546 SQLS_ENTRY(3606,"22003");
1547 SQLS_ENTRY(8115,"22003");
1548 SQLS_ENTRY(206, "22005"); /* Error in assignment */
1549 SQLS_ENTRY(235, "22005");
1550 SQLS_ENTRY(247, "22005");
1551 SQLS_ENTRY(249, "22005");
1552 SQLS_ENTRY(256, "22005");
1553 SQLS_ENTRY(257, "22005");
1554 SQLS_ENTRY(305, "22005");
1555 SQLS_ENTRY(409, "22005");
1556 SQLS_ENTRY(518, "22005");
1557 SQLS_ENTRY(529, "22005");
1558 SQLS_ENTRY(210, "22007"); /* Invalid datetime format */
1559 SQLS_ENTRY(241, "22007");
1560 SQLS_ENTRY(295, "22007");
1561 SQLS_ENTRY(242, "22008"); /* Datetime out of range */
1562 SQLS_ENTRY(296, "22008");
1563 SQLS_ENTRY(298, "22008");
1564 SQLS_ENTRY(535, "22008");
1565 SQLS_ENTRY(542, "22008");
1566 SQLS_ENTRY(517, "22008");
1567 SQLS_ENTRY(3607, "22012"); /* Div by zero */
1568 SQLS_ENTRY(8134, "22012");
1569 SQLS_ENTRY(245, "22018"); /* Syntax error? */
1570 SQLS_ENTRY(2627, "23000"); /* Constraint violation */
1571 SQLS_ENTRY(515, "23000");
1572 SQLS_ENTRY(233, "23000");
1573 SQLS_ENTRY(273, "23000");
1574 SQLS_ENTRY(530, "23000");
1575 SQLS_ENTRY(2601,"23000");
1576 SQLS_ENTRY(2615,"23000");
1577 SQLS_ENTRY(2626,"23000");
1578 SQLS_ENTRY(3604,"23000");
1579 SQLS_ENTRY(3605,"23000");
1580 SQLS_ENTRY(544, "23000");
1581 SQLS_ENTRY(547, "23000");
1582 SQLS_ENTRY(550, "23000");
1583 SQLS_ENTRY(4415, "23000");
1584 SQLS_ENTRY(1505, "23000");
1585 SQLS_ENTRY(1508, "23000");
1586 SQLS_ENTRY(3725, "23000");
1587 SQLS_ENTRY(3726, "23000");
1588 SQLS_ENTRY(4712, "23000");
1589 SQLS_ENTRY(10055, "23000");
1590 SQLS_ENTRY(10065, "23000");
1591 SQLS_ENTRY(11011, "23000");
1592 SQLS_ENTRY(11040, "23000");
1593 SQLS_ENTRY(16999, "24000"); /* Invalid cursor state */
1594 SQLS_ENTRY(16905, "24000");
1595 SQLS_ENTRY(16917, "24000");
1596 SQLS_ENTRY(16946, "24000");
1597 SQLS_ENTRY(16950, "24000");
1598 SQLS_ENTRY(266, "25000"); /* Invalid transaction state */
1599 SQLS_ENTRY(277,"25000");
1600 SQLS_ENTRY(611,"25000");
1601 SQLS_ENTRY(3906,"25000");
1602 SQLS_ENTRY(3908,"25000");
1603 SQLS_ENTRY(6401,"25000");
1604 SQLS_ENTRY(626, "25000");
1605 SQLS_ENTRY(627, "25000");
1606 SQLS_ENTRY(628, "25000");
1607 SQLS_ENTRY(3902, "25000");
1608 SQLS_ENTRY(3903, "25000");
1609 SQLS_ENTRY(3916, "25000");
1610 SQLS_ENTRY(3918, "25000");
1611 SQLS_ENTRY(3919, "25000");
1612 SQLS_ENTRY(3921, "25000");
1613 SQLS_ENTRY(3922, "25000");
1614 SQLS_ENTRY(3926, "25000");
1615 SQLS_ENTRY(7969, "25000");
1616 SQLS_ENTRY(8506, "25000");
1617 SQLS_ENTRY(15626, "25000");
1618 SQLS_ENTRY(18456, "28000"); /* Login failed? */
1619 SQLS_ENTRY(6104, "37000"); /* Syntax error or access violation */
1620 SQLS_ENTRY(8114, "37000");
1621 SQLS_ENTRY(131, "37000");
1622 SQLS_ENTRY(137, "37000");
1623 SQLS_ENTRY(170, "37000");
1624 SQLS_ENTRY(174, "37000");
1625 SQLS_ENTRY(201, "37000");
1626 SQLS_ENTRY(2812, "37000");
1627 SQLS_ENTRY(2526, "37000");
1628 SQLS_ENTRY(8144, "37000");
1629 SQLS_ENTRY(17308, "42000"); /* Syntax/Access violation */
1630 SQLS_ENTRY(17571, "42000");
1631 SQLS_ENTRY(18002, "42000");
1632 SQLS_ENTRY(229, "42000");
1633 SQLS_ENTRY(230, "42000");
1634 SQLS_ENTRY(262, "42000");
1635 SQLS_ENTRY(2557, "42000");
1636 SQLS_ENTRY(2571, "42000");
1637 SQLS_ENTRY(2760, "42000");
1638 SQLS_ENTRY(3110, "42000");
1639 SQLS_ENTRY(3704, "42000");
1640 SQLS_ENTRY(4613, "42000");
1641 SQLS_ENTRY(4618, "42000");
1642 SQLS_ENTRY(4834, "42000");
1643 SQLS_ENTRY(5011, "42000");
1644 SQLS_ENTRY(5116, "42000");
1645 SQLS_ENTRY(5812, "42000");
1646 SQLS_ENTRY(6004, "42000");
1647 SQLS_ENTRY(6102, "42000");
1648 SQLS_ENTRY(7956, "42000");
1649 SQLS_ENTRY(11010, "42000");
1650 SQLS_ENTRY(11045, "42000");
1651 SQLS_ENTRY(14126, "42000");
1652 SQLS_ENTRY(15247, "42000");
1653 SQLS_ENTRY(15622, "42000");
1654 SQLS_ENTRY(20604, "42000");
1655 SQLS_ENTRY(21049, "42000");
1656 SQLS_ENTRY(113, "42000");
1657 SQLS_ENTRY(2714, "42S01"); /* Table or view already exists */
1658 SQLS_ENTRY(208, "42S02"); /* Table or view not found */
1659 SQLS_ENTRY(3701, "42S02");
1660 SQLS_ENTRY(1913, "42S11"); /* Index already exists */
1661 SQLS_ENTRY(15605, "42S11");
1662 SQLS_ENTRY(307, "42S12"); /* Index not found */
1663 SQLS_ENTRY(308, "42S12");
1664 SQLS_ENTRY(10033, "42S12");
1665 SQLS_ENTRY(15323, "42S12");
1666 SQLS_ENTRY(18833, "42S12");
1667 SQLS_ENTRY(4925, "42S21"); /* Column already exists */
1668 SQLS_ENTRY(21255, "42S21");
1669 SQLS_ENTRY(1911, "42S22"); /* Column not found */
1670 SQLS_ENTRY(207, "42S22");
1671 SQLS_ENTRY(4924, "42S22");
1672 SQLS_ENTRY(4926, "42S22");
1673 SQLS_ENTRY(15645, "42S22");
1674 SQLS_ENTRY(21166, "42S22");
1675 }
1676 } else {
1677 switch (msgno) { /* Sybase */
1678 SQLS_ENTRY(3621, "01000");
1679 SQLS_ENTRY(9501, "01003"); /* Null in aggregate */
1680 SQLS_ENTRY(911, "08004"); /* Server rejected connection */
1681 SQLS_ENTRY(512, "21000"); /* Subquery returns more than one value */
1682 SQLS_ENTRY(213, "21S01"); /* Insert column list mismatch */
1683 SQLS_ENTRY(109, "21S01");
1684 SQLS_ENTRY(110, "21S01");
1685 SQLS_ENTRY(1715, "21S02"); /* Ref column mismatch */
1686 SQLS_ENTRY(9502, "22001"); /* String data would be truncated */
1687 SQLS_ENTRY(220, "22003"); /* Arithmetic overflow */
1688 SQLS_ENTRY(168, "22003");
1689 SQLS_ENTRY(227, "22003");
1690 SQLS_ENTRY(232, "22003");
1691 SQLS_ENTRY(234, "22003");
1692 SQLS_ENTRY(236, "22003");
1693 SQLS_ENTRY(238, "22003");
1694 SQLS_ENTRY(244, "22003");
1695 SQLS_ENTRY(246, "22003");
1696 SQLS_ENTRY(247, "22003");
1697 SQLS_ENTRY(248, "22003");
1698 SQLS_ENTRY(519, "22003");
1699 SQLS_ENTRY(520, "22003");
1700 SQLS_ENTRY(521, "22003");
1701 SQLS_ENTRY(522, "22003");
1702 SQLS_ENTRY(523, "22003");
1703 SQLS_ENTRY(524, "22003");
1704 SQLS_ENTRY(3606, "22003");
1705 SQLS_ENTRY(206, "22005"); /* Error in assignment */
1706 SQLS_ENTRY(235, "22005");
1707 SQLS_ENTRY(249, "22005");
1708 SQLS_ENTRY(256, "22005");
1709 SQLS_ENTRY(305, "22005");
1710 SQLS_ENTRY(409, "22005");
1711 SQLS_ENTRY(518, "22005");
1712 SQLS_ENTRY(529, "22005");
1713 SQLS_ENTRY(535, "22008"); /* Datetime out of range */
1714 SQLS_ENTRY(542, "22008");
1715 SQLS_ENTRY(517, "22008");
1716 SQLS_ENTRY(3607, "22012"); /* Div by zero */
1717 SQLS_ENTRY(245, "22018"); /* Syntax error? */
1718 SQLS_ENTRY(544, "23000"); /* Constraint violation */
1719 SQLS_ENTRY(233, "23000");
1720 SQLS_ENTRY(273, "23000");
1721 SQLS_ENTRY(530, "23000");
1722 SQLS_ENTRY(2601,"23000");
1723 SQLS_ENTRY(2615,"23000");
1724 SQLS_ENTRY(2626,"23000");
1725 SQLS_ENTRY(3604,"23000");
1726 SQLS_ENTRY(3605,"23000");
1727 SQLS_ENTRY(545, "23000");
1728 SQLS_ENTRY(546, "23000");
1729 SQLS_ENTRY(547, "23000");
1730 SQLS_ENTRY(548, "23000");
1731 SQLS_ENTRY(549, "23000");
1732 SQLS_ENTRY(550, "23000");
1733 SQLS_ENTRY(1505, "23000");
1734 SQLS_ENTRY(1508, "23000");
1735 SQLS_ENTRY(565, "24000"); /* Invalid cursor state */
1736 SQLS_ENTRY(558, "24000");
1737 SQLS_ENTRY(559, "24000");
1738 SQLS_ENTRY(6235, "24000");
1739 SQLS_ENTRY(583, "24000");
1740 SQLS_ENTRY(6259, "24000");
1741 SQLS_ENTRY(6260, "24000");
1742 SQLS_ENTRY(562, "24000");
1743 SQLS_ENTRY(277, "25000"); /* Invalid transaction state */
1744 SQLS_ENTRY(611,"25000");
1745 SQLS_ENTRY(3906,"25000");
1746 SQLS_ENTRY(3908,"25000");
1747 SQLS_ENTRY(6401,"25000");
1748 SQLS_ENTRY(627, "25000");
1749 SQLS_ENTRY(628, "25000");
1750 SQLS_ENTRY(641, "25000");
1751 SQLS_ENTRY(642, "25000");
1752 SQLS_ENTRY(1276, "25000");
1753 SQLS_ENTRY(3902, "25000");
1754 SQLS_ENTRY(3903, "25000");
1755 SQLS_ENTRY(6104, "37000"); /* Syntax error or access violation */
1756 SQLS_ENTRY(102, "37000");
1757 SQLS_ENTRY(137, "37000");
1758 SQLS_ENTRY(7327, "37000");
1759 SQLS_ENTRY(201, "37000");
1760 SQLS_ENTRY(257, "37000");
1761 SQLS_ENTRY(2812, "37000");
1762 SQLS_ENTRY(2526, "37000");
1763 SQLS_ENTRY(11021, "37000");
1764 SQLS_ENTRY(229, "42000"); /* Syntax/Access violation */
1765 SQLS_ENTRY(230, "42000");
1766 SQLS_ENTRY(262, "42000");
1767 SQLS_ENTRY(4602, "42000");
1768 SQLS_ENTRY(4603, "42000");
1769 SQLS_ENTRY(4608, "42000");
1770 SQLS_ENTRY(10306, "42000");
1771 SQLS_ENTRY(10323, "42000");
1772 SQLS_ENTRY(10330, "42000");
1773 SQLS_ENTRY(10331, "42000");
1774 SQLS_ENTRY(10332, "42000");
1775 SQLS_ENTRY(11110, "42000");
1776 SQLS_ENTRY(11113, "42000");
1777 SQLS_ENTRY(11118, "42000");
1778 SQLS_ENTRY(11121, "42000");
1779 SQLS_ENTRY(17222, "42000");
1780 SQLS_ENTRY(17223, "42000");
1781 SQLS_ENTRY(18350, "42000");
1782 SQLS_ENTRY(18351, "42000");
1783 SQLS_ENTRY(113, "42000");
1784 SQLS_ENTRY(2714, "42S01"); /* Table or view already exists */
1785 SQLS_ENTRY(208, "42S02"); /* Table or view not found */
1786 SQLS_ENTRY(3701, "42S02");
1787 SQLS_ENTRY(1913, "42S11"); /* Index already exists */
1788 SQLS_ENTRY(307, "42S12"); /* Index not found */
1789 SQLS_ENTRY(7010, "42S12");
1790 SQLS_ENTRY(18091, "42S12");
1791 SQLS_ENTRY(1921, "42S21"); /* Column already exists */
1792 SQLS_ENTRY(1720, "42S22"); /* Column not found */
1793 SQLS_ENTRY(207, "42S22");
1794 SQLS_ENTRY(4934, "42S22");
1795 SQLS_ENTRY(18117, "42S22");
1796 }
1797 }
1798
1799 if (p != NULL && (q = strdup(p)) != NULL) {
1800 /* FIXME correct here ?? */
1801 /* Convert known ODBC 3.x states listed above to 2.x */
1802 if (memcmp(q, "42S", 3) == 0)
1803 memcpy(q, "S00", 3);
1804
1805 return q;
1806 }
1807 return NULL;
1808 }
1809
1810 BCPCOLDATA *
tds_alloc_bcp_column_data(unsigned int column_size)1811 tds_alloc_bcp_column_data(unsigned int column_size)
1812 {
1813 BCPCOLDATA *coldata;
1814
1815 TEST_MALLOC(coldata, BCPCOLDATA);
1816
1817 if (column_size > 4 * 1024)
1818 column_size = 4 * 1024;
1819 TEST_CALLOC(coldata->data, unsigned char, column_size);
1820
1821 return coldata;
1822 Cleanup:
1823 tds_free_bcp_column_data(coldata);
1824 return NULL;
1825 }
1826
1827 void
tds_free_bcp_column_data(BCPCOLDATA * coldata)1828 tds_free_bcp_column_data(BCPCOLDATA * coldata)
1829 {
1830 if (!coldata)
1831 return;
1832
1833 free(coldata->data);
1834 free(coldata);
1835 }
1836
1837 TDSBCPINFO *
tds_alloc_bcpinfo(void)1838 tds_alloc_bcpinfo(void)
1839 {
1840 TDSBCPINFO *bcpinfo;
1841
1842 TEST_MALLOC(bcpinfo, TDSBCPINFO);
1843
1844 tds_dstr_init(&bcpinfo->tablename);
1845
1846 return bcpinfo;
1847 Cleanup:
1848 return NULL;
1849 }
1850
1851 void
tds_deinit_bcpinfo(TDSBCPINFO * bcpinfo)1852 tds_deinit_bcpinfo(TDSBCPINFO *bcpinfo)
1853 {
1854 tds_dstr_free(&bcpinfo->tablename);
1855 TDS_ZERO_FREE(bcpinfo->insert_stmt);
1856 tds_free_results(bcpinfo->bindinfo);
1857 bcpinfo->bindinfo = NULL;
1858 }
1859
1860 void
tds_free_bcpinfo(TDSBCPINFO * bcpinfo)1861 tds_free_bcpinfo(TDSBCPINFO *bcpinfo)
1862 {
1863 if (bcpinfo) {
1864 tds_deinit_bcpinfo(bcpinfo);
1865 free(bcpinfo);
1866 }
1867 }
1868
1869 /**
1870 * Reallocate a pointer and update it if success
1871 * \param pp pointer to pointer to be reallocated
1872 * \param new_size new size to be allocated
1873 * \return new pointer allocated, NULL on failure
1874 */
1875 void *
tds_realloc(void ** pp,size_t new_size)1876 tds_realloc(void **pp, size_t new_size)
1877 {
1878 void *p;
1879
1880 /* some implementation of malloc/realloc does not like size==0 */
1881 if (!new_size)
1882 new_size = 1;
1883
1884 /* use malloc if not allocated before, some implementation require it */
1885 if (*pp)
1886 p = realloc(*pp, new_size);
1887 else
1888 p = malloc(new_size);
1889
1890 /* update pointer only on success */
1891 if (p)
1892 *pp = p;
1893
1894 return p;
1895 }
1896
1897 /** @} */
1898