OSDN Git Service

c5ae1dadf32096afdfa45df6a58347b16be0dc34
[pg-rex/syncrep.git] / src / interfaces / ecpg / ecpglib / execute.c
1 /* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.70 2007/09/26 10:57:00 meskes Exp $ */
2
3 /*
4  * The aim is to get a simpler inteface to the database routines.
5  * All the tidieous messing around with tuples is supposed to be hidden
6  * by this function.
7  */
8 /* Author: Linus Tolke
9    (actually most if the code is "borrowed" from the distribution and just
10    slightly modified)
11  */
12
13 /* Taken over as part of PostgreSQL by Michael Meskes <meskes@postgresql.org>
14    on Feb. 5th, 1998 */
15
16 #define POSTGRES_ECPG_INTERNAL
17 #include "postgres_fe.h"
18
19 #include <locale.h>
20
21 #include "pg_type.h"
22
23 #include "ecpgtype.h"
24 #include "ecpglib.h"
25 #include "ecpgerrno.h"
26 #include "extern.h"
27 #include "sqlca.h"
28 #include "sql3types.h"
29 #include "pgtypes_numeric.h"
30 #include "pgtypes_date.h"
31 #include "pgtypes_timestamp.h"
32 #include "pgtypes_interval.h"
33
34 /*
35  *      This function returns a newly malloced string that has ' and \
36  *      escaped.
37  */
38 static char *
39 quote_postgres(char *arg, bool quote, int lineno)
40 {
41         char    *res;
42         size_t  length;
43         size_t  escaped_len;
44         size_t  buffer_len;
45
46         /*
47          * if quote is false we just need to store things in a descriptor they
48          * will be quoted once they are inserted in a statement
49          */
50         if (!quote)
51                 return arg;
52         else
53         {
54                 length = strlen(arg);
55                 buffer_len = 2 * length + 1;
56                 res = (char *) ECPGalloc(buffer_len + 3, lineno);
57                 if (!res)
58                         return (res);
59                 escaped_len = PQescapeString(res+1, arg, buffer_len);
60                 if (length == escaped_len)
61                 {
62                         res[0] = res[escaped_len+1] = '\'';
63                         res[escaped_len+2] = '\0';
64                 }
65                 else
66                 {
67                         /* 
68                          * We don't know if the target database is using
69                          * standard_conforming_strings, so we always use E'' strings.
70                          */
71                         memmove(res+2, res+1, escaped_len);
72                         res[0] = ESCAPE_STRING_SYNTAX;
73                         res[1] = res[escaped_len+2] = '\'';
74                         res[escaped_len+3] = '\0';
75                 }
76                 ECPGfree(arg);
77                 return res;
78         }
79 }
80
81 static void
82 free_variable(struct variable * var)
83 {
84         struct variable *var_next;
85
86         if (var == NULL)
87                 return;
88         var_next = var->next;
89         ECPGfree(var);
90
91         while (var_next)
92         {
93                 var = var_next;
94                 var_next = var->next;
95                 ECPGfree(var);
96         }
97 }
98
99 static void
100 free_statement(struct statement * stmt)
101 {
102         if (stmt == NULL)
103                 return;
104         free_variable(stmt->inlist);
105         free_variable(stmt->outlist);
106         ECPGfree(stmt->command);
107         ECPGfree(stmt->name);
108         ECPGfree(stmt);
109 }
110
111 static int 
112 next_insert(char *text, int pos, bool questionmarks)
113 {
114         bool            string = false;
115         int             p = pos;
116
117         for (; text[p] != '\0'; p++)
118         {
119                 if (text[p] == '\\')            /* escape character */
120                         p++;
121                 else if (text[p] == '\'')
122                         string = string ? false : true;
123                 else if (!string)
124                 {
125                         if (text[p] == '$' && isdigit(text[p+1]))
126                         {
127                                 /* this can be either a dollar quote or a variable */
128                                 int i;
129
130                                 for (i = p + 1; isdigit(text[i]); i++);
131                                 if (!isalpha(text[i]) && isascii(text[i]) && text[i] != '_')
132                                         /* not dollar delimeted quote */
133                                         return p;
134                         }
135                         else if (questionmarks && text[p] == '?') 
136                         {
137                                 /* also allow old style placeholders */
138                                 return p;
139                         }
140                 }
141         }
142
143         return -1;
144 }
145
146 static bool
147 ECPGtypeinfocache_push(struct ECPGtype_information_cache ** cache, int oid, bool isarray, int lineno)
148 {
149         struct ECPGtype_information_cache *new_entry
150         = (struct ECPGtype_information_cache *) ECPGalloc(sizeof(struct ECPGtype_information_cache), lineno);
151
152         if (new_entry == NULL)
153                 return (false);
154
155         new_entry->oid = oid;
156         new_entry->isarray = isarray;
157         new_entry->next = *cache;
158         *cache = new_entry;
159         return (true);
160 }
161
162 static enum ARRAY_TYPE
163 ECPGis_type_an_array(int type, const struct statement * stmt, const struct variable * var)
164 {
165         char       *array_query;
166         enum ARRAY_TYPE isarray = ECPG_ARRAY_NOT_SET;
167         PGresult   *query;
168         struct ECPGtype_information_cache *cache_entry;
169
170         if ((stmt->connection->cache_head) == NULL)
171         {
172                 /*
173                  * Text like types are not an array for ecpg, but postgres counts them
174                  * as an array. This define reminds you to not 'correct' these values.
175                  */
176 #define not_an_array_in_ecpg ECPG_ARRAY_NONE
177
178                 /* populate cache with well known types to speed things up */
179                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), BOOLOID, ECPG_ARRAY_NONE, stmt->lineno))
180                         return (ECPG_ARRAY_ERROR);
181                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), BYTEAOID, ECPG_ARRAY_NONE, stmt->lineno))
182                         return (ECPG_ARRAY_ERROR);
183                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), CHAROID, ECPG_ARRAY_NONE, stmt->lineno))
184                         return (ECPG_ARRAY_ERROR);
185                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), NAMEOID, not_an_array_in_ecpg, stmt->lineno))
186                         return (ECPG_ARRAY_ERROR);
187                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), INT8OID, ECPG_ARRAY_NONE, stmt->lineno))
188                         return (ECPG_ARRAY_ERROR);
189                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), INT2OID, ECPG_ARRAY_NONE, stmt->lineno))
190                         return (ECPG_ARRAY_ERROR);
191                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), INT2VECTOROID, ECPG_ARRAY_VECTOR, stmt->lineno))
192                         return (ECPG_ARRAY_ERROR);
193                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), INT4OID, ECPG_ARRAY_NONE, stmt->lineno))
194                         return (ECPG_ARRAY_ERROR);
195                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), REGPROCOID, ECPG_ARRAY_NONE, stmt->lineno))
196                         return (ECPG_ARRAY_ERROR);
197                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), TEXTOID, ECPG_ARRAY_NONE, stmt->lineno))
198                         return (ECPG_ARRAY_ERROR);
199                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), OIDOID, ECPG_ARRAY_NONE, stmt->lineno))
200                         return (ECPG_ARRAY_ERROR);
201                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), TIDOID, ECPG_ARRAY_NONE, stmt->lineno))
202                         return (ECPG_ARRAY_ERROR);
203                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), XIDOID, ECPG_ARRAY_NONE, stmt->lineno))
204                         return (ECPG_ARRAY_ERROR);
205                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), CIDOID, ECPG_ARRAY_NONE, stmt->lineno))
206                         return (ECPG_ARRAY_ERROR);
207                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), OIDVECTOROID, ECPG_ARRAY_VECTOR, stmt->lineno))
208                         return (ECPG_ARRAY_ERROR);
209                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), POINTOID, ECPG_ARRAY_VECTOR, stmt->lineno))
210                         return (ECPG_ARRAY_ERROR);
211                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), LSEGOID, ECPG_ARRAY_VECTOR, stmt->lineno))
212                         return (ECPG_ARRAY_ERROR);
213                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), PATHOID, ECPG_ARRAY_NONE, stmt->lineno))
214                         return (ECPG_ARRAY_ERROR);
215                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), BOXOID, ECPG_ARRAY_VECTOR, stmt->lineno))
216                         return (ECPG_ARRAY_ERROR);
217                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), POLYGONOID, ECPG_ARRAY_NONE, stmt->lineno))
218                         return (ECPG_ARRAY_ERROR);
219                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), LINEOID, ECPG_ARRAY_VECTOR, stmt->lineno))
220                         return (ECPG_ARRAY_ERROR);
221                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), FLOAT4OID, ECPG_ARRAY_NONE, stmt->lineno))
222                         return (ECPG_ARRAY_ERROR);
223                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), FLOAT8OID, ECPG_ARRAY_NONE, stmt->lineno))
224                         return (ECPG_ARRAY_ERROR);
225                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), ABSTIMEOID, ECPG_ARRAY_NONE, stmt->lineno))
226                         return (ECPG_ARRAY_ERROR);
227                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), RELTIMEOID, ECPG_ARRAY_NONE, stmt->lineno))
228                         return (ECPG_ARRAY_ERROR);
229                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), TINTERVALOID, ECPG_ARRAY_NONE, stmt->lineno))
230                         return (ECPG_ARRAY_ERROR);
231                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), UNKNOWNOID, ECPG_ARRAY_NONE, stmt->lineno))
232                         return (ECPG_ARRAY_ERROR);
233                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), CIRCLEOID, ECPG_ARRAY_NONE, stmt->lineno))
234                         return (ECPG_ARRAY_ERROR);
235                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), CASHOID, ECPG_ARRAY_NONE, stmt->lineno))
236                         return (ECPG_ARRAY_ERROR);
237                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), INETOID, ECPG_ARRAY_NONE, stmt->lineno))
238                         return (ECPG_ARRAY_ERROR);
239                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), CIDROID, ECPG_ARRAY_NONE, stmt->lineno))
240                         return (ECPG_ARRAY_ERROR);
241                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), BPCHAROID, ECPG_ARRAY_NONE, stmt->lineno))
242                         return (ECPG_ARRAY_ERROR);
243                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), VARCHAROID, ECPG_ARRAY_NONE, stmt->lineno))
244                         return (ECPG_ARRAY_ERROR);
245                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), DATEOID, ECPG_ARRAY_NONE, stmt->lineno))
246                         return (ECPG_ARRAY_ERROR);
247                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), TIMEOID, ECPG_ARRAY_NONE, stmt->lineno))
248                         return (ECPG_ARRAY_ERROR);
249                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), TIMESTAMPOID, ECPG_ARRAY_NONE, stmt->lineno))
250                         return (ECPG_ARRAY_ERROR);
251                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), TIMESTAMPTZOID, ECPG_ARRAY_NONE, stmt->lineno))
252                         return (ECPG_ARRAY_ERROR);
253                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), INTERVALOID, ECPG_ARRAY_NONE, stmt->lineno))
254                         return (ECPG_ARRAY_ERROR);
255                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), TIMETZOID, ECPG_ARRAY_NONE, stmt->lineno))
256                         return (ECPG_ARRAY_ERROR);
257                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), ZPBITOID, ECPG_ARRAY_NONE, stmt->lineno))
258                         return (ECPG_ARRAY_ERROR);
259                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), VARBITOID, ECPG_ARRAY_NONE, stmt->lineno))
260                         return (ECPG_ARRAY_ERROR);
261                 if (!ECPGtypeinfocache_push(&(stmt->connection->cache_head), NUMERICOID, ECPG_ARRAY_NONE, stmt->lineno))
262                         return (ECPG_ARRAY_ERROR);
263         }
264
265         for (cache_entry = (stmt->connection->cache_head); cache_entry != NULL; cache_entry = cache_entry->next)
266         {
267                 if (cache_entry->oid == type)
268                         return cache_entry->isarray;
269         }
270
271         array_query = (char *) ECPGalloc(strlen("select typlen from pg_type where oid= and typelem<>0") + 11, stmt->lineno);
272         if (array_query == NULL)
273                 return (ECPG_ARRAY_ERROR);
274
275         sprintf(array_query, "select typlen from pg_type where oid=%d and typelem<>0", type);
276         query = PQexec(stmt->connection->connection, array_query);
277         ECPGfree(array_query);
278         if (!ECPGcheck_PQresult(query, stmt->lineno, stmt->connection->connection, stmt->compat))
279                 return (ECPG_ARRAY_ERROR);
280         else if (PQresultStatus(query) == PGRES_TUPLES_OK)
281         {
282                 if (PQntuples(query) == 0)
283                         isarray = ECPG_ARRAY_NONE;
284                 else
285                 {
286                         isarray = (atol((char *) PQgetvalue(query, 0, 0)) == -1) ? ECPG_ARRAY_ARRAY : ECPG_ARRAY_VECTOR;
287                         if (ECPGDynamicType(type) == SQL3_CHARACTER ||
288                                 ECPGDynamicType(type) == SQL3_CHARACTER_VARYING)
289                         {
290                                 /*
291                                  * arrays of character strings are not yet implemented
292                                  */
293                                 isarray = ECPG_ARRAY_NONE;
294                         }
295                 }
296                 PQclear(query);
297         }
298         else
299                 return (ECPG_ARRAY_ERROR);
300
301         ECPGtypeinfocache_push(&(stmt->connection->cache_head), type, isarray, stmt->lineno);
302         ECPGlog("ECPGis_type_an_array line %d: TYPE database: %d C: %d array: %s\n", stmt->lineno, type, var->type, isarray ? "Yes" : "No");
303         return isarray;
304 }
305
306
307 bool
308 ECPGstore_result(const PGresult *results, int act_field,
309                                  const struct statement * stmt, struct variable * var)
310 {
311         enum ARRAY_TYPE isarray;
312         int                     act_tuple,
313                                 ntuples = PQntuples(results);
314         bool            status = true;
315
316         if ((isarray = ECPGis_type_an_array(PQftype(results, act_field), stmt, var)) == ECPG_ARRAY_ERROR)
317         {
318                 ECPGraise(stmt->lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
319                 return false;
320         }
321
322         if (isarray == ECPG_ARRAY_NONE)
323         {
324                 /*
325                  * if we don't have enough space, we cannot read all tuples
326                  */
327                 if ((var->arrsize > 0 && ntuples > var->arrsize) || (var->ind_arrsize > 0 && ntuples > var->ind_arrsize))
328                 {
329                         ECPGlog("ECPGstore_result line %d: Incorrect number of matches: %d don't fit into array of %d\n",
330                                         stmt->lineno, ntuples, var->arrsize);
331                         ECPGraise(stmt->lineno, INFORMIX_MODE(stmt->compat) ? ECPG_INFORMIX_SUBSELECT_NOT_ONE : ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
332                         return false;
333                 }
334         }
335         else
336         {
337                 /*
338                  * since we read an array, the variable has to be an array too
339                  */
340                 if (var->arrsize == 0)
341                 {
342                         ECPGraise(stmt->lineno, ECPG_NO_ARRAY, ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL);
343                         return false;
344                 }
345         }
346
347         /*
348          * allocate memory for NULL pointers
349          */
350         if ((var->arrsize == 0 || var->varcharsize == 0) && var->value == NULL)
351         {
352                 int                     len = 0;
353
354                 switch (var->type)
355                 {
356                         case ECPGt_char:
357                         case ECPGt_unsigned_char:
358                                 if (!var->varcharsize && !var->arrsize)
359                                 {
360                                         /* special mode for handling char**foo=0 */
361                                         for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
362                                                 len += strlen(PQgetvalue(results, act_tuple, act_field)) + 1;
363                                         len *= var->offset; /* should be 1, but YMNK */
364                                         len += (ntuples + 1) * sizeof(char *);
365                                 }
366                                 else
367                                 {
368                                         var->varcharsize = 0;
369                                         /* check strlen for each tuple */
370                                         for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
371                                         {
372                                                 int                     len = strlen(PQgetvalue(results, act_tuple, act_field)) + 1;
373
374                                                 if (len > var->varcharsize)
375                                                         var->varcharsize = len;
376                                         }
377                                         var->offset *= var->varcharsize;
378                                         len = var->offset * ntuples;
379                                 }
380                                 break;
381                         case ECPGt_varchar:
382                                 len = ntuples * (var->varcharsize + sizeof(int));
383                                 break;
384                         default:
385                                 len = var->offset * ntuples;
386                                 break;
387                 }
388                 ECPGlog("ECPGstore_result: line %d: allocating memory for %d tuples\n", stmt->lineno, ntuples);
389                 var->value = (char *) ECPGalloc(len, stmt->lineno);
390                 if (!var->value)
391                         return false;
392                 *((char **) var->pointer) = var->value;
393                 ECPGadd_mem(var->value, stmt->lineno);
394         }
395
396         /* allocate indicator variable if needed */
397         if ((var->ind_arrsize == 0 || var->ind_varcharsize == 0) && var->ind_value == NULL && var->ind_pointer != NULL)
398         {
399                 int                     len = var->ind_offset * ntuples;
400
401                 var->ind_value = (char *) ECPGalloc(len, stmt->lineno);
402                 if (!var->ind_value)
403                         return false;
404                 *((char **) var->ind_pointer) = var->ind_value;
405                 ECPGadd_mem(var->ind_value, stmt->lineno);
406         }
407
408         /* fill the variable with the tuple(s) */
409         if (!var->varcharsize && !var->arrsize &&
410                 (var->type == ECPGt_char || var->type == ECPGt_unsigned_char))
411         {
412                 /* special mode for handling char**foo=0 */
413
414                 /* filling the array of (char*)s */
415                 char      **current_string = (char **) var->value;
416
417                 /* storing the data (after the last array element) */
418                 char       *current_data_location = (char *) &current_string[ntuples + 1];
419
420                 for (act_tuple = 0; act_tuple < ntuples && status; act_tuple++)
421                 {
422                         int                     len = strlen(PQgetvalue(results, act_tuple, act_field)) + 1;
423
424                         if (!ECPGget_data(results, act_tuple, act_field, stmt->lineno,
425                                                           var->type, var->ind_type, current_data_location,
426                                                           var->ind_value, len, 0, var->ind_offset, isarray, stmt->compat, stmt->force_indicator))
427                                 status = false;
428                         else
429                         {
430                                 *current_string = current_data_location;
431                                 current_data_location += len;
432                                 current_string++;
433                         }
434                 }
435
436                 /* terminate the list */
437                 *current_string = NULL;
438         }
439         else
440         {
441                 for (act_tuple = 0; act_tuple < ntuples && status; act_tuple++)
442                 {
443                         if (!ECPGget_data(results, act_tuple, act_field, stmt->lineno,
444                                                           var->type, var->ind_type, var->value,
445                                                           var->ind_value, var->varcharsize, var->offset, var->ind_offset, isarray, stmt->compat, stmt->force_indicator))
446                                 status = false;
447                 }
448         }
449         return status;
450 }
451
452 bool
453 ECPGstore_input(const int lineno, const bool force_indicator, const struct variable * var,
454                                 const char **tobeinserted_p, bool quote)
455 {
456         char       *mallocedval = NULL;
457         char       *newcopy = NULL;
458
459         /*
460          * arrays are not possible unless the attribute is an array too FIXME: we
461          * do not know if the attribute is an array here
462          */
463 #if 0
464         if (var->arrsize > 1 &&...)
465         {
466                 ECPGraise(lineno, ECPG_ARRAY_INSERT, ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL);
467                 return false;
468         }
469 #endif
470
471         /*
472          * Some special treatment is needed for records since we want their
473          * contents to arrive in a comma-separated list on insert (I think).
474          */
475
476         *tobeinserted_p = "";
477
478         /* check for null value and set input buffer accordingly */
479         switch (var->ind_type)
480         {
481                 case ECPGt_short:
482                 case ECPGt_unsigned_short:
483                         if (*(short *) var->ind_value < 0)
484                                 *tobeinserted_p = NULL;
485                         break;
486                 case ECPGt_int:
487                 case ECPGt_unsigned_int:
488                         if (*(int *) var->ind_value < 0)
489                                 *tobeinserted_p = NULL;
490                         break;
491                 case ECPGt_long:
492                 case ECPGt_unsigned_long:
493                         if (*(long *) var->ind_value < 0L)
494                                 *tobeinserted_p = NULL;
495                         break;
496 #ifdef HAVE_LONG_LONG_INT_64
497                 case ECPGt_long_long:
498                 case ECPGt_unsigned_long_long:
499                         if (*(long long int *) var->ind_value < (long long) 0)
500                                 *tobeinserted_p = NULL;
501                         break;
502 #endif   /* HAVE_LONG_LONG_INT_64 */
503                 case ECPGt_NO_INDICATOR:
504                         if (force_indicator == false)
505                         {
506                                 if (ECPGis_noind_null(var->type, var->value))
507                                         *tobeinserted_p = NULL;
508                         }
509                         break;
510                 default:
511                         break;
512         }
513         if (*tobeinserted_p != NULL)
514         {
515                 int                     asize = var->arrsize ? var->arrsize : 1;
516
517                 switch (var->type)
518                 {
519                                 int                     element;
520
521                         case ECPGt_short:
522                                 if (!(mallocedval = ECPGalloc(asize * 20, lineno)))
523                                         return false;
524
525                                 if (asize > 1)
526                                 {
527                                         strcpy(mallocedval, "array [");
528
529                                         for (element = 0; element < asize; element++)
530                                                 sprintf(mallocedval + strlen(mallocedval), "%hd,", ((short *) var->value)[element]);
531
532                                         strcpy(mallocedval + strlen(mallocedval) - 1, "]");
533                                 }
534                                 else
535                                         sprintf(mallocedval, "%hd", *((short *) var->value));
536
537                                 *tobeinserted_p = mallocedval;
538                                 break;
539
540                         case ECPGt_int:
541                                 if (!(mallocedval = ECPGalloc(asize * 20, lineno)))
542                                         return false;
543
544                                 if (asize > 1)
545                                 {
546                                         strcpy(mallocedval, "{");
547
548                                         for (element = 0; element < asize; element++)
549                                                 sprintf(mallocedval + strlen(mallocedval), "%d,", ((int *) var->value)[element]);
550
551                                         strcpy(mallocedval + strlen(mallocedval) - 1, "}");
552                                 }
553                                 else
554                                         sprintf(mallocedval, "%d", *((int *) var->value));
555
556                                 *tobeinserted_p = mallocedval;
557                                 break;
558
559                         case ECPGt_unsigned_short:
560                                 if (!(mallocedval = ECPGalloc(asize * 20, lineno)))
561                                         return false;
562
563                                 if (asize > 1)
564                                 {
565                                         strcpy(mallocedval, "array [");
566
567                                         for (element = 0; element < asize; element++)
568                                                 sprintf(mallocedval + strlen(mallocedval), "%hu,", ((unsigned short *) var->value)[element]);
569
570                                         strcpy(mallocedval + strlen(mallocedval) - 1, "]");
571                                 }
572                                 else
573                                         sprintf(mallocedval, "%hu", *((unsigned short *) var->value));
574
575                                 *tobeinserted_p = mallocedval;
576                                 break;
577
578                         case ECPGt_unsigned_int:
579                                 if (!(mallocedval = ECPGalloc(asize * 20, lineno)))
580                                         return false;
581
582                                 if (asize > 1)
583                                 {
584                                         strcpy(mallocedval, "array [");
585
586                                         for (element = 0; element < asize; element++)
587                                                 sprintf(mallocedval + strlen(mallocedval), "%u,", ((unsigned int *) var->value)[element]);
588
589                                         strcpy(mallocedval + strlen(mallocedval) - 1, "]");
590                                 }
591                                 else
592                                         sprintf(mallocedval, "%u", *((unsigned int *) var->value));
593
594                                 *tobeinserted_p = mallocedval;
595                                 break;
596
597                         case ECPGt_long:
598                                 if (!(mallocedval = ECPGalloc(asize * 20, lineno)))
599                                         return false;
600
601                                 if (asize > 1)
602                                 {
603                                         strcpy(mallocedval, "array [");
604
605                                         for (element = 0; element < asize; element++)
606                                                 sprintf(mallocedval + strlen(mallocedval), "%ld,", ((long *) var->value)[element]);
607
608                                         strcpy(mallocedval + strlen(mallocedval) - 1, "]");
609                                 }
610                                 else
611                                         sprintf(mallocedval, "%ld", *((long *) var->value));
612
613                                 *tobeinserted_p = mallocedval;
614                                 break;
615
616                         case ECPGt_unsigned_long:
617                                 if (!(mallocedval = ECPGalloc(asize * 20, lineno)))
618                                         return false;
619
620                                 if (asize > 1)
621                                 {
622                                         strcpy(mallocedval, "array [");
623
624                                         for (element = 0; element < asize; element++)
625                                                 sprintf(mallocedval + strlen(mallocedval), "%lu,", ((unsigned long *) var->value)[element]);
626
627                                         strcpy(mallocedval + strlen(mallocedval) - 1, "]");
628                                 }
629                                 else
630                                         sprintf(mallocedval, "%lu", *((unsigned long *) var->value));
631
632                                 *tobeinserted_p = mallocedval;
633                                 break;
634 #ifdef HAVE_LONG_LONG_INT_64
635                         case ECPGt_long_long:
636                                 if (!(mallocedval = ECPGalloc(asize * 30, lineno)))
637                                         return false;
638
639                                 if (asize > 1)
640                                 {
641                                         strcpy(mallocedval, "array [");
642
643                                         for (element = 0; element < asize; element++)
644                                                 sprintf(mallocedval + strlen(mallocedval), "%lld,", ((long long *) var->value)[element]);
645
646                                         strcpy(mallocedval + strlen(mallocedval) - 1, "]");
647                                 }
648                                 else
649                                         sprintf(mallocedval, "%lld", *((long long *) var->value));
650
651                                 *tobeinserted_p = mallocedval;
652                                 break;
653
654                         case ECPGt_unsigned_long_long:
655                                 if (!(mallocedval = ECPGalloc(asize * 30, lineno)))
656                                         return false;
657
658                                 if (asize > 1)
659                                 {
660                                         strcpy(mallocedval, "array [");
661
662                                         for (element = 0; element < asize; element++)
663                                                 sprintf(mallocedval + strlen(mallocedval), "%llu,", ((unsigned long long *) var->value)[element]);
664
665                                         strcpy(mallocedval + strlen(mallocedval) - 1, "]");
666                                 }
667                                 else
668                                         sprintf(mallocedval, "%llu", *((unsigned long long *) var->value));
669
670                                 *tobeinserted_p = mallocedval;
671                                 break;
672 #endif   /* HAVE_LONG_LONG_INT_64 */
673                         case ECPGt_float:
674                                 if (!(mallocedval = ECPGalloc(asize * 25, lineno)))
675                                         return false;
676
677                                 if (asize > 1)
678                                 {
679                                         strcpy(mallocedval, "array [");
680
681                                         for (element = 0; element < asize; element++)
682                                                 sprintf(mallocedval + strlen(mallocedval), "%.14g,", ((float *) var->value)[element]);
683
684                                         strcpy(mallocedval + strlen(mallocedval) - 1, "]");
685                                 }
686                                 else
687                                         sprintf(mallocedval, "%.14g", *((float *) var->value));
688
689                                 *tobeinserted_p = mallocedval;
690                                 break;
691
692                         case ECPGt_double:
693                                 if (!(mallocedval = ECPGalloc(asize * 25, lineno)))
694                                         return false;
695
696                                 if (asize > 1)
697                                 {
698                                         strcpy(mallocedval, "array [");
699
700                                         for (element = 0; element < asize; element++)
701                                                 sprintf(mallocedval + strlen(mallocedval), "%.14g,", ((double *) var->value)[element]);
702
703                                         strcpy(mallocedval + strlen(mallocedval) - 1, "]");
704                                 }
705                                 else
706                                         sprintf(mallocedval, "%.14g", *((double *) var->value));
707
708                                 *tobeinserted_p = mallocedval;
709                                 break;
710
711                         case ECPGt_bool:
712                                 if (!(mallocedval = ECPGalloc(var->arrsize + sizeof("array []"), lineno)))
713                                         return false;
714
715                                 if (var->arrsize > 1)
716                                 {
717                                         strcpy(mallocedval, "array [");
718
719                                         if (var->offset == sizeof(char))
720                                                 for (element = 0; element < var->arrsize; element++)
721                                                         sprintf(mallocedval + strlen(mallocedval), "%c,", (((char *) var->value)[element]) ? 't' : 'f');
722
723                                         /*
724                                          * this is necessary since sizeof(C++'s bool)==sizeof(int)
725                                          */
726                                         else if (var->offset == sizeof(int))
727                                                 for (element = 0; element < var->arrsize; element++)
728                                                         sprintf(mallocedval + strlen(mallocedval), "%c,", (((int *) var->value)[element]) ? 't' : 'f');
729                                         else
730                                                 ECPGraise(lineno, ECPG_CONVERT_BOOL, ECPG_SQLSTATE_DATATYPE_MISMATCH, "different size");
731
732                                         strcpy(mallocedval + strlen(mallocedval) - 1, "]");
733                                 }
734                                 else
735                                 {
736                                         if (var->offset == sizeof(char))
737                                                 sprintf(mallocedval, "%c", (*((char *) var->value)) ? 't' : 'f');
738                                         else if (var->offset == sizeof(int))
739                                                 sprintf(mallocedval, "%c", (*((int *) var->value)) ? 't' : 'f');
740                                         else
741                                                 ECPGraise(lineno, ECPG_CONVERT_BOOL, ECPG_SQLSTATE_DATATYPE_MISMATCH, "different size");
742                                 }
743
744                                 *tobeinserted_p = mallocedval;
745                                 break;
746
747                         case ECPGt_char:
748                         case ECPGt_unsigned_char:
749                                 {
750                                         /* set slen to string length if type is char * */
751                                         int                     slen = (var->varcharsize == 0) ? strlen((char *) var->value) : var->varcharsize;
752
753                                         if (!(newcopy = ECPGalloc(slen + 1, lineno)))
754                                                 return false;
755
756                                         strncpy(newcopy, (char *) var->value, slen);
757                                         newcopy[slen] = '\0';
758
759                                         mallocedval = quote_postgres(newcopy, quote, lineno);
760                                         if (!mallocedval)
761                                                 return false;
762
763                                         *tobeinserted_p = mallocedval;
764                                 }
765                                 break;
766                         case ECPGt_const:
767                         case ECPGt_char_variable:
768                                 {
769                                         int                     slen = strlen((char *) var->value);
770
771                                         if (!(mallocedval = ECPGalloc(slen + 1, lineno)))
772                                                 return false;
773
774                                         strncpy(mallocedval, (char *) var->value, slen);
775                                         mallocedval[slen] = '\0';
776
777                                         *tobeinserted_p = mallocedval;
778                                 }
779                                 break;
780                         case ECPGt_varchar:
781                                 {
782                                         struct ECPGgeneric_varchar *variable =
783                                         (struct ECPGgeneric_varchar *) (var->value);
784
785                                         if (!(newcopy = (char *) ECPGalloc(variable->len + 1, lineno)))
786                                                 return false;
787
788                                         strncpy(newcopy, variable->arr, variable->len);
789                                         newcopy[variable->len] = '\0';
790
791                                         mallocedval = quote_postgres(newcopy, quote, lineno);
792                                         if (!mallocedval)
793                                                 return false;
794
795                                         *tobeinserted_p = mallocedval;
796                                 }
797                                 break;
798
799                         case ECPGt_decimal:
800                         case ECPGt_numeric:
801                                 {
802                                         char       *str = NULL;
803                                         int                     slen;
804                                         numeric    *nval;
805
806                                         if (var->arrsize > 1)
807                                         {
808                                                 for (element = 0; element < var->arrsize; element++)
809                                                 {
810                                                         nval = PGTYPESnumeric_new();
811                                                         if (!nval)
812                                                                 return false;
813
814                                                         if (var->type == ECPGt_numeric)
815                                                                 PGTYPESnumeric_copy((numeric *) ((var + var->offset * element)->value), nval);
816                                                         else
817                                                                 PGTYPESnumeric_from_decimal((decimal *) ((var + var->offset * element)->value), nval);
818
819                                                         str = PGTYPESnumeric_to_asc(nval, nval->dscale);
820                                                         slen = strlen(str);
821                                                         PGTYPESnumeric_free(nval);
822
823                                                         if (!(mallocedval = ECPGrealloc(mallocedval, strlen(mallocedval) + slen + sizeof("array [] "), lineno)))
824                                                         {
825                                                                 ECPGfree(str);
826                                                                 return false;
827                                                         }
828
829                                                         if (!element)
830                                                                 strcpy(mallocedval, "array [");
831
832                                                         strncpy(mallocedval + strlen(mallocedval), str, slen + 1);
833                                                         strcpy(mallocedval + strlen(mallocedval), ",");
834                                                         ECPGfree(str);
835                                                 }
836                                                 strcpy(mallocedval + strlen(mallocedval) - 1, "]");
837                                         }
838                                         else
839                                         {
840                                                 nval = PGTYPESnumeric_new();
841                                                 if (!nval)
842                                                         return false;
843
844                                                 if (var->type == ECPGt_numeric)
845                                                         PGTYPESnumeric_copy((numeric *) (var->value), nval);
846                                                 else
847                                                         PGTYPESnumeric_from_decimal((decimal *) (var->value), nval);
848
849                                                 str = PGTYPESnumeric_to_asc(nval, nval->dscale);
850                                                 slen = strlen(str);
851                                                 PGTYPESnumeric_free(nval);
852
853                                                 if (!(mallocedval = ECPGalloc(slen + 1, lineno)))
854                                                 {
855                                                         free(str);
856                                                         return false;
857                                                 }
858
859                                                 strncpy(mallocedval, str, slen);
860                                                 mallocedval[slen] = '\0';
861                                                 ECPGfree(str);
862                                         }
863
864                                         *tobeinserted_p = mallocedval;
865                                 }
866                                 break;
867
868                         case ECPGt_interval:
869                                 {
870                                         char       *str = NULL;
871                                         int                     slen;
872
873                                         if (var->arrsize > 1)
874                                         {
875                                                 for (element = 0; element < var->arrsize; element++)
876                                                 {
877                                                         str = quote_postgres(PGTYPESinterval_to_asc((interval *) ((var + var->offset * element)->value)), quote, lineno);
878                                                         if (!str)
879                                                                 return false;
880                                                         slen = strlen(str);
881
882                                                         if (!(mallocedval = ECPGrealloc(mallocedval, strlen(mallocedval) + slen + sizeof("array [],interval "), lineno)))
883                                                         {
884                                                                 ECPGfree(str);
885                                                                 return false;
886                                                         }
887
888                                                         if (!element)
889                                                                 strcpy(mallocedval, "array [");
890
891                                                         strncpy(mallocedval + strlen(mallocedval), str, slen + 1);
892                                                         strcpy(mallocedval + strlen(mallocedval), ",");
893                                                         ECPGfree(str);
894                                                 }
895                                                 strcpy(mallocedval + strlen(mallocedval) - 1, "]");
896                                         }
897                                         else
898                                         {
899                                                 str = quote_postgres(PGTYPESinterval_to_asc((interval *) (var->value)), quote, lineno);
900                                                 if (!str)
901                                                         return false;
902                                                 slen = strlen(str);
903
904                                                 if (!(mallocedval = ECPGalloc(slen + sizeof("interval ") + 1, lineno)))
905                                                 {
906                                                         ECPGfree(str);
907                                                         return false;
908                                                 }
909
910                                                 /* also copy trailing '\0' */
911                                                 strncpy(mallocedval + strlen(mallocedval), str, slen + 1);
912                                                 ECPGfree(str);
913                                         }
914
915                                         *tobeinserted_p = mallocedval;
916                                 }
917                                 break;
918
919                         case ECPGt_date:
920                                 {
921                                         char       *str = NULL;
922                                         int                     slen;
923
924                                         if (var->arrsize > 1)
925                                         {
926                                                 for (element = 0; element < var->arrsize; element++)
927                                                 {
928                                                         str = quote_postgres(PGTYPESdate_to_asc(*(date *) ((var + var->offset * element)->value)), quote, lineno);
929                                                         if (!str)
930                                                                 return false;
931                                                         slen = strlen(str);
932
933                                                         if (!(mallocedval = ECPGrealloc(mallocedval, strlen(mallocedval) + slen + sizeof("array [],date "), lineno)))
934                                                         {
935                                                                 ECPGfree(str);
936                                                                 return false;
937                                                         }
938
939                                                         if (!element)
940                                                                 strcpy(mallocedval, "array [");
941
942                                                         strncpy(mallocedval + strlen(mallocedval), str, slen + 1);
943                                                         strcpy(mallocedval + strlen(mallocedval), ",");
944                                                         ECPGfree(str);
945                                                 }
946                                                 strcpy(mallocedval + strlen(mallocedval) - 1, "]");
947                                         }
948                                         else
949                                         {
950                                                 str = quote_postgres(PGTYPESdate_to_asc(*(date *) (var->value)), quote, lineno);
951                                                 if (!str)
952                                                         return false;
953                                                 slen = strlen(str);
954
955                                                 if (!(mallocedval = ECPGalloc(slen + sizeof("date ") + 1, lineno)))
956                                                 {
957                                                         ECPGfree(str);
958                                                         return false;
959                                                 }
960
961                                                 /* also copy trailing '\0' */
962                                                 strncpy(mallocedval + strlen(mallocedval), str, slen + 1);
963                                                 ECPGfree(str);
964                                         }
965
966                                         *tobeinserted_p = mallocedval;
967                                 }
968                                 break;
969
970                         case ECPGt_timestamp:
971                                 {
972                                         char       *str = NULL;
973                                         int                     slen;
974
975                                         if (var->arrsize > 1)
976                                         {
977                                                 for (element = 0; element < var->arrsize; element++)
978                                                 {
979                                                         str = quote_postgres(PGTYPEStimestamp_to_asc(*(timestamp *) ((var + var->offset * element)->value)), quote, lineno);
980                                                         if (!str)
981                                                                 return false;
982
983                                                         slen = strlen(str);
984
985                                                         if (!(mallocedval = ECPGrealloc(mallocedval, strlen(mallocedval) + slen + sizeof("array [], timestamp "), lineno)))
986                                                         {
987                                                                 ECPGfree(str);
988                                                                 return false;
989                                                         }
990
991                                                         if (!element)
992                                                                 strcpy(mallocedval, "array [");
993
994                                                         strncpy(mallocedval + strlen(mallocedval), str, slen + 1);
995                                                         strcpy(mallocedval + strlen(mallocedval), ",");
996                                                         ECPGfree(str);
997                                                 }
998                                                 strcpy(mallocedval + strlen(mallocedval) - 1, "]");
999                                         }
1000                                         else
1001                                         {
1002                                                 str = quote_postgres(PGTYPEStimestamp_to_asc(*(timestamp *) (var->value)), quote, lineno);
1003                                                 if (!str)
1004                                                         return false;
1005                                                 slen = strlen(str);
1006
1007                                                 if (!(mallocedval = ECPGalloc(slen + sizeof("timestamp") + 1, lineno)))
1008                                                 {
1009                                                         ECPGfree(str);
1010                                                         return false;
1011                                                 }
1012
1013                                                 /* also copy trailing '\0' */
1014                                                 strncpy(mallocedval + strlen(mallocedval), str, slen + 1);
1015                                                 ECPGfree(str);
1016                                         }
1017
1018                                         *tobeinserted_p = mallocedval;
1019                                 }
1020                                 break;
1021
1022                         case ECPGt_descriptor:
1023                                 break;
1024
1025                         default:
1026                                 /* Not implemented yet */
1027                                 ECPGraise(lineno, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, (char *) ECPGtype_name(var->type));
1028                                 return false;
1029                                 break;
1030                 }
1031         }
1032         return true;
1033 }
1034
1035 static void
1036 free_params(const char **paramValues, int nParams, bool print, int lineno)
1037 {
1038         int n;
1039
1040         for (n = 0; n < nParams; n++)
1041         {
1042                 if (print)
1043                         ECPGlog("ECPGexecute line %d: parameter %d = %s\n", lineno, n + 1, paramValues[n] ? paramValues[n] : "null");
1044                 ECPGfree((void *)(paramValues[n]));
1045         }
1046         ECPGfree(paramValues);
1047 }
1048
1049 static bool
1050 ECPGexecute(struct statement * stmt)
1051 {
1052         bool            status = false;
1053         char       *cmdstat;
1054         PGresult   *results;
1055         PGnotify   *notify;
1056         struct variable *var;
1057         int                     desc_counter = 0;
1058         const char * *paramValues = NULL;
1059         int nParams = 0;
1060         int position = 0;
1061         struct sqlca_t *sqlca = ECPGget_sqlca();
1062         bool                    clear_result = true;
1063
1064         /*
1065          * If the type is one of the fill in types then we take the argument
1066          * and enter it to our parameter array at the first position. Then if there
1067          * are any more fill in types we add more parameters.
1068          */
1069         var = stmt->inlist;
1070         while (var)
1071         {
1072                 const char *tobeinserted;
1073                 int counter = 1;
1074
1075                 tobeinserted = NULL;
1076
1077                 /*
1078                  * A descriptor is a special case since it contains many variables but
1079                  * is listed only once.
1080                  */
1081                 if (var->type == ECPGt_descriptor)
1082                 {
1083                         /*
1084                          * We create an additional variable list here, so the same logic
1085                          * applies.
1086                          */
1087                         struct variable desc_inlist;
1088                         struct descriptor *desc;
1089                         struct descriptor_item *desc_item;
1090
1091                         for (desc = all_descriptors; desc; desc = desc->next)
1092                         {
1093                                 if (strcmp(var->pointer, desc->name) == 0)
1094                                         break;
1095                         }
1096
1097                         if (desc == NULL)
1098                         {
1099                                 ECPGraise(stmt->lineno, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, var->pointer);
1100                                 return false;
1101                         }
1102
1103                         desc_counter++;
1104                         for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
1105                         {
1106                                 if (desc_item->num == desc_counter)
1107                                 {
1108                                         desc_inlist.type = ECPGt_char;
1109                                         desc_inlist.value = desc_item->data;
1110                                         desc_inlist.pointer = &(desc_item->data);
1111                                         desc_inlist.varcharsize = strlen(desc_item->data);
1112                                         desc_inlist.arrsize = 1;
1113                                         desc_inlist.offset = 0;
1114                                         if (!desc_item->indicator)
1115                                         {
1116                                                 desc_inlist.ind_type = ECPGt_NO_INDICATOR;
1117                                                 desc_inlist.ind_value = desc_inlist.ind_pointer = NULL;
1118                                                 desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = desc_inlist.ind_offset = 0;
1119                                         }
1120                                         else
1121                                         {
1122                                                 desc_inlist.ind_type = ECPGt_int;
1123                                                 desc_inlist.ind_value = &(desc_item->indicator);
1124                                                 desc_inlist.ind_pointer = &(desc_inlist.ind_value);
1125                                                 desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = 1;
1126                                                 desc_inlist.ind_offset = 0;
1127                                         }
1128                                         if (!ECPGstore_input(stmt->lineno, stmt->force_indicator, &desc_inlist, &tobeinserted, false))
1129                                                 return false;
1130
1131                                         break;
1132                                 }
1133                         }
1134                         if (desc->count == desc_counter)
1135                                 desc_counter = 0;
1136                 }
1137                 else
1138                 {
1139                         if (!ECPGstore_input(stmt->lineno, stmt->force_indicator, var, &tobeinserted, false))
1140                                 return false;
1141                 }
1142
1143                 /*
1144                  * now tobeinserted points to an area that contains the next parameter
1145                  * if var->type=ECPGt_char_variable we have a dynamic cursor 
1146                  * we have to simulate a dynamic cursor because there is no backend functionality for it
1147                  */
1148                 if (var->type != ECPGt_char_variable)
1149                 {
1150                         nParams++;
1151                         if (!(paramValues = (const char **) ECPGrealloc(paramValues, sizeof(const char *) * nParams, stmt->lineno)))
1152                         {
1153                                 ECPGfree(paramValues);
1154                                 return false;
1155                         }
1156
1157                         paramValues[nParams - 1] = tobeinserted;
1158
1159                         if ((position = next_insert(stmt->command, position, stmt->questionmarks) + 1) == 0)
1160                         {
1161                                 /*
1162                                  * We have an argument but we dont have the matched up
1163                                  * placeholder in the string
1164                                  */
1165                                 ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS,
1166                                                 ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS,
1167                                                   NULL);
1168                                 free_params(paramValues, nParams, false, stmt->lineno);
1169                                 return false;
1170                         }
1171                         
1172                         /* let's see if this was an old style placeholder */
1173                         if (stmt->command[position-1] == '?')
1174                         {
1175                                 /* yes, replace with new style */
1176                                 int buffersize = sizeof(int) * CHAR_BIT * 10 / 3; /* a rough guess of the size we need */
1177                                 char *buffer, *newcopy;
1178
1179                                 if (!(buffer = (char *) ECPGalloc(buffersize, stmt->lineno)))
1180                                 {
1181                                         free_params(paramValues, nParams, false, stmt->lineno);
1182                                         return false;
1183                                 }
1184
1185                                 snprintf(buffer, buffersize, "$%d", counter++);
1186
1187                                 if (!(newcopy = (char *) ECPGalloc(strlen(stmt->command) + strlen(buffer) + 1, stmt->lineno)))
1188                                 {
1189                                         free_params(paramValues, nParams, false, stmt->lineno);
1190                                         ECPGfree(buffer);
1191                                         return false;
1192                                 }
1193
1194                                 strcpy(newcopy, stmt->command);
1195
1196                                 /* set positional parameter */
1197                                 strcpy(newcopy + position - 1, buffer);
1198
1199                                 /*
1200                                  * The strange thing in the second argument is the rest of the
1201                                  * string from the old string
1202                                  */
1203                                 strcat(newcopy,
1204                                            stmt->command
1205                                            + position + 1);
1206                                 ECPGfree(buffer);
1207                                 ECPGfree(stmt->command);
1208                                 stmt->command = newcopy;
1209                         }
1210                 }
1211                 else
1212                 {
1213                         char *newcopy;
1214
1215                         if (!(newcopy = (char *) ECPGalloc(strlen(stmt->command)
1216                                                                                            + strlen(tobeinserted)
1217                                                                                            + 1, stmt->lineno)))
1218                         {
1219                                 free_params(paramValues, nParams, false, stmt->lineno);
1220                                 return false;
1221                         }
1222
1223                         strcpy(newcopy, stmt->command);
1224                         if ((position = next_insert(stmt->command, position, stmt->questionmarks) + 1) == 0)
1225                         {
1226                                 /*
1227                                  * We have an argument but we dont have the matched up string
1228                                  * in the string
1229                                  */
1230                                 ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS,
1231                                                 ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS,
1232                                                   NULL);
1233                                 free_params(paramValues, nParams, false, stmt->lineno);
1234                                 ECPGfree(newcopy);
1235                                 return false;
1236                         }
1237                         else
1238                         {
1239                                 int ph_len = (stmt->command[position] == '?') ? strlen("?") : strlen("$1");
1240
1241                                 strcpy(newcopy + position - 1, tobeinserted);
1242
1243                                 /*
1244                                  * The strange thing in the second argument is the rest of the
1245                                  * string from the old string
1246                                  */
1247                                 strcat(newcopy,
1248                                            stmt->command
1249                                            + position 
1250                                            + ph_len - 1);
1251                         }
1252
1253                         ECPGfree(stmt->command);
1254                         stmt->command = newcopy;
1255                         
1256                         ECPGfree((char *)tobeinserted);
1257                         tobeinserted = NULL;
1258                 }
1259
1260                 if (desc_counter == 0)
1261                         var = var->next;
1262         }
1263
1264         /* Check if there are unmatched things left. */
1265         if (next_insert(stmt->command, position, stmt->questionmarks) >= 0)
1266         {
1267                 ECPGraise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS,
1268                                   ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL);
1269                 free_params(paramValues, nParams, false, stmt->lineno);
1270                 return false;
1271         }
1272
1273         /* The request has been build. */
1274
1275         if (stmt->connection->committed && !stmt->connection->autocommit)
1276         {
1277                 results = PQexec(stmt->connection->connection, "begin transaction");
1278                 if (!ECPGcheck_PQresult(results, stmt->lineno, stmt->connection->connection, stmt->compat))
1279                 {
1280                         free_params(paramValues, nParams, false, stmt->lineno);
1281                         return false;
1282                 }
1283                 PQclear(results);
1284                 stmt->connection->committed = false;
1285         }
1286
1287         ECPGlog("ECPGexecute line %d: QUERY: %s with %d parameter on connection %s \n", stmt->lineno, stmt->command, nParams, stmt->connection->name);
1288         if (stmt->statement_type == ECPGst_execute)
1289         {
1290                 results = PQexecPrepared(stmt->connection->connection, stmt->name, nParams, paramValues, NULL, NULL, 0);
1291                 ECPGlog("ECPGexecute line %d: using PQexecPrepared for %s\n", stmt->lineno, stmt->command);
1292         }
1293         else
1294         {
1295                 if (nParams == 0)
1296                 {
1297                         results = PQexec(stmt->connection->connection, stmt->command);
1298                         ECPGlog("ECPGexecute line %d: using PQexec\n", stmt->lineno);
1299                 }
1300                 else
1301                 {
1302                         results = PQexecParams(stmt->connection->connection, stmt->command, nParams, NULL, paramValues, NULL, NULL, 0);
1303                         ECPGlog("ECPGexecute line %d: using PQexecParams \n", stmt->lineno);
1304                 }
1305         }
1306
1307         free_params(paramValues, nParams, true, stmt->lineno);
1308
1309         if (!ECPGcheck_PQresult(results, stmt->lineno, stmt->connection->connection, stmt->compat))
1310                 return (false);
1311
1312         var = stmt->outlist;
1313         switch (PQresultStatus(results))
1314         {
1315                 int                     nfields,
1316                                         ntuples,
1317                                         act_field;
1318
1319                 case PGRES_TUPLES_OK:
1320                         nfields = PQnfields(results);
1321                         sqlca->sqlerrd[2] = ntuples = PQntuples(results);
1322                         ECPGlog("ECPGexecute line %d: Correctly got %d tuples with %d fields\n", stmt->lineno, ntuples, nfields);
1323                         status = true;
1324
1325                         if (ntuples < 1)
1326                         {
1327                                 if (ntuples)
1328                                         ECPGlog("ECPGexecute line %d: Incorrect number of matches: %d\n",
1329                                                         stmt->lineno, ntuples);
1330                                 ECPGraise(stmt->lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
1331                                 status = false;
1332                                 break;
1333                         }
1334
1335                         if (var != NULL && var->type == ECPGt_descriptor)
1336                         {
1337                                 PGresult  **resultpp = ECPGdescriptor_lvalue(stmt->lineno, (const char *) var->pointer);
1338
1339                                 if (resultpp == NULL)
1340                                         status = false;
1341                                 else
1342                                 {
1343                                         if (*resultpp)
1344                                                 PQclear(*resultpp);
1345                                         *resultpp = results;
1346                                         clear_result = FALSE;
1347                                         ECPGlog("ECPGexecute putting result (%d tuples) into descriptor '%s'\n", PQntuples(results), (const char *) var->pointer);
1348                                 }
1349                                 var = var->next;
1350                         }
1351                         else
1352                                 for (act_field = 0; act_field < nfields && status; act_field++)
1353                                 {
1354                                         if (var != NULL)
1355                                         {
1356                                                 status = ECPGstore_result(results, act_field, stmt, var);
1357                                                 var = var->next;
1358                                         }
1359                                         else if (!INFORMIX_MODE(stmt->compat))
1360                                         {
1361                                                 ECPGraise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_TARGETS, NULL);
1362                                                 return (false);
1363                                         }
1364                                 }
1365
1366                         if (status && var != NULL)
1367                         {
1368                                 ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_TARGETS, NULL);
1369                                 status = false;
1370                         }
1371
1372                         break;
1373                 case PGRES_COMMAND_OK:
1374                         status = true;
1375                         cmdstat = PQcmdStatus(results);
1376                         sqlca->sqlerrd[1] = PQoidValue(results);
1377                         sqlca->sqlerrd[2] = atol(PQcmdTuples(results));
1378                         ECPGlog("ECPGexecute line %d Ok: %s\n", stmt->lineno, cmdstat);
1379                         if (stmt->compat != ECPG_COMPAT_INFORMIX_SE &&
1380                                 !sqlca->sqlerrd[2] &&
1381                                 (!strncmp(cmdstat, "UPDATE", 6)
1382                                  || !strncmp(cmdstat, "INSERT", 6)
1383                                  || !strncmp(cmdstat, "DELETE", 6)))
1384                                 ECPGraise(stmt->lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
1385                         break;
1386                 case PGRES_COPY_OUT:
1387                         {
1388                                 char       *buffer;
1389                                 int                     res;
1390
1391                                 ECPGlog("ECPGexecute line %d: Got PGRES_COPY_OUT\n", stmt->lineno);
1392                                 while ((res = PQgetCopyData(stmt->connection->connection,
1393                                                                                         &buffer, 0)) > 0)
1394                                 {
1395                                         printf("%s", buffer);
1396                                         PQfreemem(buffer);
1397                                 }
1398                                 if (res == -1)
1399                                 {
1400                                         /* COPY done */
1401                                         PQclear(results);
1402                                         results = PQgetResult(stmt->connection->connection);
1403                                         if (PQresultStatus(results) == PGRES_COMMAND_OK)
1404                                                 ECPGlog("ECPGexecute line %d: Got PGRES_COMMAND_OK after PGRES_COPY_OUT\n", stmt->lineno);
1405                                         else
1406                                                 ECPGlog("ECPGexecute line %d: Got error after PGRES_COPY_OUT: %s", PQresultErrorMessage(results));
1407                                 }
1408                                 break;
1409                         }
1410                 default:
1411                         /* execution should never reach this code because it is already handled in ECPGcheck_PQresult() */
1412                         ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
1413                                         stmt->lineno);
1414                         ECPGraise_backend(stmt->lineno, results, stmt->connection->connection, stmt->compat);
1415                         status = false;
1416                         break;
1417         }
1418         if (clear_result)
1419                 PQclear(results);
1420
1421         /* check for asynchronous returns */
1422         notify = PQnotifies(stmt->connection->connection);
1423         if (notify)
1424         {
1425                 ECPGlog("ECPGexecute line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
1426                                 stmt->lineno, notify->relname, notify->be_pid);
1427                 PQfreemem(notify);
1428         }
1429
1430         return status;
1431 }
1432
1433 bool
1434 ECPGdo(const int lineno, const int compat, const int force_indicator, const char *connection_name, const bool questionmarks, const enum ECPG_statement_type st, const char *query,...)
1435 {
1436         va_list         args;
1437         struct statement *stmt;
1438         struct connection *con;
1439         bool            status;
1440         char       *oldlocale;
1441         enum ECPGttype type;
1442         struct variable **list;
1443         enum ECPG_statement_type statement_type = st;
1444         char *prepname;
1445
1446         if (!query)
1447         {
1448                 ECPGraise(lineno, ECPG_EMPTY, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, NULL);
1449                 return(false);
1450         }
1451
1452         /* Make sure we do NOT honor the locale for numeric input/output */
1453         /* since the database wants the standard decimal point */
1454         oldlocale = ECPGstrdup(setlocale(LC_NUMERIC, NULL), lineno);
1455         setlocale(LC_NUMERIC, "C");
1456
1457 #ifdef ENABLE_THREAD_SAFETY
1458         ecpg_pthreads_init();
1459 #endif
1460
1461         con = ECPGget_connection(connection_name);
1462
1463         if (!ECPGinit(con, connection_name, lineno))
1464         {
1465                 setlocale(LC_NUMERIC, oldlocale);
1466                 ECPGfree(oldlocale);
1467                 return (false);
1468         }
1469
1470         /* construct statement in our own structure */
1471         va_start(args, query);
1472
1473         /*
1474          * create a list of variables
1475          * The variables are listed with input variables preceding outputvariables
1476          * The end of each group is marked by an end marker.
1477          * per variable we list:
1478          * type - as defined in ecpgtype.h
1479          * value - where to store the data
1480          * varcharsize - length of string in case we have a stringvariable, else 0
1481          * arraysize - 0 for pointer (we don't know the size of the array),
1482          * 1 for simple variable, size for arrays
1483          * offset - offset between ith and (i+1)th entry in an array,
1484          * normally that means sizeof(type)
1485          * ind_type - type of indicator variable
1486          * ind_value - pointer to indicator variable
1487          * ind_varcharsize - empty
1488          * ind_arraysize -      arraysize of indicator array
1489          * ind_offset - indicator offset
1490          */
1491         if (!(stmt = (struct statement *) ECPGalloc(sizeof(struct statement), lineno)))
1492         {
1493                 setlocale(LC_NUMERIC, oldlocale);
1494                 ECPGfree(oldlocale);
1495                 va_end(args);
1496                 return false;
1497         }
1498
1499         /* If statement type is ECPGst_prepnormal we are supposed to prepare
1500          * the statement before executing them */
1501         if (statement_type == ECPGst_prepnormal)
1502         {
1503                 if (!ECPGauto_prepare(lineno, connection_name, questionmarks, &prepname, query))
1504                         return(false);
1505
1506                 /* statement is now prepared, so instead of the query we have to execute the name */
1507                 stmt->command = prepname;
1508                 statement_type = ECPGst_execute;
1509         }
1510         else
1511                 stmt->command = ECPGstrdup(query, lineno);
1512
1513         stmt->name = NULL;
1514
1515         if (statement_type == ECPGst_execute)
1516         {
1517                 /* if we have an EXECUTE command, only the name is send */
1518                 char *command = ECPGprepared(stmt->command, con, lineno);
1519
1520                 if (command)
1521                 {
1522                         stmt->name = stmt->command;
1523                         stmt->command = ECPGstrdup(command, lineno);
1524                 }
1525                 else
1526                         ECPGraise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt->command);
1527         }
1528
1529         stmt->connection = con;
1530         stmt->lineno = lineno;
1531         stmt->compat = compat;
1532         stmt->force_indicator = force_indicator;
1533         stmt->questionmarks = questionmarks;
1534         stmt->statement_type = statement_type;
1535
1536         list = &(stmt->inlist);
1537
1538         type = va_arg(args, enum ECPGttype);
1539
1540         while (type != ECPGt_EORT)
1541         {
1542                 if (type == ECPGt_EOIT)
1543                         list = &(stmt->outlist);
1544                 else
1545                 {
1546                         struct variable *var,
1547                                            *ptr;
1548
1549                         if (!(var = (struct variable *) ECPGalloc(sizeof(struct variable), lineno)))
1550                         {
1551                                 setlocale(LC_NUMERIC, oldlocale);
1552                                 ECPGfree(oldlocale);
1553                                 free_statement(stmt);
1554                                 va_end(args);
1555                                 return false;
1556                         }
1557
1558                         var->type = type;
1559                         var->pointer = va_arg(args, char *);
1560
1561                         var->varcharsize = va_arg(args, long);
1562                         var->arrsize = va_arg(args, long);
1563                         var->offset = va_arg(args, long);
1564
1565                         if (var->arrsize == 0 || var->varcharsize == 0)
1566                                 var->value = *((char **) (var->pointer));
1567                         else
1568                                 var->value = var->pointer;
1569
1570                         /*
1571                          * negative values are used to indicate an array without given bounds
1572                          */
1573                         /* reset to zero for us */
1574                         if (var->arrsize < 0)
1575                                 var->arrsize = 0;
1576                         if (var->varcharsize < 0)
1577                                 var->varcharsize = 0;
1578
1579                         var->next = NULL;
1580
1581                         var->ind_type = va_arg(args, enum ECPGttype);
1582                         var->ind_pointer = va_arg(args, char *);
1583                         var->ind_varcharsize = va_arg(args, long);
1584                         var->ind_arrsize = va_arg(args, long);
1585                         var->ind_offset = va_arg(args, long);
1586
1587                         if (var->ind_type != ECPGt_NO_INDICATOR
1588                                 && (var->ind_arrsize == 0 || var->ind_varcharsize == 0))
1589                                 var->ind_value = *((char **) (var->ind_pointer));
1590                         else
1591                                 var->ind_value = var->ind_pointer;
1592
1593                         /*
1594                          * negative values are used to indicate an array without given bounds
1595                          */
1596                         /* reset to zero for us */
1597                         if (var->ind_arrsize < 0)
1598                                 var->ind_arrsize = 0;
1599                         if (var->ind_varcharsize < 0)
1600                                 var->ind_varcharsize = 0;
1601
1602                         /* if variable is NULL, the statement hasn't been prepared */
1603                         if (var->pointer == NULL)
1604                         {
1605                                 ECPGraise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, NULL);
1606                                 ECPGfree(var);
1607                                 setlocale(LC_NUMERIC, oldlocale);
1608                                 ECPGfree(oldlocale);
1609                                 free_statement(stmt);
1610                                 va_end(args);
1611                                 return false;
1612                         }
1613
1614                         for (ptr = *list; ptr && ptr->next; ptr = ptr->next);
1615
1616                         if (ptr == NULL)
1617                                 *list = var;
1618                         else
1619                                 ptr->next = var;
1620                 }
1621
1622                 type = va_arg(args, enum ECPGttype);
1623         }
1624
1625         va_end(args);
1626
1627         /* are we connected? */
1628         if (con == NULL || con->connection == NULL)
1629         {
1630                 free_statement(stmt);
1631                 ECPGraise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, (con) ? con->name : "<empty>");
1632                 setlocale(LC_NUMERIC, oldlocale);
1633                 ECPGfree(oldlocale);
1634                 return false;
1635         }
1636
1637         /* initialize auto_mem struct */
1638         ECPGclear_auto_mem();
1639
1640         status = ECPGexecute(stmt);
1641         free_statement(stmt);
1642
1643         /* and reset locale value so our application is not affected */
1644         setlocale(LC_NUMERIC, oldlocale);
1645         ECPGfree(oldlocale);
1646
1647         return (status);
1648 }
1649
1650 /* old descriptor interface */
1651 bool
1652 ECPGdo_descriptor(int line, const char *connection,
1653                                   const char *descriptor, const char *query)
1654 {
1655         return ECPGdo(line, ECPG_COMPAT_PGSQL, true, connection, '\0', 0, (char *) query, ECPGt_EOIT,
1656                                   ECPGt_descriptor, descriptor, 0L, 0L, 0L,
1657                                   ECPGt_NO_INDICATOR, NULL, 0L, 0L, 0L, ECPGt_EORT);
1658 }