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