Line data Source code
1 : /*
2 : * dynamic SQL support routines
3 : *
4 : * src/interfaces/ecpg/ecpglib/descriptor.c
5 : */
6 :
7 : #define POSTGRES_ECPG_INTERNAL
8 : #include "postgres_fe.h"
9 :
10 : #include "catalog/pg_type_d.h"
11 : #include "ecpg-pthread-win32.h"
12 : #include "ecpgerrno.h"
13 : #include "ecpglib.h"
14 : #include "ecpglib_extern.h"
15 : #include "ecpgtype.h"
16 : #include "sql3types.h"
17 : #include "sqlca.h"
18 : #include "sqlda.h"
19 :
20 : static void descriptor_free(struct descriptor *desc);
21 :
22 : /* We manage descriptors separately for each thread. */
23 : static pthread_key_t descriptor_key;
24 : static pthread_once_t descriptor_once = PTHREAD_ONCE_INIT;
25 :
26 : static void descriptor_deallocate_all(struct descriptor *list);
27 :
28 : static void
29 0 : descriptor_destructor(void *arg)
30 : {
31 0 : descriptor_deallocate_all(arg);
32 0 : }
33 :
34 : static void
35 20 : descriptor_key_init(void)
36 : {
37 20 : pthread_key_create(&descriptor_key, descriptor_destructor);
38 20 : }
39 :
40 : static struct descriptor *
41 3200308 : get_descriptors(void)
42 : {
43 3200308 : pthread_once(&descriptor_once, descriptor_key_init);
44 3200308 : return (struct descriptor *) pthread_getspecific(descriptor_key);
45 : }
46 :
47 : static void
48 3200058 : set_descriptors(struct descriptor *value)
49 : {
50 3200058 : pthread_setspecific(descriptor_key, value);
51 3200058 : }
52 :
53 : /* old internal convenience function that might go away later */
54 : static PGresult *
55 148 : ecpg_result_by_descriptor(int line, const char *name)
56 : {
57 148 : struct descriptor *desc = ecpg_find_desc(line, name);
58 :
59 148 : if (desc == NULL)
60 0 : return NULL;
61 148 : return desc->result;
62 : }
63 :
64 : static unsigned int
65 16 : ecpg_dynamic_type_DDT(Oid type)
66 : {
67 16 : switch (type)
68 : {
69 16 : case DATEOID:
70 16 : return SQL3_DDT_DATE;
71 0 : case TIMEOID:
72 0 : return SQL3_DDT_TIME;
73 0 : case TIMESTAMPOID:
74 0 : return SQL3_DDT_TIMESTAMP;
75 0 : case TIMESTAMPTZOID:
76 0 : return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE;
77 0 : case TIMETZOID:
78 0 : return SQL3_DDT_TIME_WITH_TIME_ZONE;
79 0 : default:
80 0 : return SQL3_DDT_ILLEGAL;
81 : }
82 : }
83 :
84 : bool
85 24 : ECPGget_desc_header(int lineno, const char *desc_name, int *count)
86 : {
87 : PGresult *ECPGresult;
88 24 : struct sqlca_t *sqlca = ECPGget_sqlca();
89 :
90 24 : if (sqlca == NULL)
91 : {
92 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
93 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
94 0 : return false;
95 : }
96 :
97 24 : ecpg_init_sqlca(sqlca);
98 24 : ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
99 24 : if (!ECPGresult)
100 0 : return false;
101 :
102 24 : *count = PQnfields(ECPGresult);
103 24 : sqlca->sqlerrd[2] = 1;
104 24 : ecpg_log("ECPGget_desc_header: found %d attributes\n", *count);
105 24 : return true;
106 : }
107 :
108 : static bool
109 206 : get_int_item(int lineno, void *var, enum ECPGttype vartype, int value)
110 : {
111 206 : switch (vartype)
112 : {
113 0 : case ECPGt_short:
114 0 : *(short *) var = (short) value;
115 0 : break;
116 206 : case ECPGt_int:
117 206 : *(int *) var = value;
118 206 : break;
119 0 : case ECPGt_long:
120 0 : *(long *) var = (long) value;
121 0 : break;
122 0 : case ECPGt_unsigned_short:
123 0 : *(unsigned short *) var = (unsigned short) value;
124 0 : break;
125 0 : case ECPGt_unsigned_int:
126 0 : *(unsigned int *) var = (unsigned int) value;
127 0 : break;
128 0 : case ECPGt_unsigned_long:
129 0 : *(unsigned long *) var = (unsigned long) value;
130 0 : break;
131 0 : case ECPGt_long_long:
132 0 : *(long long int *) var = (long long int) value;
133 0 : break;
134 0 : case ECPGt_unsigned_long_long:
135 0 : *(unsigned long long int *) var = (unsigned long long int) value;
136 0 : break;
137 0 : case ECPGt_float:
138 0 : *(float *) var = (float) value;
139 0 : break;
140 0 : case ECPGt_double:
141 0 : *(double *) var = (double) value;
142 0 : break;
143 0 : default:
144 0 : ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
145 0 : return false;
146 : }
147 :
148 206 : return true;
149 : }
150 :
151 : static bool
152 8 : set_int_item(int lineno, int *target, const void *var, enum ECPGttype vartype)
153 : {
154 8 : switch (vartype)
155 : {
156 0 : case ECPGt_short:
157 0 : *target = *(const short *) var;
158 0 : break;
159 8 : case ECPGt_int:
160 8 : *target = *(const int *) var;
161 8 : break;
162 0 : case ECPGt_long:
163 0 : *target = *(const long *) var;
164 0 : break;
165 0 : case ECPGt_unsigned_short:
166 0 : *target = *(const unsigned short *) var;
167 0 : break;
168 0 : case ECPGt_unsigned_int:
169 0 : *target = *(const unsigned int *) var;
170 0 : break;
171 0 : case ECPGt_unsigned_long:
172 0 : *target = *(const unsigned long *) var;
173 0 : break;
174 0 : case ECPGt_long_long:
175 0 : *target = *(const long long int *) var;
176 0 : break;
177 0 : case ECPGt_unsigned_long_long:
178 0 : *target = *(const unsigned long long int *) var;
179 0 : break;
180 0 : case ECPGt_float:
181 0 : *target = *(const float *) var;
182 0 : break;
183 0 : case ECPGt_double:
184 0 : *target = *(const double *) var;
185 0 : break;
186 0 : default:
187 0 : ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
188 0 : return false;
189 : }
190 :
191 8 : return true;
192 : }
193 :
194 : static bool
195 60 : get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int varcharsize)
196 : {
197 60 : switch (vartype)
198 : {
199 60 : case ECPGt_char:
200 : case ECPGt_unsigned_char:
201 : case ECPGt_string:
202 60 : strncpy(var, value, varcharsize);
203 60 : break;
204 0 : case ECPGt_varchar:
205 : {
206 0 : struct ECPGgeneric_varchar *variable =
207 : (struct ECPGgeneric_varchar *) var;
208 :
209 0 : if (varcharsize == 0)
210 0 : memcpy(variable->arr, value, strlen(value));
211 : else
212 0 : strncpy(variable->arr, value, varcharsize);
213 :
214 0 : variable->len = strlen(value);
215 0 : if (varcharsize > 0 && variable->len > varcharsize)
216 0 : variable->len = varcharsize;
217 : }
218 0 : break;
219 0 : default:
220 0 : ecpg_raise(lineno, ECPG_VAR_NOT_CHAR, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
221 0 : return false;
222 : }
223 :
224 60 : return true;
225 : }
226 :
227 : #define RETURN_IF_NO_DATA if (ntuples < 1) \
228 : { \
229 : va_end(args); \
230 : ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL); \
231 : return false; \
232 : }
233 :
234 : bool
235 124 : ECPGget_desc(int lineno, const char *desc_name, int index, ...)
236 : {
237 : va_list args;
238 : PGresult *ECPGresult;
239 : enum ECPGdtype type;
240 : int ntuples,
241 : act_tuple;
242 : struct variable data_var;
243 124 : struct sqlca_t *sqlca = ECPGget_sqlca();
244 124 : bool alloc_failed = (sqlca == NULL);
245 :
246 124 : if (alloc_failed)
247 : {
248 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
249 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
250 0 : return false;
251 : }
252 :
253 124 : va_start(args, index);
254 124 : ecpg_init_sqlca(sqlca);
255 124 : ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
256 124 : if (!ECPGresult)
257 : {
258 0 : va_end(args);
259 0 : return false;
260 : }
261 :
262 124 : ntuples = PQntuples(ECPGresult);
263 :
264 124 : if (index < 1 || index > PQnfields(ECPGresult))
265 : {
266 0 : ecpg_raise(lineno, ECPG_INVALID_DESCRIPTOR_INDEX, ECPG_SQLSTATE_INVALID_DESCRIPTOR_INDEX, NULL);
267 0 : va_end(args);
268 0 : return false;
269 : }
270 :
271 124 : ecpg_log("ECPGget_desc: reading items for tuple %d\n", index);
272 124 : --index;
273 :
274 124 : type = va_arg(args, enum ECPGdtype);
275 :
276 124 : memset(&data_var, 0, sizeof data_var);
277 124 : data_var.type = ECPGt_EORT;
278 124 : data_var.ind_type = ECPGt_NO_INDICATOR;
279 :
280 472 : while (type != ECPGd_EODT)
281 : {
282 : char type_str[20];
283 : long varcharsize;
284 : long offset;
285 : long arrsize;
286 : enum ECPGttype vartype;
287 : void *var;
288 :
289 348 : vartype = va_arg(args, enum ECPGttype);
290 348 : var = va_arg(args, void *);
291 348 : varcharsize = va_arg(args, long);
292 348 : arrsize = va_arg(args, long);
293 348 : offset = va_arg(args, long);
294 :
295 348 : switch (type)
296 : {
297 52 : case (ECPGd_indicator):
298 52 : RETURN_IF_NO_DATA;
299 52 : data_var.ind_type = vartype;
300 52 : data_var.ind_pointer = var;
301 52 : data_var.ind_varcharsize = varcharsize;
302 52 : data_var.ind_arrsize = arrsize;
303 52 : data_var.ind_offset = offset;
304 52 : if (data_var.ind_arrsize == 0 || data_var.ind_varcharsize == 0)
305 20 : data_var.ind_value = *((void **) (data_var.ind_pointer));
306 : else
307 32 : data_var.ind_value = data_var.ind_pointer;
308 52 : break;
309 :
310 58 : case ECPGd_data:
311 58 : RETURN_IF_NO_DATA;
312 58 : data_var.type = vartype;
313 58 : data_var.pointer = var;
314 58 : data_var.varcharsize = varcharsize;
315 58 : data_var.arrsize = arrsize;
316 58 : data_var.offset = offset;
317 58 : if (data_var.arrsize == 0 || data_var.varcharsize == 0)
318 20 : data_var.value = *((void **) (data_var.pointer));
319 : else
320 38 : data_var.value = data_var.pointer;
321 58 : break;
322 :
323 60 : case ECPGd_name:
324 60 : if (!get_char_item(lineno, var, vartype, PQfname(ECPGresult, index), varcharsize))
325 : {
326 0 : va_end(args);
327 0 : return false;
328 : }
329 :
330 60 : ecpg_log("ECPGget_desc: NAME = %s\n", PQfname(ECPGresult, index));
331 60 : break;
332 :
333 0 : case ECPGd_nullable:
334 0 : if (!get_int_item(lineno, var, vartype, 1))
335 : {
336 0 : va_end(args);
337 0 : return false;
338 : }
339 :
340 0 : break;
341 :
342 0 : case ECPGd_key_member:
343 0 : if (!get_int_item(lineno, var, vartype, 0))
344 : {
345 0 : va_end(args);
346 0 : return false;
347 : }
348 :
349 0 : break;
350 :
351 28 : case ECPGd_scale:
352 28 : if (!get_int_item(lineno, var, vartype, (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff))
353 : {
354 0 : va_end(args);
355 0 : return false;
356 : }
357 :
358 28 : ecpg_log("ECPGget_desc: SCALE = %d\n", (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff);
359 28 : break;
360 :
361 28 : case ECPGd_precision:
362 28 : if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) >> 16))
363 : {
364 0 : va_end(args);
365 0 : return false;
366 : }
367 :
368 28 : ecpg_log("ECPGget_desc: PRECISION = %d\n", PQfmod(ECPGresult, index) >> 16);
369 28 : break;
370 :
371 28 : case ECPGd_octet:
372 28 : if (!get_int_item(lineno, var, vartype, PQfsize(ECPGresult, index)))
373 : {
374 0 : va_end(args);
375 0 : return false;
376 : }
377 :
378 28 : ecpg_log("ECPGget_desc: OCTET_LENGTH = %d\n", PQfsize(ECPGresult, index));
379 28 : break;
380 :
381 30 : case ECPGd_length:
382 30 : if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) - VARHDRSZ))
383 : {
384 0 : va_end(args);
385 0 : return false;
386 : }
387 :
388 30 : ecpg_log("ECPGget_desc: LENGTH = %d\n", PQfmod(ECPGresult, index) - VARHDRSZ);
389 30 : break;
390 :
391 28 : case ECPGd_type:
392 28 : if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type(PQftype(ECPGresult, index))))
393 : {
394 0 : va_end(args);
395 0 : return false;
396 : }
397 :
398 28 : ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type(PQftype(ECPGresult, index)));
399 28 : break;
400 :
401 8 : case ECPGd_di_code:
402 8 : if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type_DDT(PQftype(ECPGresult, index))))
403 : {
404 0 : va_end(args);
405 0 : return false;
406 : }
407 :
408 8 : ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type_DDT(PQftype(ECPGresult, index)));
409 8 : break;
410 :
411 0 : case ECPGd_cardinality:
412 0 : if (!get_int_item(lineno, var, vartype, PQntuples(ECPGresult)))
413 : {
414 0 : va_end(args);
415 0 : return false;
416 : }
417 :
418 0 : ecpg_log("ECPGget_desc: CARDINALITY = %d\n", PQntuples(ECPGresult));
419 0 : break;
420 :
421 28 : case ECPGd_ret_length:
422 : case ECPGd_ret_octet:
423 :
424 28 : RETURN_IF_NO_DATA;
425 :
426 : /*
427 : * this is like ECPGstore_result
428 : */
429 28 : if (arrsize > 0 && ntuples > arrsize)
430 : {
431 0 : ecpg_log("ECPGget_desc on line %d: incorrect number of matches; %d don't fit into array of %ld\n",
432 : lineno, ntuples, arrsize);
433 0 : ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
434 0 : va_end(args);
435 0 : return false;
436 : }
437 : /* allocate storage if needed */
438 28 : if (arrsize == 0 && *(void **) var == NULL)
439 : {
440 0 : void *mem = ecpg_auto_alloc(offset * ntuples, lineno);
441 :
442 0 : if (!mem)
443 : {
444 0 : va_end(args);
445 0 : return false;
446 : }
447 0 : *(void **) var = mem;
448 0 : var = mem;
449 : }
450 :
451 56 : for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
452 : {
453 28 : if (!get_int_item(lineno, var, vartype, PQgetlength(ECPGresult, act_tuple, index)))
454 : {
455 0 : va_end(args);
456 0 : return false;
457 : }
458 28 : var = (char *) var + offset;
459 28 : ecpg_log("ECPGget_desc: RETURNED[%d] = %d\n", act_tuple, PQgetlength(ECPGresult, act_tuple, index));
460 : }
461 28 : break;
462 :
463 0 : default:
464 0 : snprintf(type_str, sizeof(type_str), "%d", type);
465 0 : ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
466 0 : va_end(args);
467 0 : return false;
468 : }
469 :
470 348 : type = va_arg(args, enum ECPGdtype);
471 : }
472 :
473 124 : if (data_var.type != ECPGt_EORT)
474 : {
475 : struct statement stmt;
476 :
477 58 : memset(&stmt, 0, sizeof stmt);
478 58 : stmt.lineno = lineno;
479 :
480 : /* desperate try to guess something sensible */
481 58 : stmt.connection = ecpg_get_connection(NULL);
482 58 : if (stmt.connection == NULL)
483 : {
484 2 : ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
485 2 : ecpg_gettext("NULL"));
486 2 : va_end(args);
487 2 : return false;
488 : }
489 :
490 : /* Make sure we do NOT honor the locale for numeric input */
491 : /* since the database gives the standard decimal point */
492 : /* (see comments in execute.c) */
493 : #ifdef HAVE_USELOCALE
494 :
495 : /*
496 : * To get here, the above PQnfields() test must have found nonzero
497 : * fields. One needs a connection to create such a descriptor. (EXEC
498 : * SQL SET DESCRIPTOR can populate the descriptor's "items", but it
499 : * can't change the descriptor's PQnfields().) Any successful
500 : * connection initializes ecpg_clocale.
501 : */
502 : Assert(ecpg_clocale);
503 56 : stmt.oldlocale = uselocale(ecpg_clocale);
504 : #else
505 : #ifdef WIN32
506 : stmt.oldthreadlocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
507 : #endif
508 : stmt.oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL),
509 : lineno, &alloc_failed);
510 : if (alloc_failed)
511 : {
512 : va_end(args);
513 : return false;
514 : }
515 :
516 : setlocale(LC_NUMERIC, "C");
517 : #endif
518 :
519 56 : ecpg_store_result(ECPGresult, index, &stmt, &data_var);
520 :
521 : #ifdef HAVE_USELOCALE
522 56 : if (stmt.oldlocale != (locale_t) 0)
523 56 : uselocale(stmt.oldlocale);
524 : #else
525 : if (stmt.oldlocale)
526 : {
527 : setlocale(LC_NUMERIC, stmt.oldlocale);
528 : ecpg_free(stmt.oldlocale);
529 : }
530 : #ifdef WIN32
531 : if (stmt.oldthreadlocale != -1)
532 : _configthreadlocale(stmt.oldthreadlocale);
533 : #endif
534 : #endif
535 : }
536 66 : else if (data_var.ind_type != ECPGt_NO_INDICATOR && data_var.ind_pointer != NULL)
537 :
538 : /*
539 : * ind_type != NO_INDICATOR should always have ind_pointer != NULL but
540 : * since this might be changed manually in the .c file let's play it
541 : * safe
542 : */
543 : {
544 : /*
545 : * this is like ECPGstore_result but since we don't have a data
546 : * variable at hand, we can't call it
547 : */
548 28 : if (data_var.ind_arrsize > 0 && ntuples > data_var.ind_arrsize)
549 : {
550 0 : ecpg_log("ECPGget_desc on line %d: incorrect number of matches (indicator); %d don't fit into array of %ld\n",
551 : lineno, ntuples, data_var.ind_arrsize);
552 0 : ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
553 0 : va_end(args);
554 0 : return false;
555 : }
556 :
557 : /* allocate storage if needed */
558 28 : if (data_var.ind_arrsize == 0 && data_var.ind_value == NULL)
559 : {
560 0 : void *mem = ecpg_auto_alloc(data_var.ind_offset * ntuples, lineno);
561 :
562 0 : if (!mem)
563 : {
564 0 : va_end(args);
565 0 : return false;
566 : }
567 0 : *(void **) data_var.ind_pointer = mem;
568 0 : data_var.ind_value = mem;
569 : }
570 :
571 56 : for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
572 : {
573 28 : if (!get_int_item(lineno, data_var.ind_value, data_var.ind_type, -PQgetisnull(ECPGresult, act_tuple, index)))
574 : {
575 0 : va_end(args);
576 0 : return false;
577 : }
578 28 : data_var.ind_value = (char *) data_var.ind_value + data_var.ind_offset;
579 28 : ecpg_log("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index));
580 : }
581 : }
582 122 : sqlca->sqlerrd[2] = ntuples;
583 122 : va_end(args);
584 122 : return true;
585 : }
586 :
587 : #undef RETURN_IF_NO_DATA
588 :
589 : bool
590 2 : ECPGset_desc_header(int lineno, const char *desc_name, int count)
591 : {
592 2 : struct descriptor *desc = ecpg_find_desc(lineno, desc_name);
593 :
594 2 : if (desc == NULL)
595 0 : return false;
596 2 : desc->count = count;
597 2 : return true;
598 : }
599 :
600 : static void
601 26 : set_desc_attr(struct descriptor_item *desc_item, struct variable *var,
602 : char *tobeinserted)
603 : {
604 26 : if (var->type != ECPGt_bytea)
605 22 : desc_item->is_binary = false;
606 :
607 : else
608 : {
609 4 : struct ECPGgeneric_bytea *variable =
610 : (struct ECPGgeneric_bytea *) (var->value);
611 :
612 4 : desc_item->is_binary = true;
613 4 : desc_item->data_len = variable->len;
614 : }
615 :
616 26 : ecpg_free(desc_item->data); /* free() takes care of a potential NULL value */
617 26 : desc_item->data = tobeinserted;
618 26 : }
619 :
620 :
621 : bool
622 26 : ECPGset_desc(int lineno, const char *desc_name, int index, ...)
623 : {
624 : va_list args;
625 : struct descriptor *desc;
626 : struct descriptor_item *desc_item;
627 : struct variable *var;
628 :
629 26 : desc = ecpg_find_desc(lineno, desc_name);
630 26 : if (desc == NULL)
631 0 : return false;
632 :
633 40 : for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
634 : {
635 28 : if (desc_item->num == index)
636 14 : break;
637 : }
638 :
639 26 : if (desc_item == NULL)
640 : {
641 12 : desc_item = (struct descriptor_item *) ecpg_alloc(sizeof(*desc_item), lineno);
642 12 : if (!desc_item)
643 0 : return false;
644 12 : desc_item->num = index;
645 12 : if (desc->count < index)
646 12 : desc->count = index;
647 12 : desc_item->next = desc->items;
648 12 : desc->items = desc_item;
649 : }
650 :
651 26 : if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
652 0 : return false;
653 :
654 26 : va_start(args, index);
655 :
656 : for (;;)
657 34 : {
658 : enum ECPGdtype itemtype;
659 60 : char *tobeinserted = NULL;
660 :
661 60 : itemtype = va_arg(args, enum ECPGdtype);
662 :
663 60 : if (itemtype == ECPGd_EODT)
664 26 : break;
665 :
666 34 : var->type = va_arg(args, enum ECPGttype);
667 34 : var->pointer = va_arg(args, char *);
668 :
669 34 : var->varcharsize = va_arg(args, long);
670 34 : var->arrsize = va_arg(args, long);
671 34 : var->offset = va_arg(args, long);
672 :
673 34 : if (var->arrsize == 0 || var->varcharsize == 0)
674 0 : var->value = *((char **) (var->pointer));
675 : else
676 34 : var->value = var->pointer;
677 :
678 : /*
679 : * negative values are used to indicate an array without given bounds
680 : */
681 : /* reset to zero for us */
682 34 : if (var->arrsize < 0)
683 0 : var->arrsize = 0;
684 34 : if (var->varcharsize < 0)
685 0 : var->varcharsize = 0;
686 :
687 34 : var->next = NULL;
688 :
689 34 : switch (itemtype)
690 : {
691 26 : case ECPGd_data:
692 : {
693 26 : if (!ecpg_store_input(lineno, true, var, &tobeinserted, false))
694 : {
695 0 : ecpg_free(var);
696 0 : va_end(args);
697 0 : return false;
698 : }
699 :
700 26 : set_desc_attr(desc_item, var, tobeinserted);
701 26 : tobeinserted = NULL;
702 26 : break;
703 : }
704 :
705 8 : case ECPGd_indicator:
706 8 : set_int_item(lineno, &desc_item->indicator, var->pointer, var->type);
707 8 : break;
708 :
709 0 : case ECPGd_length:
710 0 : set_int_item(lineno, &desc_item->length, var->pointer, var->type);
711 0 : break;
712 :
713 0 : case ECPGd_precision:
714 0 : set_int_item(lineno, &desc_item->precision, var->pointer, var->type);
715 0 : break;
716 :
717 0 : case ECPGd_scale:
718 0 : set_int_item(lineno, &desc_item->scale, var->pointer, var->type);
719 0 : break;
720 :
721 0 : case ECPGd_type:
722 0 : set_int_item(lineno, &desc_item->type, var->pointer, var->type);
723 0 : break;
724 :
725 0 : default:
726 : {
727 : char type_str[20];
728 :
729 0 : snprintf(type_str, sizeof(type_str), "%d", itemtype);
730 0 : ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
731 0 : ecpg_free(var);
732 0 : va_end(args);
733 0 : return false;
734 : }
735 : }
736 : }
737 26 : ecpg_free(var);
738 26 : va_end(args);
739 :
740 26 : return true;
741 : }
742 :
743 : /* Free the descriptor and items in it. */
744 : static void
745 1600030 : descriptor_free(struct descriptor *desc)
746 : {
747 : struct descriptor_item *desc_item;
748 :
749 1600034 : for (desc_item = desc->items; desc_item;)
750 : {
751 : struct descriptor_item *di;
752 :
753 4 : ecpg_free(desc_item->data);
754 4 : di = desc_item;
755 4 : desc_item = desc_item->next;
756 4 : ecpg_free(di);
757 : }
758 :
759 1600030 : ecpg_free(desc->name);
760 1600030 : PQclear(desc->result);
761 1600030 : ecpg_free(desc);
762 1600030 : }
763 :
764 : bool
765 1600030 : ECPGdeallocate_desc(int line, const char *name)
766 : {
767 : struct descriptor *desc;
768 : struct descriptor *prev;
769 1600030 : struct sqlca_t *sqlca = ECPGget_sqlca();
770 :
771 1600030 : if (sqlca == NULL)
772 : {
773 0 : ecpg_raise(line, ECPG_OUT_OF_MEMORY,
774 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
775 0 : return false;
776 : }
777 :
778 1600030 : ecpg_init_sqlca(sqlca);
779 1600040 : for (desc = get_descriptors(), prev = NULL; desc; prev = desc, desc = desc->next)
780 : {
781 1600040 : if (strcmp(name, desc->name) == 0)
782 : {
783 1600030 : if (prev)
784 10 : prev->next = desc->next;
785 : else
786 1600020 : set_descriptors(desc->next);
787 1600030 : descriptor_free(desc);
788 1600030 : return true;
789 : }
790 : }
791 0 : ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
792 0 : return false;
793 : }
794 :
795 : /* Deallocate all descriptors in the list */
796 : static void
797 0 : descriptor_deallocate_all(struct descriptor *list)
798 : {
799 0 : while (list)
800 : {
801 0 : struct descriptor *next = list->next;
802 :
803 0 : descriptor_free(list);
804 0 : list = next;
805 : }
806 0 : }
807 :
808 : bool
809 1600038 : ECPGallocate_desc(int line, const char *name)
810 : {
811 : struct descriptor *new;
812 1600038 : struct sqlca_t *sqlca = ECPGget_sqlca();
813 :
814 1600038 : if (sqlca == NULL)
815 : {
816 0 : ecpg_raise(line, ECPG_OUT_OF_MEMORY,
817 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
818 0 : return false;
819 : }
820 :
821 1600038 : ecpg_init_sqlca(sqlca);
822 1600038 : new = (struct descriptor *) ecpg_alloc(sizeof(struct descriptor), line);
823 1600038 : if (!new)
824 0 : return false;
825 1600038 : new->next = get_descriptors();
826 1600038 : new->name = ecpg_alloc(strlen(name) + 1, line);
827 1600038 : if (!new->name)
828 : {
829 0 : ecpg_free(new);
830 0 : return false;
831 : }
832 1600038 : new->count = -1;
833 1600038 : new->items = NULL;
834 1600038 : new->result = PQmakeEmptyPGresult(NULL, 0);
835 1600038 : if (!new->result)
836 : {
837 0 : ecpg_free(new->name);
838 0 : ecpg_free(new);
839 0 : ecpg_raise(line, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
840 0 : return false;
841 : }
842 1600038 : strcpy(new->name, name);
843 1600038 : set_descriptors(new);
844 1600038 : return true;
845 : }
846 :
847 : /* Find descriptor with name in the connection. */
848 : struct descriptor *
849 240 : ecpg_find_desc(int line, const char *name)
850 : {
851 : struct descriptor *desc;
852 :
853 338 : for (desc = get_descriptors(); desc; desc = desc->next)
854 : {
855 338 : if (strcmp(name, desc->name) == 0)
856 240 : return desc;
857 : }
858 :
859 0 : ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
860 0 : return NULL; /* not found */
861 : }
862 :
863 : bool
864 42 : ECPGdescribe(int line, int compat, bool input, const char *connection_name, const char *stmt_name, ...)
865 : {
866 42 : bool ret = false;
867 : struct connection *con;
868 : struct prepared_statement *prep;
869 : PGresult *res;
870 : va_list args;
871 :
872 : /* DESCRIBE INPUT is not yet supported */
873 42 : if (input)
874 : {
875 0 : ecpg_raise(line, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, "DESCRIBE INPUT");
876 0 : return ret;
877 : }
878 :
879 42 : con = ecpg_get_connection(connection_name);
880 42 : if (!con)
881 : {
882 0 : ecpg_raise(line, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
883 0 : connection_name ? connection_name : ecpg_gettext("NULL"));
884 0 : return ret;
885 : }
886 42 : prep = ecpg_find_prepared_statement(stmt_name, con, NULL);
887 42 : if (!prep)
888 : {
889 0 : ecpg_raise(line, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt_name);
890 0 : return ret;
891 : }
892 :
893 42 : va_start(args, stmt_name);
894 :
895 : for (;;)
896 42 : {
897 : enum ECPGttype type;
898 : void *ptr;
899 :
900 : /* variable type */
901 84 : type = va_arg(args, enum ECPGttype);
902 :
903 84 : if (type == ECPGt_EORT)
904 42 : break;
905 :
906 : /* rest of variable parameters */
907 42 : ptr = va_arg(args, void *);
908 42 : (void) va_arg(args, long); /* skip args */
909 42 : (void) va_arg(args, long);
910 42 : (void) va_arg(args, long);
911 :
912 : /* variable indicator */
913 42 : (void) va_arg(args, enum ECPGttype);
914 42 : (void) va_arg(args, void *); /* skip args */
915 42 : (void) va_arg(args, long);
916 42 : (void) va_arg(args, long);
917 42 : (void) va_arg(args, long);
918 :
919 42 : switch (type)
920 : {
921 18 : case ECPGt_descriptor:
922 : {
923 18 : char *name = ptr;
924 18 : struct descriptor *desc = ecpg_find_desc(line, name);
925 :
926 18 : if (desc == NULL)
927 0 : break;
928 :
929 18 : res = PQdescribePrepared(con->connection, stmt_name);
930 18 : if (!ecpg_check_PQresult(res, line, con->connection, compat))
931 0 : break;
932 :
933 18 : PQclear(desc->result);
934 :
935 18 : desc->result = res;
936 18 : ret = true;
937 18 : break;
938 : }
939 24 : case ECPGt_sqlda:
940 : {
941 24 : if (INFORMIX_MODE(compat))
942 12 : {
943 12 : struct sqlda_compat **_sqlda = ptr;
944 : struct sqlda_compat *sqlda;
945 :
946 12 : res = PQdescribePrepared(con->connection, stmt_name);
947 12 : if (!ecpg_check_PQresult(res, line, con->connection, compat))
948 0 : break;
949 :
950 12 : sqlda = ecpg_build_compat_sqlda(line, res, -1, compat);
951 12 : if (sqlda)
952 : {
953 12 : struct sqlda_compat *sqlda_old = *_sqlda;
954 : struct sqlda_compat *sqlda_old1;
955 :
956 12 : while (sqlda_old)
957 : {
958 0 : sqlda_old1 = sqlda_old->desc_next;
959 0 : free(sqlda_old);
960 0 : sqlda_old = sqlda_old1;
961 : }
962 :
963 12 : *_sqlda = sqlda;
964 12 : ret = true;
965 : }
966 :
967 12 : PQclear(res);
968 : }
969 : else
970 : {
971 12 : struct sqlda_struct **_sqlda = ptr;
972 : struct sqlda_struct *sqlda;
973 :
974 12 : res = PQdescribePrepared(con->connection, stmt_name);
975 12 : if (!ecpg_check_PQresult(res, line, con->connection, compat))
976 0 : break;
977 :
978 12 : sqlda = ecpg_build_native_sqlda(line, res, -1, compat);
979 12 : if (sqlda)
980 : {
981 12 : struct sqlda_struct *sqlda_old = *_sqlda;
982 : struct sqlda_struct *sqlda_old1;
983 :
984 12 : while (sqlda_old)
985 : {
986 0 : sqlda_old1 = sqlda_old->desc_next;
987 0 : free(sqlda_old);
988 0 : sqlda_old = sqlda_old1;
989 : }
990 :
991 12 : *_sqlda = sqlda;
992 12 : ret = true;
993 : }
994 :
995 12 : PQclear(res);
996 : }
997 24 : break;
998 : }
999 42 : default:
1000 : /* nothing else may come */
1001 : ;
1002 : }
1003 : }
1004 :
1005 42 : va_end(args);
1006 :
1007 42 : return ret;
1008 : }
|