Header And Logo

PostgreSQL
| The world's most advanced open source database.

execute.c

Go to the documentation of this file.
00001 /* src/interfaces/ecpg/ecpglib/execute.c */
00002 
00003 /*
00004  * The aim is to get a simpler inteface to the database routines.
00005  * All the tidieous messing around with tuples is supposed to be hidden
00006  * by this function.
00007  */
00008 /* Author: Linus Tolke
00009    (actually most if the code is "borrowed" from the distribution and just
00010    slightly modified)
00011  */
00012 
00013 /* Taken over as part of PostgreSQL by Michael Meskes <[email protected]>
00014    on Feb. 5th, 1998 */
00015 
00016 #define POSTGRES_ECPG_INTERNAL
00017 #include "postgres_fe.h"
00018 
00019 #include <locale.h>
00020 #include <float.h>
00021 #include <math.h>
00022 
00023 #include "pg_type.h"
00024 
00025 #include "ecpgtype.h"
00026 #include "ecpglib.h"
00027 #include "ecpgerrno.h"
00028 #include "extern.h"
00029 #include "sqlca.h"
00030 #include "sqlda-native.h"
00031 #include "sqlda-compat.h"
00032 #include "sql3types.h"
00033 #include "pgtypes_numeric.h"
00034 #include "pgtypes_date.h"
00035 #include "pgtypes_timestamp.h"
00036 #include "pgtypes_interval.h"
00037 
00038 /*
00039  *  This function returns a newly malloced string that has ' and \
00040  *  escaped.
00041  */
00042 static char *
00043 quote_postgres(char *arg, bool quote, int lineno)
00044 {
00045     char       *res;
00046     size_t      length;
00047     size_t      escaped_len;
00048     size_t      buffer_len;
00049 
00050     /*
00051      * if quote is false we just need to store things in a descriptor they
00052      * will be quoted once they are inserted in a statement
00053      */
00054     if (!quote)
00055         return arg;
00056     else
00057     {
00058         length = strlen(arg);
00059         buffer_len = 2 * length + 1;
00060         res = (char *) ecpg_alloc(buffer_len + 3, lineno);
00061         if (!res)
00062             return (res);
00063         escaped_len = PQescapeString(res + 1, arg, buffer_len);
00064         if (length == escaped_len)
00065         {
00066             res[0] = res[escaped_len + 1] = '\'';
00067             res[escaped_len + 2] = '\0';
00068         }
00069         else
00070         {
00071             /*
00072              * We don't know if the target database is using
00073              * standard_conforming_strings, so we always use E'' strings.
00074              */
00075             memmove(res + 2, res + 1, escaped_len);
00076             res[0] = ESCAPE_STRING_SYNTAX;
00077             res[1] = res[escaped_len + 2] = '\'';
00078             res[escaped_len + 3] = '\0';
00079         }
00080         ecpg_free(arg);
00081         return res;
00082     }
00083 }
00084 
00085 static void
00086 free_variable(struct variable * var)
00087 {
00088     struct variable *var_next;
00089 
00090     if (var == NULL)
00091         return;
00092     var_next = var->next;
00093     ecpg_free(var);
00094 
00095     while (var_next)
00096     {
00097         var = var_next;
00098         var_next = var->next;
00099         ecpg_free(var);
00100     }
00101 }
00102 
00103 static void
00104 free_statement(struct statement * stmt)
00105 {
00106     if (stmt == NULL)
00107         return;
00108     free_variable(stmt->inlist);
00109     free_variable(stmt->outlist);
00110     ecpg_free(stmt->command);
00111     ecpg_free(stmt->name);
00112     ecpg_free(stmt);
00113 }
00114 
00115 static int
00116 next_insert(char *text, int pos, bool questionmarks)
00117 {
00118     bool        string = false;
00119     int         p = pos;
00120 
00121     for (; text[p] != '\0'; p++)
00122     {
00123         if (text[p] == '\\')    /* escape character */
00124             p++;
00125         else if (text[p] == '\'')
00126             string = string ? false : true;
00127         else if (!string)
00128         {
00129             if (text[p] == '$' && isdigit((unsigned char) text[p + 1]))
00130             {
00131                 /* this can be either a dollar quote or a variable */
00132                 int         i;
00133 
00134                 for (i = p + 1; isdigit((unsigned char) text[i]); i++)
00135                      /* empty loop body */ ;
00136                 if (!isalpha((unsigned char) text[i]) &&
00137                     isascii((unsigned char) text[i]) &&text[i] != '_')
00138                     /* not dollar delimited quote */
00139                     return p;
00140             }
00141             else if (questionmarks && text[p] == '?')
00142             {
00143                 /* also allow old style placeholders */
00144                 return p;
00145             }
00146         }
00147     }
00148 
00149     return -1;
00150 }
00151 
00152 static bool
00153 ecpg_type_infocache_push(struct ECPGtype_information_cache ** cache, int oid, bool isarray, int lineno)
00154 {
00155     struct ECPGtype_information_cache *new_entry
00156     = (struct ECPGtype_information_cache *) ecpg_alloc(sizeof(struct ECPGtype_information_cache), lineno);
00157 
00158     if (new_entry == NULL)
00159         return (false);
00160 
00161     new_entry->oid = oid;
00162     new_entry->isarray = isarray;
00163     new_entry->next = *cache;
00164     *cache = new_entry;
00165     return (true);
00166 }
00167 
00168 static enum ARRAY_TYPE
00169 ecpg_is_type_an_array(int type, const struct statement * stmt, const struct variable * var)
00170 {
00171     char       *array_query;
00172     enum ARRAY_TYPE isarray = ECPG_ARRAY_NOT_SET;
00173     PGresult   *query;
00174     struct ECPGtype_information_cache *cache_entry;
00175 
00176     if ((stmt->connection->cache_head) == NULL)
00177     {
00178         /*
00179          * Text like types are not an array for ecpg, but postgres counts them
00180          * as an array. This define reminds you to not 'correct' these values.
00181          */
00182 #define not_an_array_in_ecpg ECPG_ARRAY_NONE
00183 
00184         /* populate cache with well known types to speed things up */
00185         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), BOOLOID, ECPG_ARRAY_NONE, stmt->lineno))
00186             return (ECPG_ARRAY_ERROR);
00187         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), BYTEAOID, ECPG_ARRAY_NONE, stmt->lineno))
00188             return (ECPG_ARRAY_ERROR);
00189         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), CHAROID, ECPG_ARRAY_NONE, stmt->lineno))
00190             return (ECPG_ARRAY_ERROR);
00191         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), NAMEOID, not_an_array_in_ecpg, stmt->lineno))
00192             return (ECPG_ARRAY_ERROR);
00193         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), INT8OID, ECPG_ARRAY_NONE, stmt->lineno))
00194             return (ECPG_ARRAY_ERROR);
00195         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), INT2OID, ECPG_ARRAY_NONE, stmt->lineno))
00196             return (ECPG_ARRAY_ERROR);
00197         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), INT2VECTOROID, ECPG_ARRAY_VECTOR, stmt->lineno))
00198             return (ECPG_ARRAY_ERROR);
00199         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), INT4OID, ECPG_ARRAY_NONE, stmt->lineno))
00200             return (ECPG_ARRAY_ERROR);
00201         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), REGPROCOID, ECPG_ARRAY_NONE, stmt->lineno))
00202             return (ECPG_ARRAY_ERROR);
00203         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), TEXTOID, ECPG_ARRAY_NONE, stmt->lineno))
00204             return (ECPG_ARRAY_ERROR);
00205         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), OIDOID, ECPG_ARRAY_NONE, stmt->lineno))
00206             return (ECPG_ARRAY_ERROR);
00207         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), TIDOID, ECPG_ARRAY_NONE, stmt->lineno))
00208             return (ECPG_ARRAY_ERROR);
00209         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), XIDOID, ECPG_ARRAY_NONE, stmt->lineno))
00210             return (ECPG_ARRAY_ERROR);
00211         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), CIDOID, ECPG_ARRAY_NONE, stmt->lineno))
00212             return (ECPG_ARRAY_ERROR);
00213         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), OIDVECTOROID, ECPG_ARRAY_VECTOR, stmt->lineno))
00214             return (ECPG_ARRAY_ERROR);
00215         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), POINTOID, ECPG_ARRAY_VECTOR, stmt->lineno))
00216             return (ECPG_ARRAY_ERROR);
00217         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), LSEGOID, ECPG_ARRAY_VECTOR, stmt->lineno))
00218             return (ECPG_ARRAY_ERROR);
00219         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), PATHOID, ECPG_ARRAY_NONE, stmt->lineno))
00220             return (ECPG_ARRAY_ERROR);
00221         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), BOXOID, ECPG_ARRAY_VECTOR, stmt->lineno))
00222             return (ECPG_ARRAY_ERROR);
00223         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), POLYGONOID, ECPG_ARRAY_NONE, stmt->lineno))
00224             return (ECPG_ARRAY_ERROR);
00225         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), LINEOID, ECPG_ARRAY_VECTOR, stmt->lineno))
00226             return (ECPG_ARRAY_ERROR);
00227         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), FLOAT4OID, ECPG_ARRAY_NONE, stmt->lineno))
00228             return (ECPG_ARRAY_ERROR);
00229         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), FLOAT8OID, ECPG_ARRAY_NONE, stmt->lineno))
00230             return (ECPG_ARRAY_ERROR);
00231         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), ABSTIMEOID, ECPG_ARRAY_NONE, stmt->lineno))
00232             return (ECPG_ARRAY_ERROR);
00233         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), RELTIMEOID, ECPG_ARRAY_NONE, stmt->lineno))
00234             return (ECPG_ARRAY_ERROR);
00235         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), TINTERVALOID, ECPG_ARRAY_NONE, stmt->lineno))
00236             return (ECPG_ARRAY_ERROR);
00237         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), UNKNOWNOID, ECPG_ARRAY_NONE, stmt->lineno))
00238             return (ECPG_ARRAY_ERROR);
00239         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), CIRCLEOID, ECPG_ARRAY_NONE, stmt->lineno))
00240             return (ECPG_ARRAY_ERROR);
00241         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), CASHOID, ECPG_ARRAY_NONE, stmt->lineno))
00242             return (ECPG_ARRAY_ERROR);
00243         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), INETOID, ECPG_ARRAY_NONE, stmt->lineno))
00244             return (ECPG_ARRAY_ERROR);
00245         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), CIDROID, ECPG_ARRAY_NONE, stmt->lineno))
00246             return (ECPG_ARRAY_ERROR);
00247         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), BPCHAROID, ECPG_ARRAY_NONE, stmt->lineno))
00248             return (ECPG_ARRAY_ERROR);
00249         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), VARCHAROID, ECPG_ARRAY_NONE, stmt->lineno))
00250             return (ECPG_ARRAY_ERROR);
00251         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), DATEOID, ECPG_ARRAY_NONE, stmt->lineno))
00252             return (ECPG_ARRAY_ERROR);
00253         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), TIMEOID, ECPG_ARRAY_NONE, stmt->lineno))
00254             return (ECPG_ARRAY_ERROR);
00255         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), TIMESTAMPOID, ECPG_ARRAY_NONE, stmt->lineno))
00256             return (ECPG_ARRAY_ERROR);
00257         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), TIMESTAMPTZOID, ECPG_ARRAY_NONE, stmt->lineno))
00258             return (ECPG_ARRAY_ERROR);
00259         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), INTERVALOID, ECPG_ARRAY_NONE, stmt->lineno))
00260             return (ECPG_ARRAY_ERROR);
00261         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), TIMETZOID, ECPG_ARRAY_NONE, stmt->lineno))
00262             return (ECPG_ARRAY_ERROR);
00263         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), ZPBITOID, ECPG_ARRAY_NONE, stmt->lineno))
00264             return (ECPG_ARRAY_ERROR);
00265         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), VARBITOID, ECPG_ARRAY_NONE, stmt->lineno))
00266             return (ECPG_ARRAY_ERROR);
00267         if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), NUMERICOID, ECPG_ARRAY_NONE, stmt->lineno))
00268             return (ECPG_ARRAY_ERROR);
00269     }
00270 
00271     for (cache_entry = (stmt->connection->cache_head); cache_entry != NULL; cache_entry = cache_entry->next)
00272     {
00273         if (cache_entry->oid == type)
00274             return cache_entry->isarray;
00275     }
00276 
00277     array_query = (char *) ecpg_alloc(strlen("select typlen from pg_type where oid= and typelem<>0") + 11, stmt->lineno);
00278     if (array_query == NULL)
00279         return (ECPG_ARRAY_ERROR);
00280 
00281     sprintf(array_query, "select typlen from pg_type where oid=%d and typelem<>0", type);
00282     query = PQexec(stmt->connection->connection, array_query);
00283     ecpg_free(array_query);
00284     if (!ecpg_check_PQresult(query, stmt->lineno, stmt->connection->connection, stmt->compat))
00285         return (ECPG_ARRAY_ERROR);
00286     else if (PQresultStatus(query) == PGRES_TUPLES_OK)
00287     {
00288         if (PQntuples(query) == 0)
00289             isarray = ECPG_ARRAY_NONE;
00290         else
00291         {
00292             isarray = (atol((char *) PQgetvalue(query, 0, 0)) == -1) ? ECPG_ARRAY_ARRAY : ECPG_ARRAY_VECTOR;
00293             if (ecpg_dynamic_type(type) == SQL3_CHARACTER ||
00294                 ecpg_dynamic_type(type) == SQL3_CHARACTER_VARYING)
00295             {
00296                 /*
00297                  * arrays of character strings are not yet implemented
00298                  */
00299                 isarray = ECPG_ARRAY_NONE;
00300             }
00301         }
00302         PQclear(query);
00303     }
00304     else
00305         return (ECPG_ARRAY_ERROR);
00306 
00307     ecpg_type_infocache_push(&(stmt->connection->cache_head), type, isarray, stmt->lineno);
00308     ecpg_log("ecpg_is_type_an_array on line %d: type (%d); C (%d); array (%s)\n", stmt->lineno, type, var->type, ECPG_IS_ARRAY(isarray) ? "yes" : "no");
00309     return isarray;
00310 }
00311 
00312 
00313 bool
00314 ecpg_store_result(const PGresult *results, int act_field,
00315                   const struct statement * stmt, struct variable * var)
00316 {
00317     enum ARRAY_TYPE isarray;
00318     int         act_tuple,
00319                 ntuples = PQntuples(results);
00320     bool        status = true;
00321 
00322     if ((isarray = ecpg_is_type_an_array(PQftype(results, act_field), stmt, var)) == ECPG_ARRAY_ERROR)
00323     {
00324         ecpg_raise(stmt->lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
00325         return false;
00326     }
00327 
00328     if (isarray == ECPG_ARRAY_NONE)
00329     {
00330         /*
00331          * if we don't have enough space, we cannot read all tuples
00332          */
00333         if ((var->arrsize > 0 && ntuples > var->arrsize) || (var->ind_arrsize > 0 && ntuples > var->ind_arrsize))
00334         {
00335             ecpg_log("ecpg_store_result on line %d: incorrect number of matches; %d don't fit into array of %ld\n",
00336                      stmt->lineno, ntuples, var->arrsize);
00337             ecpg_raise(stmt->lineno, INFORMIX_MODE(stmt->compat) ? ECPG_INFORMIX_SUBSELECT_NOT_ONE : ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
00338             return false;
00339         }
00340     }
00341     else
00342     {
00343         /*
00344          * since we read an array, the variable has to be an array too
00345          */
00346         if (var->arrsize == 0)
00347         {
00348             ecpg_raise(stmt->lineno, ECPG_NO_ARRAY, ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL);
00349             return false;
00350         }
00351     }
00352 
00353     /*
00354      * allocate memory for NULL pointers
00355      */
00356     if ((var->arrsize == 0 || var->varcharsize == 0) && var->value == NULL)
00357     {
00358         int         len = 0;
00359 
00360         if (!PQfformat(results, act_field))
00361         {
00362             switch (var->type)
00363             {
00364                 case ECPGt_char:
00365                 case ECPGt_unsigned_char:
00366                 case ECPGt_string:
00367                     if (!var->varcharsize && !var->arrsize)
00368                     {
00369                         /* special mode for handling char**foo=0 */
00370                         for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
00371                             len += strlen(PQgetvalue(results, act_tuple, act_field)) + 1;
00372                         len *= var->offset;     /* should be 1, but YMNK */
00373                         len += (ntuples + 1) * sizeof(char *);
00374                     }
00375                     else
00376                     {
00377                         var->varcharsize = 0;
00378                         /* check strlen for each tuple */
00379                         for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
00380                         {
00381                             int         len = strlen(PQgetvalue(results, act_tuple, act_field)) + 1;
00382 
00383                             if (len > var->varcharsize)
00384                                 var->varcharsize = len;
00385                         }
00386                         var->offset *= var->varcharsize;
00387                         len = var->offset * ntuples;
00388                     }
00389                     break;
00390                 case ECPGt_varchar:
00391                     len = ntuples * (var->varcharsize + sizeof(int));
00392                     break;
00393                 default:
00394                     len = var->offset * ntuples;
00395                     break;
00396             }
00397         }
00398         else
00399         {
00400             for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
00401                 len += PQgetlength(results, act_tuple, act_field);
00402         }
00403 
00404         ecpg_log("ecpg_store_result on line %d: allocating memory for %d tuples\n", stmt->lineno, ntuples);
00405         var->value = (char *) ecpg_alloc(len, stmt->lineno);
00406         if (!var->value)
00407             return false;
00408         *((char **) var->pointer) = var->value;
00409         ecpg_add_mem(var->value, stmt->lineno);
00410     }
00411 
00412     /* allocate indicator variable if needed */
00413     if ((var->ind_arrsize == 0 || var->ind_varcharsize == 0) && var->ind_value == NULL && var->ind_pointer != NULL)
00414     {
00415         int         len = var->ind_offset * ntuples;
00416 
00417         var->ind_value = (char *) ecpg_alloc(len, stmt->lineno);
00418         if (!var->ind_value)
00419             return false;
00420         *((char **) var->ind_pointer) = var->ind_value;
00421         ecpg_add_mem(var->ind_value, stmt->lineno);
00422     }
00423 
00424     /* fill the variable with the tuple(s) */
00425     if (!var->varcharsize && !var->arrsize &&
00426         (var->type == ECPGt_char || var->type == ECPGt_unsigned_char || var->type == ECPGt_string))
00427     {
00428         /* special mode for handling char**foo=0 */
00429 
00430         /* filling the array of (char*)s */
00431         char      **current_string = (char **) var->value;
00432 
00433         /* storing the data (after the last array element) */
00434         char       *current_data_location = (char *) &current_string[ntuples + 1];
00435 
00436         for (act_tuple = 0; act_tuple < ntuples && status; act_tuple++)
00437         {
00438             int         len = strlen(PQgetvalue(results, act_tuple, act_field)) + 1;
00439 
00440             if (!ecpg_get_data(results, act_tuple, act_field, stmt->lineno,
00441                              var->type, var->ind_type, current_data_location,
00442                                var->ind_value, len, 0, var->ind_offset, isarray, stmt->compat, stmt->force_indicator))
00443                 status = false;
00444             else
00445             {
00446                 *current_string = current_data_location;
00447                 current_data_location += len;
00448                 current_string++;
00449             }
00450         }
00451 
00452         /* terminate the list */
00453         *current_string = NULL;
00454     }
00455     else
00456     {
00457         for (act_tuple = 0; act_tuple < ntuples && status; act_tuple++)
00458         {
00459             if (!ecpg_get_data(results, act_tuple, act_field, stmt->lineno,
00460                                var->type, var->ind_type, var->value,
00461                                var->ind_value, var->varcharsize, var->offset, var->ind_offset, isarray, stmt->compat, stmt->force_indicator))
00462                 status = false;
00463         }
00464     }
00465     return status;
00466 }
00467 
00468 static void
00469 sprintf_double_value(char *ptr, double value, const char *delim)
00470 {
00471     if (isnan(value))
00472         sprintf(ptr, "%s%s", "NaN", delim);
00473     else if (isinf(value))
00474     {
00475         if (value < 0)
00476             sprintf(ptr, "%s%s", "-Infinity", delim);
00477         else
00478             sprintf(ptr, "%s%s", "Infinity", delim);
00479     }
00480     else
00481         sprintf(ptr, "%.15g%s", value, delim);
00482 }
00483 
00484 static void
00485 sprintf_float_value(char *ptr, float value, const char *delim)
00486 {
00487     if (isnan(value))
00488         sprintf(ptr, "%s%s", "NaN", delim);
00489     else if (isinf(value))
00490     {
00491         if (value < 0)
00492             sprintf(ptr, "%s%s", "-Infinity", delim);
00493         else
00494             sprintf(ptr, "%s%s", "Infinity", delim);
00495     }
00496     else
00497         sprintf(ptr, "%.15g%s", value, delim);
00498 }
00499 
00500 bool
00501 ecpg_store_input(const int lineno, const bool force_indicator, const struct variable * var,
00502                  char **tobeinserted_p, bool quote)
00503 {
00504     char       *mallocedval = NULL;
00505     char       *newcopy = NULL;
00506 
00507     /*
00508      * arrays are not possible unless the attribute is an array too FIXME: we
00509      * do not know if the attribute is an array here
00510      */
00511 #if 0
00512     if (var->arrsize > 1 &&...)
00513     {
00514         ecpg_raise(lineno, ECPG_ARRAY_INSERT, ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL);
00515         return false;
00516     }
00517 #endif
00518 
00519     /*
00520      * Some special treatment is needed for records since we want their
00521      * contents to arrive in a comma-separated list on insert (I think).
00522      */
00523 
00524     *tobeinserted_p = "";
00525 
00526     /* check for null value and set input buffer accordingly */
00527     switch (var->ind_type)
00528     {
00529         case ECPGt_short:
00530         case ECPGt_unsigned_short:
00531             if (*(short *) var->ind_value < 0)
00532                 *tobeinserted_p = NULL;
00533             break;
00534         case ECPGt_int:
00535         case ECPGt_unsigned_int:
00536             if (*(int *) var->ind_value < 0)
00537                 *tobeinserted_p = NULL;
00538             break;
00539         case ECPGt_long:
00540         case ECPGt_unsigned_long:
00541             if (*(long *) var->ind_value < 0L)
00542                 *tobeinserted_p = NULL;
00543             break;
00544 #ifdef HAVE_LONG_LONG_INT
00545         case ECPGt_long_long:
00546         case ECPGt_unsigned_long_long:
00547             if (*(long long int *) var->ind_value < (long long) 0)
00548                 *tobeinserted_p = NULL;
00549             break;
00550 #endif   /* HAVE_LONG_LONG_INT */
00551         case ECPGt_NO_INDICATOR:
00552             if (force_indicator == false)
00553             {
00554                 if (ECPGis_noind_null(var->type, var->value))
00555                     *tobeinserted_p = NULL;
00556             }
00557             break;
00558         default:
00559             break;
00560     }
00561     if (*tobeinserted_p != NULL)
00562     {
00563         int         asize = var->arrsize ? var->arrsize : 1;
00564 
00565         switch (var->type)
00566         {
00567                 int         element;
00568 
00569             case ECPGt_short:
00570                 if (!(mallocedval = ecpg_alloc(asize * 20, lineno)))
00571                     return false;
00572 
00573                 if (asize > 1)
00574                 {
00575                     strcpy(mallocedval, "array [");
00576 
00577                     for (element = 0; element < asize; element++)
00578                         sprintf(mallocedval + strlen(mallocedval), "%hd,", ((short *) var->value)[element]);
00579 
00580                     strcpy(mallocedval + strlen(mallocedval) - 1, "]");
00581                 }
00582                 else
00583                     sprintf(mallocedval, "%hd", *((short *) var->value));
00584 
00585                 *tobeinserted_p = mallocedval;
00586                 break;
00587 
00588             case ECPGt_int:
00589                 if (!(mallocedval = ecpg_alloc(asize * 20, lineno)))
00590                     return false;
00591 
00592                 if (asize > 1)
00593                 {
00594                     strcpy(mallocedval, "{");
00595 
00596                     for (element = 0; element < asize; element++)
00597                         sprintf(mallocedval + strlen(mallocedval), "%d,", ((int *) var->value)[element]);
00598 
00599                     strcpy(mallocedval + strlen(mallocedval) - 1, "}");
00600                 }
00601                 else
00602                     sprintf(mallocedval, "%d", *((int *) var->value));
00603 
00604                 *tobeinserted_p = mallocedval;
00605                 break;
00606 
00607             case ECPGt_unsigned_short:
00608                 if (!(mallocedval = ecpg_alloc(asize * 20, lineno)))
00609                     return false;
00610 
00611                 if (asize > 1)
00612                 {
00613                     strcpy(mallocedval, "array [");
00614 
00615                     for (element = 0; element < asize; element++)
00616                         sprintf(mallocedval + strlen(mallocedval), "%hu,", ((unsigned short *) var->value)[element]);
00617 
00618                     strcpy(mallocedval + strlen(mallocedval) - 1, "]");
00619                 }
00620                 else
00621                     sprintf(mallocedval, "%hu", *((unsigned short *) var->value));
00622 
00623                 *tobeinserted_p = mallocedval;
00624                 break;
00625 
00626             case ECPGt_unsigned_int:
00627                 if (!(mallocedval = ecpg_alloc(asize * 20, lineno)))
00628                     return false;
00629 
00630                 if (asize > 1)
00631                 {
00632                     strcpy(mallocedval, "array [");
00633 
00634                     for (element = 0; element < asize; element++)
00635                         sprintf(mallocedval + strlen(mallocedval), "%u,", ((unsigned int *) var->value)[element]);
00636 
00637                     strcpy(mallocedval + strlen(mallocedval) - 1, "]");
00638                 }
00639                 else
00640                     sprintf(mallocedval, "%u", *((unsigned int *) var->value));
00641 
00642                 *tobeinserted_p = mallocedval;
00643                 break;
00644 
00645             case ECPGt_long:
00646                 if (!(mallocedval = ecpg_alloc(asize * 20, lineno)))
00647                     return false;
00648 
00649                 if (asize > 1)
00650                 {
00651                     strcpy(mallocedval, "array [");
00652 
00653                     for (element = 0; element < asize; element++)
00654                         sprintf(mallocedval + strlen(mallocedval), "%ld,", ((long *) var->value)[element]);
00655 
00656                     strcpy(mallocedval + strlen(mallocedval) - 1, "]");
00657                 }
00658                 else
00659                     sprintf(mallocedval, "%ld", *((long *) var->value));
00660 
00661                 *tobeinserted_p = mallocedval;
00662                 break;
00663 
00664             case ECPGt_unsigned_long:
00665                 if (!(mallocedval = ecpg_alloc(asize * 20, lineno)))
00666                     return false;
00667 
00668                 if (asize > 1)
00669                 {
00670                     strcpy(mallocedval, "array [");
00671 
00672                     for (element = 0; element < asize; element++)
00673                         sprintf(mallocedval + strlen(mallocedval), "%lu,", ((unsigned long *) var->value)[element]);
00674 
00675                     strcpy(mallocedval + strlen(mallocedval) - 1, "]");
00676                 }
00677                 else
00678                     sprintf(mallocedval, "%lu", *((unsigned long *) var->value));
00679 
00680                 *tobeinserted_p = mallocedval;
00681                 break;
00682 #ifdef HAVE_LONG_LONG_INT
00683             case ECPGt_long_long:
00684                 if (!(mallocedval = ecpg_alloc(asize * 30, lineno)))
00685                     return false;
00686 
00687                 if (asize > 1)
00688                 {
00689                     strcpy(mallocedval, "array [");
00690 
00691                     for (element = 0; element < asize; element++)
00692                         sprintf(mallocedval + strlen(mallocedval), "%lld,", ((long long int *) var->value)[element]);
00693 
00694                     strcpy(mallocedval + strlen(mallocedval) - 1, "]");
00695                 }
00696                 else
00697                     sprintf(mallocedval, "%lld", *((long long int *) var->value));
00698 
00699                 *tobeinserted_p = mallocedval;
00700                 break;
00701 
00702             case ECPGt_unsigned_long_long:
00703                 if (!(mallocedval = ecpg_alloc(asize * 30, lineno)))
00704                     return false;
00705 
00706                 if (asize > 1)
00707                 {
00708                     strcpy(mallocedval, "array [");
00709 
00710                     for (element = 0; element < asize; element++)
00711                         sprintf(mallocedval + strlen(mallocedval), "%llu,", ((unsigned long long int *) var->value)[element]);
00712 
00713                     strcpy(mallocedval + strlen(mallocedval) - 1, "]");
00714                 }
00715                 else
00716                     sprintf(mallocedval, "%llu", *((unsigned long long int *) var->value));
00717 
00718                 *tobeinserted_p = mallocedval;
00719                 break;
00720 #endif   /* HAVE_LONG_LONG_INT */
00721             case ECPGt_float:
00722                 if (!(mallocedval = ecpg_alloc(asize * 25, lineno)))
00723                     return false;
00724 
00725                 if (asize > 1)
00726                 {
00727                     strcpy(mallocedval, "array [");
00728 
00729                     for (element = 0; element < asize; element++)
00730                         sprintf_float_value(mallocedval + strlen(mallocedval), ((float *) var->value)[element], ",");
00731 
00732                     strcpy(mallocedval + strlen(mallocedval) - 1, "]");
00733                 }
00734                 else
00735                     sprintf_float_value(mallocedval, *((float *) var->value), "");
00736 
00737                 *tobeinserted_p = mallocedval;
00738                 break;
00739 
00740             case ECPGt_double:
00741                 if (!(mallocedval = ecpg_alloc(asize * 25, lineno)))
00742                     return false;
00743 
00744                 if (asize > 1)
00745                 {
00746                     strcpy(mallocedval, "array [");
00747 
00748                     for (element = 0; element < asize; element++)
00749                         sprintf_double_value(mallocedval + strlen(mallocedval), ((double *) var->value)[element], ",");
00750 
00751                     strcpy(mallocedval + strlen(mallocedval) - 1, "]");
00752                 }
00753                 else
00754                     sprintf_double_value(mallocedval, *((double *) var->value), "");
00755 
00756                 *tobeinserted_p = mallocedval;
00757                 break;
00758 
00759             case ECPGt_bool:
00760                 if (!(mallocedval = ecpg_alloc(var->arrsize + sizeof("array []"), lineno)))
00761                     return false;
00762 
00763                 if (var->arrsize > 1)
00764                 {
00765                     strcpy(mallocedval, "array [");
00766 
00767                     if (var->offset == sizeof(char))
00768                         for (element = 0; element < var->arrsize; element++)
00769                             sprintf(mallocedval + strlen(mallocedval), "%c,", (((char *) var->value)[element]) ? 't' : 'f');
00770 
00771                     /*
00772                      * this is necessary since sizeof(C++'s bool)==sizeof(int)
00773                      */
00774                     else if (var->offset == sizeof(int))
00775                         for (element = 0; element < var->arrsize; element++)
00776                             sprintf(mallocedval + strlen(mallocedval), "%c,", (((int *) var->value)[element]) ? 't' : 'f');
00777                     else
00778                         ecpg_raise(lineno, ECPG_CONVERT_BOOL, ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL);
00779 
00780                     strcpy(mallocedval + strlen(mallocedval) - 1, "]");
00781                 }
00782                 else
00783                 {
00784                     if (var->offset == sizeof(char))
00785                         sprintf(mallocedval, "%c", (*((char *) var->value)) ? 't' : 'f');
00786                     else if (var->offset == sizeof(int))
00787                         sprintf(mallocedval, "%c", (*((int *) var->value)) ? 't' : 'f');
00788                     else
00789                         ecpg_raise(lineno, ECPG_CONVERT_BOOL, ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL);
00790                 }
00791 
00792                 *tobeinserted_p = mallocedval;
00793                 break;
00794 
00795             case ECPGt_char:
00796             case ECPGt_unsigned_char:
00797             case ECPGt_string:
00798                 {
00799                     /* set slen to string length if type is char * */
00800                     int         slen = (var->varcharsize == 0) ? strlen((char *) var->value) : (unsigned int) var->varcharsize;
00801 
00802                     if (!(newcopy = ecpg_alloc(slen + 1, lineno)))
00803                         return false;
00804 
00805                     strncpy(newcopy, (char *) var->value, slen);
00806                     newcopy[slen] = '\0';
00807 
00808                     mallocedval = quote_postgres(newcopy, quote, lineno);
00809                     if (!mallocedval)
00810                         return false;
00811 
00812                     *tobeinserted_p = mallocedval;
00813                 }
00814                 break;
00815             case ECPGt_const:
00816             case ECPGt_char_variable:
00817                 {
00818                     int         slen = strlen((char *) var->value);
00819 
00820                     if (!(mallocedval = ecpg_alloc(slen + 1, lineno)))
00821                         return false;
00822 
00823                     strncpy(mallocedval, (char *) var->value, slen);
00824                     mallocedval[slen] = '\0';
00825 
00826                     *tobeinserted_p = mallocedval;
00827                 }
00828                 break;
00829             case ECPGt_varchar:
00830                 {
00831                     struct ECPGgeneric_varchar *variable =
00832                     (struct ECPGgeneric_varchar *) (var->value);
00833 
00834                     if (!(newcopy = (char *) ecpg_alloc(variable->len + 1, lineno)))
00835                         return false;
00836 
00837                     strncpy(newcopy, variable->arr, variable->len);
00838                     newcopy[variable->len] = '\0';
00839 
00840                     mallocedval = quote_postgres(newcopy, quote, lineno);
00841                     if (!mallocedval)
00842                         return false;
00843 
00844                     *tobeinserted_p = mallocedval;
00845                 }
00846                 break;
00847 
00848             case ECPGt_decimal:
00849             case ECPGt_numeric:
00850                 {
00851                     char       *str = NULL;
00852                     int         slen;
00853                     numeric    *nval;
00854 
00855                     if (var->arrsize > 1)
00856                     {
00857                         if (!(mallocedval = ecpg_strdup("array [", lineno)))
00858                             return false;
00859 
00860                         for (element = 0; element < var->arrsize; element++)
00861                         {
00862                             nval = PGTYPESnumeric_new();
00863                             if (!nval)
00864                                 return false;
00865 
00866                             if (var->type == ECPGt_numeric)
00867                                 PGTYPESnumeric_copy((numeric *) ((var + var->offset * element)->value), nval);
00868                             else
00869                                 PGTYPESnumeric_from_decimal((decimal *) ((var + var->offset * element)->value), nval);
00870 
00871                             str = PGTYPESnumeric_to_asc(nval, nval->dscale);
00872                             slen = strlen(str);
00873                             PGTYPESnumeric_free(nval);
00874 
00875                             if (!(mallocedval = ecpg_realloc(mallocedval, strlen(mallocedval) + slen + 2, lineno)))
00876                             {
00877                                 ecpg_free(str);
00878                                 return false;
00879                             }
00880 
00881                             strncpy(mallocedval + strlen(mallocedval), str, slen + 1);
00882                             strcpy(mallocedval + strlen(mallocedval), ",");
00883                             ecpg_free(str);
00884                         }
00885                         strcpy(mallocedval + strlen(mallocedval) - 1, "]");
00886                     }
00887                     else
00888                     {
00889                         nval = PGTYPESnumeric_new();
00890                         if (!nval)
00891                             return false;
00892 
00893                         if (var->type == ECPGt_numeric)
00894                             PGTYPESnumeric_copy((numeric *) (var->value), nval);
00895                         else
00896                             PGTYPESnumeric_from_decimal((decimal *) (var->value), nval);
00897 
00898                         str = PGTYPESnumeric_to_asc(nval, nval->dscale);
00899                         slen = strlen(str);
00900                         PGTYPESnumeric_free(nval);
00901 
00902                         if (!(mallocedval = ecpg_alloc(slen + 1, lineno)))
00903                         {
00904                             free(str);
00905                             return false;
00906                         }
00907 
00908                         strncpy(mallocedval, str, slen);
00909                         mallocedval[slen] = '\0';
00910                         ecpg_free(str);
00911                     }
00912 
00913                     *tobeinserted_p = mallocedval;
00914                 }
00915                 break;
00916 
00917             case ECPGt_interval:
00918                 {
00919                     char       *str = NULL;
00920                     int         slen;
00921 
00922                     if (var->arrsize > 1)
00923                     {
00924                         if (!(mallocedval = ecpg_strdup("array [", lineno)))
00925                             return false;
00926 
00927                         for (element = 0; element < var->arrsize; element++)
00928                         {
00929                             str = quote_postgres(PGTYPESinterval_to_asc((interval *) ((var + var->offset * element)->value)), quote, lineno);
00930                             if (!str)
00931                                 return false;
00932                             slen = strlen(str);
00933 
00934                             if (!(mallocedval = ecpg_realloc(mallocedval, strlen(mallocedval) + slen + 2, lineno)))
00935                             {
00936                                 ecpg_free(str);
00937                                 return false;
00938                             }
00939 
00940                             strncpy(mallocedval + strlen(mallocedval), str, slen + 1);
00941                             strcpy(mallocedval + strlen(mallocedval), ",");
00942                             ecpg_free(str);
00943                         }
00944                         strcpy(mallocedval + strlen(mallocedval) - 1, "]");
00945                     }
00946                     else
00947                     {
00948                         str = quote_postgres(PGTYPESinterval_to_asc((interval *) (var->value)), quote, lineno);
00949                         if (!str)
00950                             return false;
00951                         slen = strlen(str);
00952 
00953                         if (!(mallocedval = ecpg_alloc(slen + sizeof("interval ") + 1, lineno)))
00954                         {
00955                             ecpg_free(str);
00956                             return false;
00957                         }
00958 
00959                         /* also copy trailing '\0' */
00960                         strncpy(mallocedval + strlen(mallocedval), str, slen + 1);
00961                         ecpg_free(str);
00962                     }
00963 
00964                     *tobeinserted_p = mallocedval;
00965                 }
00966                 break;
00967 
00968             case ECPGt_date:
00969                 {
00970                     char       *str = NULL;
00971                     int         slen;
00972 
00973                     if (var->arrsize > 1)
00974                     {
00975                         if (!(mallocedval = ecpg_strdup("array [", lineno)))
00976                             return false;
00977 
00978                         for (element = 0; element < var->arrsize; element++)
00979                         {
00980                             str = quote_postgres(PGTYPESdate_to_asc(*(date *) ((var + var->offset * element)->value)), quote, lineno);
00981                             if (!str)
00982                                 return false;
00983                             slen = strlen(str);
00984 
00985                             if (!(mallocedval = ecpg_realloc(mallocedval, strlen(mallocedval) + slen + 2, lineno)))
00986                             {
00987                                 ecpg_free(str);
00988                                 return false;
00989                             }
00990 
00991                             strncpy(mallocedval + strlen(mallocedval), str, slen + 1);
00992                             strcpy(mallocedval + strlen(mallocedval), ",");
00993                             ecpg_free(str);
00994                         }
00995                         strcpy(mallocedval + strlen(mallocedval) - 1, "]");
00996                     }
00997                     else
00998                     {
00999                         str = quote_postgres(PGTYPESdate_to_asc(*(date *) (var->value)), quote, lineno);
01000                         if (!str)
01001                             return false;
01002                         slen = strlen(str);
01003 
01004                         if (!(mallocedval = ecpg_alloc(slen + sizeof("date ") + 1, lineno)))
01005                         {
01006                             ecpg_free(str);
01007                             return false;
01008                         }
01009 
01010                         /* also copy trailing '\0' */
01011                         strncpy(mallocedval + strlen(mallocedval), str, slen + 1);
01012                         ecpg_free(str);
01013                     }
01014 
01015                     *tobeinserted_p = mallocedval;
01016                 }
01017                 break;
01018 
01019             case ECPGt_timestamp:
01020                 {
01021                     char       *str = NULL;
01022                     int         slen;
01023 
01024                     if (var->arrsize > 1)
01025                     {
01026                         if (!(mallocedval = ecpg_strdup("array [", lineno)))
01027                             return false;
01028 
01029                         for (element = 0; element < var->arrsize; element++)
01030                         {
01031                             str = quote_postgres(PGTYPEStimestamp_to_asc(*(timestamp *) ((var + var->offset * element)->value)), quote, lineno);
01032                             if (!str)
01033                                 return false;
01034 
01035                             slen = strlen(str);
01036 
01037                             if (!(mallocedval = ecpg_realloc(mallocedval, strlen(mallocedval) + slen + 2, lineno)))
01038                             {
01039                                 ecpg_free(str);
01040                                 return false;
01041                             }
01042 
01043                             strncpy(mallocedval + strlen(mallocedval), str, slen + 1);
01044                             strcpy(mallocedval + strlen(mallocedval), ",");
01045                             ecpg_free(str);
01046                         }
01047                         strcpy(mallocedval + strlen(mallocedval) - 1, "]");
01048                     }
01049                     else
01050                     {
01051                         str = quote_postgres(PGTYPEStimestamp_to_asc(*(timestamp *) (var->value)), quote, lineno);
01052                         if (!str)
01053                             return false;
01054                         slen = strlen(str);
01055 
01056                         if (!(mallocedval = ecpg_alloc(slen + sizeof("timestamp") + 1, lineno)))
01057                         {
01058                             ecpg_free(str);
01059                             return false;
01060                         }
01061 
01062                         /* also copy trailing '\0' */
01063                         strncpy(mallocedval + strlen(mallocedval), str, slen + 1);
01064                         ecpg_free(str);
01065                     }
01066 
01067                     *tobeinserted_p = mallocedval;
01068                 }
01069                 break;
01070 
01071             case ECPGt_descriptor:
01072             case ECPGt_sqlda:
01073                 break;
01074 
01075             default:
01076                 /* Not implemented yet */
01077                 ecpg_raise(lineno, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, ecpg_type_name(var->type));
01078                 return false;
01079                 break;
01080         }
01081     }
01082     return true;
01083 }
01084 
01085 static void
01086 free_params(char **paramValues, int nParams, bool print, int lineno)
01087 {
01088     int         n;
01089 
01090     for (n = 0; n < nParams; n++)
01091     {
01092         if (print)
01093             ecpg_log("free_params on line %d: parameter %d = %s\n", lineno, n + 1, paramValues[n] ? paramValues[n] : "null");
01094         ecpg_free(paramValues[n]);
01095     }
01096     ecpg_free(paramValues);
01097 }
01098 
01099 
01100 static bool
01101 insert_tobeinserted(int position, int ph_len, struct statement * stmt, char *tobeinserted)
01102 {
01103     char       *newcopy;
01104 
01105     if (!(newcopy = (char *) ecpg_alloc(strlen(stmt->command)
01106                                         + strlen(tobeinserted)
01107                                         + 1, stmt->lineno)))
01108     {
01109         ecpg_free(tobeinserted);
01110         return false;
01111     }
01112 
01113     strcpy(newcopy, stmt->command);
01114     strcpy(newcopy + position - 1, tobeinserted);
01115 
01116     /*
01117      * The strange thing in the second argument is the rest of the string from
01118      * the old string
01119      */
01120     strcat(newcopy,
01121            stmt->command
01122            + position
01123            + ph_len - 1);
01124 
01125     ecpg_free(stmt->command);
01126     stmt->command = newcopy;
01127 
01128     ecpg_free((char *) tobeinserted);
01129     return true;
01130 }
01131 
01132 static bool
01133 ecpg_execute(struct statement * stmt)
01134 {
01135     bool        status = false;
01136     char       *cmdstat;
01137     PGresult   *results;
01138     PGnotify   *notify;
01139     struct variable *var;
01140     int         desc_counter = 0;
01141     char      **paramValues = NULL;
01142     int         nParams = 0;
01143     int         position = 0;
01144     struct sqlca_t *sqlca = ECPGget_sqlca();
01145     bool        clear_result = true;
01146 
01147     /*
01148      * If the type is one of the fill in types then we take the argument and
01149      * enter it to our parameter array at the first position. Then if there
01150      * are any more fill in types we add more parameters.
01151      */
01152     var = stmt->inlist;
01153     while (var)
01154     {
01155         char       *tobeinserted;
01156         int         counter = 1;
01157 
01158         tobeinserted = NULL;
01159 
01160         /*
01161          * A descriptor is a special case since it contains many variables but
01162          * is listed only once.
01163          */
01164         if (var->type == ECPGt_descriptor)
01165         {
01166             /*
01167              * We create an additional variable list here, so the same logic
01168              * applies.
01169              */
01170             struct variable desc_inlist;
01171             struct descriptor *desc;
01172             struct descriptor_item *desc_item;
01173 
01174             desc = ecpg_find_desc(stmt->lineno, var->pointer);
01175             if (desc == NULL)
01176                 return false;
01177 
01178             desc_counter++;
01179             for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
01180             {
01181                 if (desc_item->num == desc_counter)
01182                 {
01183                     desc_inlist.type = ECPGt_char;
01184                     desc_inlist.value = desc_item->data;
01185                     desc_inlist.pointer = &(desc_item->data);
01186                     desc_inlist.varcharsize = strlen(desc_item->data);
01187                     desc_inlist.arrsize = 1;
01188                     desc_inlist.offset = 0;
01189                     if (!desc_item->indicator)
01190                     {
01191                         desc_inlist.ind_type = ECPGt_NO_INDICATOR;
01192                         desc_inlist.ind_value = desc_inlist.ind_pointer = NULL;
01193                         desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = desc_inlist.ind_offset = 0;
01194                     }
01195                     else
01196                     {
01197                         desc_inlist.ind_type = ECPGt_int;
01198                         desc_inlist.ind_value = &(desc_item->indicator);
01199                         desc_inlist.ind_pointer = &(desc_inlist.ind_value);
01200                         desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = 1;
01201                         desc_inlist.ind_offset = 0;
01202                     }
01203                     if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, &desc_inlist, &tobeinserted, false))
01204                         return false;
01205 
01206                     break;
01207                 }
01208             }
01209             if (desc->count == desc_counter)
01210                 desc_counter = 0;
01211         }
01212         else if (var->type == ECPGt_sqlda)
01213         {
01214             if (INFORMIX_MODE(stmt->compat))
01215             {
01216                 struct sqlda_compat *sqlda = *(struct sqlda_compat **) var->pointer;
01217                 struct variable desc_inlist;
01218                 int         i;
01219 
01220                 if (sqlda == NULL)
01221                     return false;
01222 
01223                 desc_counter++;
01224                 for (i = 0; i < sqlda->sqld; i++)
01225                 {
01226                     if (i + 1 == desc_counter)
01227                     {
01228                         desc_inlist.type = sqlda->sqlvar[i].sqltype;
01229                         desc_inlist.value = sqlda->sqlvar[i].sqldata;
01230                         desc_inlist.pointer = &(sqlda->sqlvar[i].sqldata);
01231                         switch (desc_inlist.type)
01232                         {
01233                             case ECPGt_char:
01234                             case ECPGt_varchar:
01235                                 desc_inlist.varcharsize = strlen(sqlda->sqlvar[i].sqldata);
01236                                 break;
01237                             default:
01238                                 desc_inlist.varcharsize = 0;
01239                                 break;
01240                         }
01241                         desc_inlist.arrsize = 1;
01242                         desc_inlist.offset = 0;
01243                         if (sqlda->sqlvar[i].sqlind)
01244                         {
01245                             desc_inlist.ind_type = ECPGt_short;
01246                             /* ECPG expects indicator value < 0 */
01247                             if (*(sqlda->sqlvar[i].sqlind))
01248                                 *(sqlda->sqlvar[i].sqlind) = -1;
01249                             desc_inlist.ind_value = sqlda->sqlvar[i].sqlind;
01250                             desc_inlist.ind_pointer = &(sqlda->sqlvar[i].sqlind);
01251                             desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = 1;
01252                             desc_inlist.ind_offset = 0;
01253                         }
01254                         else
01255                         {
01256                             desc_inlist.ind_type = ECPGt_NO_INDICATOR;
01257                             desc_inlist.ind_value = desc_inlist.ind_pointer = NULL;
01258                             desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = desc_inlist.ind_offset = 0;
01259                         }
01260                         if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, &desc_inlist, &tobeinserted, false))
01261                             return false;
01262 
01263                         break;
01264                     }
01265                 }
01266                 if (sqlda->sqld == desc_counter)
01267                     desc_counter = 0;
01268             }
01269             else
01270             {
01271                 struct sqlda_struct *sqlda = *(struct sqlda_struct **) var->pointer;
01272                 struct variable desc_inlist;
01273                 int         i;
01274 
01275                 if (sqlda == NULL)
01276                     return false;
01277 
01278                 desc_counter++;
01279                 for (i = 0; i < sqlda->sqln; i++)
01280                 {
01281                     if (i + 1 == desc_counter)
01282                     {
01283                         desc_inlist.type = sqlda->sqlvar[i].sqltype;
01284                         desc_inlist.value = sqlda->sqlvar[i].sqldata;
01285                         desc_inlist.pointer = &(sqlda->sqlvar[i].sqldata);
01286                         switch (desc_inlist.type)
01287                         {
01288                             case ECPGt_char:
01289                             case ECPGt_varchar:
01290                                 desc_inlist.varcharsize = strlen(sqlda->sqlvar[i].sqldata);
01291                                 break;
01292                             default:
01293                                 desc_inlist.varcharsize = 0;
01294                                 break;
01295                         }
01296                         desc_inlist.arrsize = 1;
01297                         desc_inlist.offset = 0;
01298                         if (sqlda->sqlvar[i].sqlind)
01299                         {
01300                             desc_inlist.ind_type = ECPGt_short;
01301                             /* ECPG expects indicator value < 0 */
01302                             if (*(sqlda->sqlvar[i].sqlind))
01303                                 *(sqlda->sqlvar[i].sqlind) = -1;
01304                             desc_inlist.ind_value = sqlda->sqlvar[i].sqlind;
01305                             desc_inlist.ind_pointer = &(sqlda->sqlvar[i].sqlind);
01306                             desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = 1;
01307                             desc_inlist.ind_offset = 0;
01308                         }
01309                         else
01310                         {
01311                             desc_inlist.ind_type = ECPGt_NO_INDICATOR;
01312                             desc_inlist.ind_value = desc_inlist.ind_pointer = NULL;
01313                             desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = desc_inlist.ind_offset = 0;
01314                         }
01315                         if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, &desc_inlist, &tobeinserted, false))
01316                             return false;
01317 
01318                         break;
01319                     }
01320                 }
01321                 if (sqlda->sqln == desc_counter)
01322                     desc_counter = 0;
01323             }
01324 
01325         }
01326         else
01327         {
01328             if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, var, &tobeinserted, false))
01329                 return false;
01330         }
01331 
01332         /*
01333          * now tobeinserted points to an area that contains the next parameter
01334          * now find the positin in the string where it belongs
01335          */
01336         if ((position = next_insert(stmt->command, position, stmt->questionmarks) + 1) == 0)
01337         {
01338             /*
01339              * We have an argument but we dont have the matched up placeholder
01340              * in the string
01341              */
01342             ecpg_raise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS,
01343                        ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS,
01344                        NULL);
01345             free_params(paramValues, nParams, false, stmt->lineno);
01346             return false;
01347         }
01348 
01349         /*
01350          * if var->type=ECPGt_char_variable we have a dynamic cursor we have
01351          * to simulate a dynamic cursor because there is no backend
01352          * functionality for it
01353          */
01354         if (var->type == ECPGt_char_variable)
01355         {
01356             int         ph_len = (stmt->command[position] == '?') ? strlen("?") : strlen("$1");
01357 
01358             if (!insert_tobeinserted(position, ph_len, stmt, tobeinserted))
01359             {
01360                 free_params(paramValues, nParams, false, stmt->lineno);
01361                 return false;
01362             }
01363             tobeinserted = NULL;
01364         }
01365 
01366         /*
01367          * if the placeholder is '$0' we have to replace it on the client side
01368          * this is for places we want to support variables at that are not
01369          * supported in the backend
01370          */
01371         else if (stmt->command[position] == '0')
01372         {
01373             if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
01374             {
01375                 free_params(paramValues, nParams, false, stmt->lineno);
01376                 return false;
01377             }
01378             tobeinserted = NULL;
01379         }
01380         else
01381         {
01382             nParams++;
01383             if (!(paramValues = (char **) ecpg_realloc(paramValues, sizeof(char *) * nParams, stmt->lineno)))
01384             {
01385                 ecpg_free(paramValues);
01386                 return false;
01387             }
01388 
01389             paramValues[nParams - 1] = tobeinserted;
01390 
01391             /* let's see if this was an old style placeholder */
01392             if (stmt->command[position] == '?')
01393             {
01394                 /* yes, replace with new style */
01395                 int         buffersize = sizeof(int) * CHAR_BIT * 10 / 3;       /* a rough guess of the
01396                                                                                  * size we need */
01397 
01398                 if (!(tobeinserted = (char *) ecpg_alloc(buffersize, stmt->lineno)))
01399                 {
01400                     free_params(paramValues, nParams, false, stmt->lineno);
01401                     return false;
01402                 }
01403 
01404                 snprintf(tobeinserted, buffersize, "$%d", counter++);
01405 
01406                 if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
01407                 {
01408                     free_params(paramValues, nParams, false, stmt->lineno);
01409                     return false;
01410                 }
01411                 tobeinserted = NULL;
01412             }
01413         }
01414 
01415         if (desc_counter == 0)
01416             var = var->next;
01417     }
01418 
01419     /* Check if there are unmatched things left. */
01420     if (next_insert(stmt->command, position, stmt->questionmarks) >= 0)
01421     {
01422         ecpg_raise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS,
01423                  ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL);
01424         free_params(paramValues, nParams, false, stmt->lineno);
01425         return false;
01426     }
01427 
01428     /* The request has been build. */
01429 
01430     if (PQtransactionStatus(stmt->connection->connection) == PQTRANS_IDLE && !stmt->connection->autocommit)
01431     {
01432         results = PQexec(stmt->connection->connection, "begin transaction");
01433         if (!ecpg_check_PQresult(results, stmt->lineno, stmt->connection->connection, stmt->compat))
01434         {
01435             free_params(paramValues, nParams, false, stmt->lineno);
01436             return false;
01437         }
01438         PQclear(results);
01439     }
01440 
01441     ecpg_log("ecpg_execute on line %d: query: %s; with %d parameter(s) on connection %s\n", stmt->lineno, stmt->command, nParams, stmt->connection->name);
01442     if (stmt->statement_type == ECPGst_execute)
01443     {
01444         results = PQexecPrepared(stmt->connection->connection, stmt->name, nParams, (const char *const *) paramValues, NULL, NULL, 0);
01445         ecpg_log("ecpg_execute on line %d: using PQexecPrepared for \"%s\"\n", stmt->lineno, stmt->command);
01446     }
01447     else
01448     {
01449         if (nParams == 0)
01450         {
01451             results = PQexec(stmt->connection->connection, stmt->command);
01452             ecpg_log("ecpg_execute on line %d: using PQexec\n", stmt->lineno);
01453         }
01454         else
01455         {
01456             results = PQexecParams(stmt->connection->connection, stmt->command, nParams, NULL, (const char *const *) paramValues, NULL, NULL, 0);
01457             ecpg_log("ecpg_execute on line %d: using PQexecParams\n", stmt->lineno);
01458         }
01459     }
01460 
01461     free_params(paramValues, nParams, true, stmt->lineno);
01462 
01463     if (!ecpg_check_PQresult(results, stmt->lineno, stmt->connection->connection, stmt->compat))
01464         return (false);
01465 
01466     var = stmt->outlist;
01467     switch (PQresultStatus(results))
01468     {
01469             int         nfields,
01470                         ntuples,
01471                         act_field;
01472 
01473         case PGRES_TUPLES_OK:
01474             nfields = PQnfields(results);
01475             sqlca->sqlerrd[2] = ntuples = PQntuples(results);
01476             ecpg_log("ecpg_execute on line %d: correctly got %d tuples with %d fields\n", stmt->lineno, ntuples, nfields);
01477             status = true;
01478 
01479             if (ntuples < 1)
01480             {
01481                 if (ntuples)
01482                     ecpg_log("ecpg_execute on line %d: incorrect number of matches (%d)\n",
01483                              stmt->lineno, ntuples);
01484                 ecpg_raise(stmt->lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
01485                 status = false;
01486                 break;
01487             }
01488 
01489             if (var != NULL && var->type == ECPGt_descriptor)
01490             {
01491                 struct descriptor *desc = ecpg_find_desc(stmt->lineno, var->pointer);
01492 
01493                 if (desc == NULL)
01494                     status = false;
01495                 else
01496                 {
01497                     if (desc->result)
01498                         PQclear(desc->result);
01499                     desc->result = results;
01500                     clear_result = false;
01501                     ecpg_log("ecpg_execute on line %d: putting result (%d tuples) into descriptor %s\n",
01502                              stmt->lineno, PQntuples(results), (const char *) var->pointer);
01503                 }
01504                 var = var->next;
01505             }
01506             else if (var != NULL && var->type == ECPGt_sqlda)
01507             {
01508                 if (INFORMIX_MODE(stmt->compat))
01509                 {
01510                     struct sqlda_compat **_sqlda = (struct sqlda_compat **) var->pointer;
01511                     struct sqlda_compat *sqlda = *_sqlda;
01512                     struct sqlda_compat *sqlda_new;
01513                     int         i;
01514 
01515                     /*
01516                      * If we are passed in a previously existing sqlda (chain)
01517                      * then free it.
01518                      */
01519                     while (sqlda)
01520                     {
01521                         sqlda_new = sqlda->desc_next;
01522                         free(sqlda);
01523                         sqlda = sqlda_new;
01524                     }
01525                     *_sqlda = sqlda = sqlda_new = NULL;
01526                     for (i = ntuples - 1; i >= 0; i--)
01527                     {
01528                         /*
01529                          * Build a new sqlda structure. Note that only
01530                          * fetching 1 record is supported
01531                          */
01532                         sqlda_new = ecpg_build_compat_sqlda(stmt->lineno, results, i, stmt->compat);
01533 
01534                         if (!sqlda_new)
01535                         {
01536                             /* cleanup all SQLDAs we created up */
01537                             while (sqlda)
01538                             {
01539                                 sqlda_new = sqlda->desc_next;
01540                                 free(sqlda);
01541                                 sqlda = sqlda_new;
01542                             }
01543                             *_sqlda = NULL;
01544 
01545                             ecpg_log("ecpg_execute on line %d: out of memory allocating a new sqlda\n", stmt->lineno);
01546                             status = false;
01547                             break;
01548                         }
01549                         else
01550                         {
01551                             ecpg_log("ecpg_execute on line %d: new sqlda was built\n", stmt->lineno);
01552 
01553                             *_sqlda = sqlda_new;
01554 
01555                             ecpg_set_compat_sqlda(stmt->lineno, _sqlda, results, i, stmt->compat);
01556                             ecpg_log("ecpg_execute on line %d: putting result (1 tuple %d fields) into sqlda descriptor\n",
01557                                      stmt->lineno, PQnfields(results));
01558 
01559                             sqlda_new->desc_next = sqlda;
01560                             sqlda = sqlda_new;
01561                         }
01562                     }
01563                 }
01564                 else
01565                 {
01566                     struct sqlda_struct **_sqlda = (struct sqlda_struct **) var->pointer;
01567                     struct sqlda_struct *sqlda = *_sqlda;
01568                     struct sqlda_struct *sqlda_new;
01569                     int         i;
01570 
01571                     /*
01572                      * If we are passed in a previously existing sqlda (chain)
01573                      * then free it.
01574                      */
01575                     while (sqlda)
01576                     {
01577                         sqlda_new = sqlda->desc_next;
01578                         free(sqlda);
01579                         sqlda = sqlda_new;
01580                     }
01581                     *_sqlda = sqlda = sqlda_new = NULL;
01582                     for (i = ntuples - 1; i >= 0; i--)
01583                     {
01584                         /*
01585                          * Build a new sqlda structure. Note that only
01586                          * fetching 1 record is supported
01587                          */
01588                         sqlda_new = ecpg_build_native_sqlda(stmt->lineno, results, i, stmt->compat);
01589 
01590                         if (!sqlda_new)
01591                         {
01592                             /* cleanup all SQLDAs we created up */
01593                             while (sqlda)
01594                             {
01595                                 sqlda_new = sqlda->desc_next;
01596                                 free(sqlda);
01597                                 sqlda = sqlda_new;
01598                             }
01599                             *_sqlda = NULL;
01600 
01601                             ecpg_log("ecpg_execute on line %d: out of memory allocating a new sqlda\n", stmt->lineno);
01602                             status = false;
01603                             break;
01604                         }
01605                         else
01606                         {
01607                             ecpg_log("ecpg_execute on line %d: new sqlda was built\n", stmt->lineno);
01608 
01609                             *_sqlda = sqlda_new;
01610 
01611                             ecpg_set_native_sqlda(stmt->lineno, _sqlda, results, i, stmt->compat);
01612                             ecpg_log("ecpg_execute on line %d: putting result (1 tuple %d fields) into sqlda descriptor\n",
01613                                      stmt->lineno, PQnfields(results));
01614 
01615                             sqlda_new->desc_next = sqlda;
01616                             sqlda = sqlda_new;
01617                         }
01618                     }
01619                 }
01620 
01621                 var = var->next;
01622             }
01623             else
01624                 for (act_field = 0; act_field < nfields && status; act_field++)
01625                 {
01626                     if (var != NULL)
01627                     {
01628                         status = ecpg_store_result(results, act_field, stmt, var);
01629                         var = var->next;
01630                     }
01631                     else if (!INFORMIX_MODE(stmt->compat))
01632                     {
01633                         ecpg_raise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_TARGETS, NULL);
01634                         return (false);
01635                     }
01636                 }
01637 
01638             if (status && var != NULL)
01639             {
01640                 ecpg_raise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_TARGETS, NULL);
01641                 status = false;
01642             }
01643 
01644             break;
01645         case PGRES_COMMAND_OK:
01646             status = true;
01647             cmdstat = PQcmdStatus(results);
01648             sqlca->sqlerrd[1] = PQoidValue(results);
01649             sqlca->sqlerrd[2] = atol(PQcmdTuples(results));
01650             ecpg_log("ecpg_execute on line %d: OK: %s\n", stmt->lineno, cmdstat);
01651             if (stmt->compat != ECPG_COMPAT_INFORMIX_SE &&
01652                 !sqlca->sqlerrd[2] &&
01653                 (strncmp(cmdstat, "UPDATE", 6) == 0
01654                  || strncmp(cmdstat, "INSERT", 6) == 0
01655                  || strncmp(cmdstat, "DELETE", 6) == 0))
01656                 ecpg_raise(stmt->lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
01657             break;
01658         case PGRES_COPY_OUT:
01659             {
01660                 char       *buffer;
01661                 int         res;
01662 
01663                 ecpg_log("ecpg_execute on line %d: COPY OUT data transfer in progress\n", stmt->lineno);
01664                 while ((res = PQgetCopyData(stmt->connection->connection,
01665                                             &buffer, 0)) > 0)
01666                 {
01667                     printf("%s", buffer);
01668                     PQfreemem(buffer);
01669                 }
01670                 if (res == -1)
01671                 {
01672                     /* COPY done */
01673                     PQclear(results);
01674                     results = PQgetResult(stmt->connection->connection);
01675                     if (PQresultStatus(results) == PGRES_COMMAND_OK)
01676                         ecpg_log("ecpg_execute on line %d: got PGRES_COMMAND_OK after PGRES_COPY_OUT\n", stmt->lineno);
01677                     else
01678                         ecpg_log("ecpg_execute on line %d: got error after PGRES_COPY_OUT: %s", stmt->lineno, PQresultErrorMessage(results));
01679                 }
01680                 break;
01681             }
01682         default:
01683 
01684             /*
01685              * execution should never reach this code because it is already
01686              * handled in ECPGcheck_PQresult()
01687              */
01688             ecpg_log("ecpg_execute on line %d: unknown execution status type\n",
01689                      stmt->lineno);
01690             ecpg_raise_backend(stmt->lineno, results, stmt->connection->connection, stmt->compat);
01691             status = false;
01692             break;
01693     }
01694     if (clear_result)
01695         PQclear(results);
01696 
01697     /* check for asynchronous returns */
01698     notify = PQnotifies(stmt->connection->connection);
01699     if (notify)
01700     {
01701         ecpg_log("ecpg_execute on line %d: asynchronous notification of \"%s\" from backend PID %d received\n",
01702                  stmt->lineno, notify->relname, notify->be_pid);
01703         PQfreemem(notify);
01704     }
01705 
01706     return status;
01707 }
01708 
01709 bool
01710 ECPGdo(const int lineno, const int compat, const int force_indicator, const char *connection_name, const bool questionmarks, const int st, const char *query,...)
01711 {
01712     va_list     args;
01713     struct statement *stmt;
01714     struct connection *con;
01715     bool        status;
01716     char       *oldlocale;
01717     enum ECPGttype type;
01718     struct variable **list;
01719     enum ECPG_statement_type statement_type = (enum ECPG_statement_type) st;
01720     char       *prepname;
01721 
01722     if (!query)
01723     {
01724         ecpg_raise(lineno, ECPG_EMPTY, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, NULL);
01725         return (false);
01726     }
01727 
01728     /* Make sure we do NOT honor the locale for numeric input/output */
01729     /* since the database wants the standard decimal point */
01730     oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno);
01731     setlocale(LC_NUMERIC, "C");
01732 
01733 #ifdef ENABLE_THREAD_SAFETY
01734     ecpg_pthreads_init();
01735 #endif
01736 
01737     con = ecpg_get_connection(connection_name);
01738 
01739     if (!ecpg_init(con, connection_name, lineno))
01740     {
01741         setlocale(LC_NUMERIC, oldlocale);
01742         ecpg_free(oldlocale);
01743         return (false);
01744     }
01745 
01746     /* construct statement in our own structure */
01747     va_start(args, query);
01748 
01749     /*
01750      * create a list of variables The variables are listed with input
01751      * variables preceding outputvariables The end of each group is marked by
01752      * an end marker. per variable we list: type - as defined in ecpgtype.h
01753      * value - where to store the data varcharsize - length of string in case
01754      * we have a stringvariable, else 0 arraysize - 0 for pointer (we don't
01755      * know the size of the array), 1 for simple variable, size for arrays
01756      * offset - offset between ith and (i+1)th entry in an array, normally
01757      * that means sizeof(type) ind_type - type of indicator variable ind_value
01758      * - pointer to indicator variable ind_varcharsize - empty ind_arraysize -
01759      * arraysize of indicator array ind_offset - indicator offset
01760      */
01761     if (!(stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno)))
01762     {
01763         setlocale(LC_NUMERIC, oldlocale);
01764         ecpg_free(oldlocale);
01765         va_end(args);
01766         return false;
01767     }
01768 
01769     /*
01770      * If statement type is ECPGst_prepnormal we are supposed to prepare the
01771      * statement before executing them
01772      */
01773     if (statement_type == ECPGst_prepnormal)
01774     {
01775         if (!ecpg_auto_prepare(lineno, connection_name, compat, &prepname, query))
01776         {
01777             setlocale(LC_NUMERIC, oldlocale);
01778             ecpg_free(oldlocale);
01779             free_statement(stmt);
01780             va_end(args);
01781             return (false);
01782         }
01783 
01784         /*
01785          * statement is now prepared, so instead of the query we have to
01786          * execute the name
01787          */
01788         stmt->command = prepname;
01789         statement_type = ECPGst_execute;
01790     }
01791     else
01792         stmt->command = ecpg_strdup(query, lineno);
01793 
01794     stmt->name = NULL;
01795 
01796     if (statement_type == ECPGst_execute)
01797     {
01798         /* if we have an EXECUTE command, only the name is send */
01799         char       *command = ecpg_prepared(stmt->command, con);
01800 
01801         if (command)
01802         {
01803             stmt->name = stmt->command;
01804             stmt->command = ecpg_strdup(command, lineno);
01805         }
01806         else
01807         {
01808             ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt->command);
01809             setlocale(LC_NUMERIC, oldlocale);
01810             ecpg_free(oldlocale);
01811             free_statement(stmt);
01812             va_end(args);
01813             return (false);
01814         }
01815     }
01816 
01817     stmt->connection = con;
01818     stmt->lineno = lineno;
01819     stmt->compat = compat;
01820     stmt->force_indicator = force_indicator;
01821     stmt->questionmarks = questionmarks;
01822     stmt->statement_type = statement_type;
01823 
01824     list = &(stmt->inlist);
01825 
01826     type = va_arg(args, enum ECPGttype);
01827 
01828     while (type != ECPGt_EORT)
01829     {
01830         if (type == ECPGt_EOIT)
01831             list = &(stmt->outlist);
01832         else
01833         {
01834             struct variable *var,
01835                        *ptr;
01836 
01837             if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
01838             {
01839                 setlocale(LC_NUMERIC, oldlocale);
01840                 ecpg_free(oldlocale);
01841                 free_statement(stmt);
01842                 va_end(args);
01843                 return false;
01844             }
01845 
01846             var->type = type;
01847             var->pointer = va_arg(args, char *);
01848 
01849             var->varcharsize = va_arg(args, long);
01850             var->arrsize = va_arg(args, long);
01851             var->offset = va_arg(args, long);
01852 
01853             if (var->arrsize == 0 || var->varcharsize == 0)
01854                 var->value = *((char **) (var->pointer));
01855             else
01856                 var->value = var->pointer;
01857 
01858             /*
01859              * negative values are used to indicate an array without given
01860              * bounds
01861              */
01862             /* reset to zero for us */
01863             if (var->arrsize < 0)
01864                 var->arrsize = 0;
01865             if (var->varcharsize < 0)
01866                 var->varcharsize = 0;
01867 
01868             var->next = NULL;
01869 
01870             var->ind_type = va_arg(args, enum ECPGttype);
01871             var->ind_pointer = va_arg(args, char *);
01872             var->ind_varcharsize = va_arg(args, long);
01873             var->ind_arrsize = va_arg(args, long);
01874             var->ind_offset = va_arg(args, long);
01875 
01876             if (var->ind_type != ECPGt_NO_INDICATOR
01877                 && (var->ind_arrsize == 0 || var->ind_varcharsize == 0))
01878                 var->ind_value = *((char **) (var->ind_pointer));
01879             else
01880                 var->ind_value = var->ind_pointer;
01881 
01882             /*
01883              * negative values are used to indicate an array without given
01884              * bounds
01885              */
01886             /* reset to zero for us */
01887             if (var->ind_arrsize < 0)
01888                 var->ind_arrsize = 0;
01889             if (var->ind_varcharsize < 0)
01890                 var->ind_varcharsize = 0;
01891 
01892             /* if variable is NULL, the statement hasn't been prepared */
01893             if (var->pointer == NULL)
01894             {
01895                 ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, NULL);
01896                 ecpg_free(var);
01897                 setlocale(LC_NUMERIC, oldlocale);
01898                 ecpg_free(oldlocale);
01899                 free_statement(stmt);
01900                 va_end(args);
01901                 return false;
01902             }
01903 
01904             for (ptr = *list; ptr && ptr->next; ptr = ptr->next);
01905 
01906             if (ptr == NULL)
01907                 *list = var;
01908             else
01909                 ptr->next = var;
01910         }
01911 
01912         type = va_arg(args, enum ECPGttype);
01913     }
01914 
01915     va_end(args);
01916 
01917     /* are we connected? */
01918     if (con == NULL || con->connection == NULL)
01919     {
01920         free_statement(stmt);
01921         ecpg_raise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, (con) ? con->name : ecpg_gettext("<empty>"));
01922         setlocale(LC_NUMERIC, oldlocale);
01923         ecpg_free(oldlocale);
01924         return false;
01925     }
01926 
01927     /* initialize auto_mem struct */
01928     ecpg_clear_auto_mem();
01929 
01930     status = ecpg_execute(stmt);
01931     free_statement(stmt);
01932 
01933     /* and reset locale value so our application is not affected */
01934     setlocale(LC_NUMERIC, oldlocale);
01935     ecpg_free(oldlocale);
01936 
01937     return (status);
01938 }
01939 
01940 /* old descriptor interface */
01941 bool
01942 ECPGdo_descriptor(int line, const char *connection,
01943                   const char *descriptor, const char *query)
01944 {
01945     return ECPGdo(line, ECPG_COMPAT_PGSQL, true, connection, '\0', 0, query, ECPGt_EOIT,
01946                   ECPGt_descriptor, descriptor, 0L, 0L, 0L,
01947                   ECPGt_NO_INDICATOR, NULL, 0L, 0L, 0L, ECPGt_EORT);
01948 }