📄 execute.c
字号:
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.43.2.2 2006/04/24 09:45:44 meskes Exp $ *//* * The aim is to get a simpler inteface to the database routines. * All the tidieous messing around with tuples is supposed to be hidden * by this function. *//* Author: Linus Tolke (actually most if the code is "borrowed" from the distribution and just slightly modified) *//* Taken over as part of PostgreSQL by Michael Meskes <meskes@postgresql.org> on Feb. 5th, 1998 */#define POSTGRES_ECPG_INTERNAL#include "postgres_fe.h"#include <stdio.h>#include <locale.h>#include "pg_type.h"#include "ecpgtype.h"#include "ecpglib.h"#include "ecpgerrno.h"#include "extern.h"#include "sqlca.h"#include "sql3types.h"#include "pgtypes_numeric.h"#include "pgtypes_date.h"#include "pgtypes_timestamp.h"#include "pgtypes_interval.h"/* This function returns a newly malloced string that has the \ in the argument quoted with \ and the ' quoted with ' as SQL92 says. */static char *quote_postgres(char *arg, int lineno){ char *res = (char *) ECPGalloc(2 * strlen(arg) + 3, lineno); int i, ri = 0; if (!res) return (res); if (strchr(arg, '\\') != NULL) res[ri++] = ESCAPE_STRING_SYNTAX; res[ri++] = '\''; for (i = 0; arg[i]; i++, ri++) { if (SQL_STR_DOUBLE(arg[i])) res[ri++] = arg[i]; res[ri] = arg[i]; } res[ri++] = '\''; res[ri] = '\0'; ECPGfree(arg); return res;}#if defined(__GNUC__) && (defined (__powerpc__) || defined(__amd64__) || defined(__x86_64__))#define APREF ap#else#define APREF *ap#endifvoidECPGget_variable(va_list APREF, enum ECPGttype type, struct variable * var, bool indicator){ var->type = type; var->pointer = va_arg(APREF, char *); var->varcharsize = va_arg(APREF, long); var->arrsize = va_arg(APREF, long); var->offset = va_arg(APREF, long); if (var->arrsize == 0 || var->varcharsize == 0) var->value = *((char **) (var->pointer)); else var->value = var->pointer; /* * negative values are used to indicate an array without given bounds */ /* reset to zero for us */ if (var->arrsize < 0) var->arrsize = 0; if (var->varcharsize < 0) var->varcharsize = 0; var->next = NULL; if (indicator) { var->ind_type = va_arg(APREF, enum ECPGttype); var->ind_pointer = va_arg(APREF, char *); var->ind_varcharsize = va_arg(APREF, long); var->ind_arrsize = va_arg(APREF, long); var->ind_offset = va_arg(APREF, long); if (var->ind_type != ECPGt_NO_INDICATOR && (var->ind_arrsize == 0 || var->ind_varcharsize == 0)) var->ind_value = *((char **) (var->ind_pointer)); else var->ind_value = var->ind_pointer; /* * negative values are used to indicate an array without given bounds */ /* reset to zero for us */ if (var->ind_arrsize < 0) var->ind_arrsize = 0; if (var->ind_varcharsize < 0) var->ind_varcharsize = 0; }}#undef APREF/* * create a list of variables * The variables are listed with input variables preceding outputvariables * The end of each group is marked by an end marker. * per variable we list: * type - as defined in ecpgtype.h * value - where to store the data * varcharsize - length of string in case we have a stringvariable, else 0 * arraysize - 0 for pointer (we don't know the size of the array), * 1 for simple variable, size for arrays * offset - offset between ith and (i+1)th entry in an array, * normally that means sizeof(type) * ind_type - type of indicator variable * ind_value - pointer to indicator variable * ind_varcharsize - empty * ind_arraysize - arraysize of indicator array * ind_offset - indicator offset */static boolcreate_statement(int lineno, int compat, int force_indicator, struct connection * connection, struct statement ** stmt, const char *query, va_list ap){ struct variable **list = &((*stmt)->inlist); enum ECPGttype type; if (!(*stmt = (struct statement *) ECPGalloc(sizeof(struct statement), lineno))) return false; (*stmt)->command = ECPGstrdup(query, lineno); (*stmt)->connection = connection; (*stmt)->lineno = lineno; (*stmt)->compat = compat; (*stmt)->force_indicator = force_indicator; list = &((*stmt)->inlist); type = va_arg(ap, enum ECPGttype); while (type != ECPGt_EORT) { if (type == ECPGt_EOIT) list = &((*stmt)->outlist); else { struct variable *var, *ptr; if (!(var = (struct variable *) ECPGalloc(sizeof(struct variable), lineno))) return false;#if defined(__GNUC__) && (defined (__powerpc__) || defined(__amd64__) || defined(__x86_64__)) ECPGget_variable(ap, type, var, true);#else ECPGget_variable(&ap, type, var, true);#endif /* if variable is NULL, the statement hasn't been prepared */ if (var->pointer == NULL) { ECPGraise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, NULL); ECPGfree(var); return false; } for (ptr = *list; ptr && ptr->next; ptr = ptr->next); if (ptr == NULL) *list = var; else ptr->next = var; } type = va_arg(ap, enum ECPGttype); } return (true);}static voidfree_variable(struct variable * var){ struct variable *var_next; if (var == NULL) return; var_next = var->next; ECPGfree(var); while (var_next) { var = var_next; var_next = var->next; ECPGfree(var); }}static voidfree_statement(struct statement * stmt){ if (stmt == NULL) return; free_variable(stmt->inlist); free_variable(stmt->outlist); ECPGfree(stmt->command); ECPGfree(stmt);}static char *next_insert(char *text){ char *ptr = text; bool string = false; for (; *ptr != '\0' && (*ptr != '?' || string); ptr++) { if (*ptr == '\\') /* escape character */ ptr++; else if (*ptr == '\'') string = string ? false : true; } return (*ptr == '\0') ? NULL : ptr;}static voidECPGtypeinfocache_push(struct ECPGtype_information_cache ** cache, int oid, bool isarray, int lineno){ struct ECPGtype_information_cache *new_entry = (struct ECPGtype_information_cache *) ECPGalloc(sizeof(struct ECPGtype_information_cache), lineno); new_entry->oid = oid; new_entry->isarray = isarray; new_entry->next = *cache; *cache = new_entry;}static enum ARRAY_TYPEECPGis_type_an_array(int type, const struct statement * stmt, const struct variable * var){ char *array_query; enum ARRAY_TYPE isarray = ECPG_ARRAY_NOT_SET; PGresult *query; struct ECPGtype_information_cache *cache_entry; if ((stmt->connection->cache_head) == NULL) { /* * Text like types are not an array for ecpg, but postgres counts them * as an array. This define reminds you to not 'correct' these values. */#define not_an_array_in_ecpg ECPG_ARRAY_NONE /* populate cache with well known types to speed things up */ ECPGtypeinfocache_push(&(stmt->connection->cache_head), BOOLOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), BYTEAOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), CHAROID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), NAMEOID, not_an_array_in_ecpg, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), INT8OID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), INT2OID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), INT2VECTOROID, ECPG_ARRAY_VECTOR, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), INT4OID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), REGPROCOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), TEXTOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), OIDOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), TIDOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), XIDOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), CIDOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), OIDVECTOROID, ECPG_ARRAY_VECTOR, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), POINTOID, ECPG_ARRAY_VECTOR, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), LSEGOID, ECPG_ARRAY_VECTOR, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), PATHOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), BOXOID, ECPG_ARRAY_VECTOR, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), POLYGONOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), LINEOID, ECPG_ARRAY_VECTOR, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), FLOAT4OID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), FLOAT8OID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), ABSTIMEOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), RELTIMEOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), TINTERVALOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), UNKNOWNOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), CIRCLEOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), CASHOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), INETOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), CIDROID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), BPCHAROID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), VARCHAROID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), DATEOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), TIMEOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), TIMESTAMPOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), TIMESTAMPTZOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), INTERVALOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), TIMETZOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), ZPBITOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), VARBITOID, ECPG_ARRAY_NONE, stmt->lineno); ECPGtypeinfocache_push(&(stmt->connection->cache_head), NUMERICOID, ECPG_ARRAY_NONE, stmt->lineno); } for (cache_entry = (stmt->connection->cache_head); cache_entry != NULL; cache_entry = cache_entry->next) { if (cache_entry->oid == type) return cache_entry->isarray; } array_query = (char *) ECPGalloc(strlen("select typlen from pg_type where oid= and typelem<>0") + 11, stmt->lineno); sprintf(array_query, "select typlen from pg_type where oid=%d and typelem<>0", type); query = PQexec(stmt->connection->connection, array_query); ECPGfree(array_query); if (PQresultStatus(query) == PGRES_TUPLES_OK) { if (PQntuples(query) == 0) isarray = ECPG_ARRAY_NONE; else { isarray = (atol((char *) PQgetvalue(query, 0, 0)) == -1) ? ECPG_ARRAY_ARRAY : ECPG_ARRAY_VECTOR; if (ECPGDynamicType(type) == SQL3_CHARACTER || ECPGDynamicType(type) == SQL3_CHARACTER_VARYING) { /* * arrays of character strings are not yet implemented */ isarray = ECPG_ARRAY_NONE; } } } PQclear(query); ECPGtypeinfocache_push(&(stmt->connection->cache_head), type, isarray, stmt->lineno); ECPGlog("ECPGis_type_an_array line %d: TYPE database: %d C: %d array: %s\n", stmt->lineno, type, var->type, isarray ? "Yes" : "No"); return isarray;}boolECPGstore_result(const PGresult *results, int act_field, const struct statement * stmt, struct variable * var){ enum ARRAY_TYPE isarray; int act_tuple, ntuples = PQntuples(results); bool status = true; isarray = ECPGis_type_an_array(PQftype(results, act_field), stmt, var); if (isarray == ECPG_ARRAY_NONE) { /* * if we don't have enough space, we cannot read all tuples */ if ((var->arrsize > 0 && ntuples > var->arrsize) || (var->ind_arrsize > 0 && ntuples > var->ind_arrsize)) { ECPGlog("ECPGstore_result line %d: Incorrect number of matches: %d don't fit into array of %d\n", stmt->lineno, ntuples, var->arrsize); ECPGraise(stmt->lineno, INFORMIX_MODE(stmt->compat) ? ECPG_INFORMIX_SUBSELECT_NOT_ONE : ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL); return false; } } else { /* * since we read an array, the variable has to be an array too */ if (var->arrsize == 0) { ECPGraise(stmt->lineno, ECPG_NO_ARRAY, ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL); return false; } } /* * allocate memory for NULL pointers */ if ((var->arrsize == 0 || var->varcharsize == 0) && var->value == NULL) { int len = 0; switch (var->type) { case ECPGt_char: case ECPGt_unsigned_char: if (!var->varcharsize && !var->arrsize) { /* special mode for handling char**foo=0 */ for (act_tuple = 0; act_tuple < ntuples; act_tuple++) len += strlen(PQgetvalue(results, act_tuple, act_field)) + 1; len *= var->offset; /* should be 1, but YMNK */ len += (ntuples + 1) * sizeof(char *); ECPGlog("ECPGstore_result: line %d: allocating %d bytes for %d tuples (char**=0)", stmt->lineno, len, ntuples); } else { var->varcharsize = 0; /* check strlen for each tuple */ for (act_tuple = 0; act_tuple < ntuples; act_tuple++) { int len = strlen(PQgetvalue(results, act_tuple, act_field)) + 1; if (len > var->varcharsize) var->varcharsize = len; } var->offset *= var->varcharsize; len = var->offset * ntuples; } break; case ECPGt_varchar: len = ntuples * (var->varcharsize + sizeof(int)); break; default: len = var->offset * ntuples; break; } var->value = (char *) ECPGalloc(len, stmt->lineno); *((char **) var->pointer) = var->value; ECPGadd_mem(var->value, stmt->lineno); } /* allocate indicator variable if needed */ if ((var->ind_arrsize == 0 || var->ind_varcharsize == 0) && var->ind_value == NULL && var->ind_pointer != NULL) { int len = var->ind_offset * ntuples; var->ind_value = (char *) ECPGalloc(len, stmt->lineno); *((char **) var->ind_pointer) = var->ind_value; ECPGadd_mem(var->ind_value, stmt->lineno); } /* fill the variable with the tuple(s) */ if (!var->varcharsize && !var->arrsize && (var->type == ECPGt_char || var->type == ECPGt_unsigned_char)) { /* special mode for handling char**foo=0 */ /* filling the array of (char*)s */ char **current_string = (char **) var->value; /* storing the data (after the last array element) */ char *current_data_location = (char *) ¤t_string[ntuples + 1]; for (act_tuple = 0; act_tuple < ntuples && status; act_tuple++) { int len = strlen(PQgetvalue(results, act_tuple, act_field)) + 1; if (!ECPGget_data(results, act_tuple, act_field, stmt->lineno, var->type, var->ind_type, current_data_location, var->ind_value, len, 0, var->ind_offset, isarray, stmt->compat, stmt->force_indicator)) status = false; else { *current_string = current_data_location; current_data_location += len; current_string++; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -