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