From: Michael Meskes Date: Wed, 30 Jun 2004 15:01:58 +0000 (+0000) Subject: Added SET DESCRIPTOR command. X-Git-Tag: REL8_0_0BETA1~291 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=90326c01c9c116a888998e2744eeca9d3afa6242;p=postgresql Added SET DESCRIPTOR command. Note that this still has some bugs. The functionality is there though, it's just a matter of fixing the bugs now. Cleaned up error handling in preprocessor. --- diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c index b1ec43d48e..9684e30cc7 100644 --- a/src/interfaces/ecpg/ecpglib/descriptor.c +++ b/src/interfaces/ecpg/ecpglib/descriptor.c @@ -1,6 +1,6 @@ /* dynamic SQL support routines * - * $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.7 2003/11/29 19:52:08 pgsql Exp $ + * $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.8 2004/06/30 15:01:56 meskes Exp $ */ #define POSTGRES_ECPG_INTERNAL @@ -110,6 +110,51 @@ get_int_item(int lineno, void *var, enum ECPGttype vartype, int value) return (true); } +static bool +set_int_item(int lineno, int *target, const void *var, enum ECPGttype vartype) +{ + switch (vartype) + { + case ECPGt_short: + *target = *(short *) var; + break; + case ECPGt_int: + *target = *(int *) var; + break; + case ECPGt_long: + *target = *(long *) var; + break; + case ECPGt_unsigned_short: + *target = *(unsigned short *) var; + break; + case ECPGt_unsigned_int: + *target = *(unsigned int *) var; + break; + case ECPGt_unsigned_long: + *target = *(unsigned long *) var; + break; +#ifdef HAVE_LONG_LONG_INT_64 + case ECPGt_long_long: + *target = *(long long int *) var; + break; + case ECPGt_unsigned_long_long: + *target = *(unsigned long long int *) var; + break; +#endif /* HAVE_LONG_LONG_INT_64 */ + case ECPGt_float: + *target = *(float *) var; + break; + case ECPGt_double: + *target = *(double *) var; + break; + default: + ECPGraise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL); + return (false); + } + + return true; +} + static bool get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int varcharsize) { @@ -385,6 +430,124 @@ ECPGget_desc(int lineno, char *desc_name, int index,...) return (true); } +bool +ECPGset_desc(int lineno, char *desc_name, int index,...) +{ + va_list args; + struct descriptor *desc; + struct descriptor_item *desc_item, *last_di; + + for (desc = all_descriptors; desc; desc = desc->next) + { + if (strcmp(desc_name, desc->name)==0) + break; + } + + if (desc == NULL) + { + ECPGraise(lineno, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, desc_name); + return false; + } + + for (desc_item = desc->items; desc_item; desc_item = desc_item->next) + { + if (desc_item->num == index) + break; + } + + if (desc_item == NULL) + { + desc_item = ECPGalloc(sizeof(*desc_item), lineno); + desc_item->num = index; + desc_item->next = desc->items; + desc->items = desc_item; + } + + va_start(args, index); + + do + { + enum ECPGdtype itemtype; + long varcharsize; + long offset; + long arrsize; + enum ECPGttype vartype; + void *var; + + itemtype = va_arg(args, enum ECPGdtype); + + if (itemtype == ECPGd_EODT) + break; + + vartype = va_arg(args, enum ECPGttype); + var = va_arg(args, void *); + varcharsize = va_arg(args, long); + arrsize = va_arg(args, long); + offset = va_arg(args, long); + + switch (itemtype) + { + case ECPGd_data: + { + // FIXME: how to do this in general? + switch (vartype) + { + case ECPGt_char: + desc_item->data = strdup((char *)var); + break; + case ECPGt_int: + { + char buf[20]; + snprintf(buf, 20, "%d", *(int *)var); + desc_item->data = strdup(buf); + break; + } + default: + abort(); + } + break; + } + + case ECPGd_indicator: + set_int_item(lineno, &desc_item->indicator, var, vartype); + break; + + case ECPGd_length: + set_int_item(lineno, &desc_item->length, var, vartype); + break; + + case ECPGd_precision: + set_int_item(lineno, &desc_item->precision, var, vartype); + break; + + case ECPGd_scale: + set_int_item(lineno, &desc_item->scale, var, vartype); + break; + + case ECPGd_type: + set_int_item(lineno, &desc_item->type, var, vartype); + break; + + default: + { + char type_str[20]; + snprintf(type_str, sizeof(type_str), "%d", itemtype); + ECPGraise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str); + return false; + } + } + + /*if (itemtype == ECPGd_data) + { + free(desc_item->data); + desc_item->data = NULL; + }*/ + } + while (true); + + return true; +} + bool ECPGdeallocate_desc(int line, const char *name) { @@ -425,6 +588,7 @@ ECPGallocate_desc(int line, const char *name) ECPGfree(new); return false; } + new->items = NULL; new->result = PQmakeEmptyPGresult(NULL, 0); if (!new->result) { diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index c91e96d3a1..d99f958445 100644 --- a/src/interfaces/ecpg/ecpglib/execute.c +++ b/src/interfaces/ecpg/ecpglib/execute.c @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.34 2004/06/27 12:28:40 meskes Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.35 2004/06/30 15:01:56 meskes Exp $ */ /* * The aim is to get a simpler inteface to the database routines. @@ -1026,6 +1026,9 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, free(str); } break; + + case ECPGt_descriptor: + break; default: /* Not implemented yet */ @@ -1046,6 +1049,7 @@ ECPGexecute(struct statement * stmt) PGresult *results; PGnotify *notify; struct variable *var; + int desc_counter = 0; copiedquery = ECPGstrdup(stmt->command, stmt->lineno); @@ -1056,64 +1060,116 @@ ECPGexecute(struct statement * stmt) * so on. */ var = stmt->inlist; + while (var) { char *newcopy = NULL; - const char *tobeinserted = NULL; + const char *tobeinserted; char *p; - bool malloced = FALSE; - int hostvarl = 0; - - if (!ECPGstore_input(stmt, var, &tobeinserted, &malloced)) - return false; + bool malloced = FALSE; + int hostvarl = 0; - /* - * Now tobeinserted points to an area that is to be inserted at - * the first %s - */ - if (!(newcopy = (char *) ECPGalloc(strlen(copiedquery) + strlen(tobeinserted) + 1, stmt->lineno))) - return false; - - strcpy(newcopy, copiedquery); - if ((p = next_insert(newcopy + hostvarl)) == NULL) + tobeinserted = NULL; + /* A descriptor is a special case since it contains many variables but is listed only once. */ + if (var->type == ECPGt_descriptor) { - /* - * We have an argument but we dont have the matched up string - * in the string - */ - ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL); - return false; + /* We create an additional variable list here, so the same logic applies. */ + struct variable desc_inlist; + struct descriptor *desc; + struct descriptor_item *desc_item; + for (desc = all_descriptors; desc; desc = desc->next) + { + if (strcmp(var->pointer, desc->name) == 0) + break; + } + + if (desc == NULL) + { + ECPGraise(stmt->lineno, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, var->pointer); + return false; + } + + desc_counter++; + for (desc_item = desc->items; desc_item; desc_item = desc_item->next) + { + if (desc_item->num == desc_counter) + { + desc_inlist.type = ECPGt_char; + desc_inlist.value = desc_item->data; + desc_inlist.pointer = &(desc_item->data); + desc_inlist.varcharsize = strlen(desc_item->data); + desc_inlist.arrsize = 1; + desc_inlist.offset = 0; + desc_inlist.ind_type = ECPGt_NO_INDICATOR; + desc_inlist.ind_value = desc_inlist.ind_pointer = NULL; + desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = desc_inlist.ind_offset = 0; + + if (!ECPGstore_input(stmt, &desc_inlist, &tobeinserted, &malloced)) + return false; + + break; + } + } + + if (!desc_item) /* no more entries found in descriptor */ + desc_counter = 0; } else { - strcpy(p, tobeinserted); - hostvarl = strlen(newcopy); - + if (!ECPGstore_input(stmt, var, &tobeinserted, &malloced)) + return false; + } + if (tobeinserted) + { /* - * The strange thing in the second argument is the rest of the - * string from the old string + * Now tobeinserted points to an area that is to be inserted at + * the first %s */ - strcat(newcopy, - copiedquery - + (p - newcopy) - + sizeof("?") - 1 /* don't count the '\0' */ ); - } + if (!(newcopy = (char *) ECPGalloc(strlen(copiedquery) + strlen(tobeinserted) + 1, stmt->lineno))) + return false; - /* - * Now everything is safely copied to the newcopy. Lets free the - * oldcopy and let the copiedquery get the var->value from the - * newcopy. - */ - if (malloced) - { - ECPGfree((char *) tobeinserted); - tobeinserted = NULL; - } + strcpy(newcopy, copiedquery); + if ((p = next_insert(newcopy + hostvarl)) == NULL) + { + /* + * We have an argument but we dont have the matched up string + * in the string + */ + ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL); + return false; + } + else + { + strcpy(p, tobeinserted); + hostvarl = strlen(newcopy); + + /* + * The strange thing in the second argument is the rest of the + * string from the old string + */ + strcat(newcopy, + copiedquery + + (p - newcopy) + + sizeof("?") - 1 /* don't count the '\0' */ ); + } - ECPGfree(copiedquery); - copiedquery = newcopy; + /* + * Now everything is safely copied to the newcopy. Lets free the + * oldcopy and let the copiedquery get the var->value from the + * newcopy. + */ + if (malloced) + { + ECPGfree((char *) tobeinserted); + tobeinserted = NULL; + } - var = var->next; + ECPGfree(copiedquery); + copiedquery = newcopy; + } + + if (desc_counter == 0) + var = var->next; } /* Check if there are unmatched things left. */ diff --git a/src/interfaces/ecpg/ecpglib/extern.h b/src/interfaces/ecpg/ecpglib/extern.h index b265247f38..c644ff292d 100644 --- a/src/interfaces/ecpg/ecpglib/extern.h +++ b/src/interfaces/ecpg/ecpglib/extern.h @@ -7,39 +7,42 @@ enum COMPAT_MODE { - ECPG_COMPAT_PGSQL = 0, ECPG_COMPAT_INFORMIX, ECPG_COMPAT_INFORMIX_SE + ECPG_COMPAT_PGSQL = 0, ECPG_COMPAT_INFORMIX, ECPG_COMPAT_INFORMIX_SE }; #define INFORMIX_MODE(X) ((X) == ECPG_COMPAT_INFORMIX || (X) == ECPG_COMPAT_INFORMIX_SE) enum ARRAY_TYPE { - ECPG_ARRAY_NOT_SET, ECPG_ARRAY_ARRAY, ECPG_ARRAY_VECTOR, ECPG_ARRAY_NONE + ECPG_ARRAY_NOT_SET, ECPG_ARRAY_ARRAY, ECPG_ARRAY_VECTOR, ECPG_ARRAY_NONE }; /* Here are some methods used by the lib. */ /* Returns a pointer to a string containing a simple type name. */ -void ECPGadd_mem(void *ptr, int lineno); - -bool ECPGget_data(const PGresult *, int, int, int, enum ECPGttype type, - enum ECPGttype, char *, char *, long, long, long, enum ARRAY_TYPE, enum COMPAT_MODE, bool); -struct connection *ECPGget_connection(const char *); -char *ECPGalloc(long, int); -char *ECPGrealloc(void *, long, int); -void ECPGfree(void *); -bool ECPGinit(const struct connection *, const char *, const int); -char *ECPGstrdup(const char *, int); -const char *ECPGtype_name(enum ECPGttype); -unsigned int ECPGDynamicType(Oid); -void ECPGfree_auto_mem(void); -void ECPGclear_auto_mem(void); +void ECPGadd_mem (void *ptr, int lineno); + +bool ECPGget_data (const PGresult *, int, int, int, enum ECPGttype type, + enum ECPGttype, char *, char *, long, long, long, + enum ARRAY_TYPE, enum COMPAT_MODE, bool); +struct connection *ECPGget_connection (const char *); +char *ECPGalloc (long, int); +char *ECPGrealloc (void *, long, int); +void ECPGfree (void *); +bool ECPGinit (const struct connection *, const char *, const int); +char *ECPGstrdup (const char *, int); +const char *ECPGtype_name (enum ECPGttype); +unsigned int ECPGDynamicType (Oid); +void ECPGfree_auto_mem (void); +void ECPGclear_auto_mem (void); + +struct descriptor *ecpggetdescp (int, char *); /* A generic varchar type. */ struct ECPGgeneric_varchar { - int len; - char arr[1]; + int len; + char arr[1]; }; /* @@ -48,64 +51,79 @@ struct ECPGgeneric_varchar struct ECPGtype_information_cache { - struct ECPGtype_information_cache *next; - int oid; - bool isarray; + struct ECPGtype_information_cache *next; + int oid; + bool isarray; }; /* structure to store one statement */ struct statement { - int lineno; - char *command; - struct connection *connection; - enum COMPAT_MODE compat; - bool force_indicator; - struct variable *inlist; - struct variable *outlist; + int lineno; + char *command; + struct connection *connection; + enum COMPAT_MODE compat; + bool force_indicator; + struct variable *inlist; + struct variable *outlist; }; /* structure to store connections */ struct connection { - char *name; - PGconn *connection; - bool committed; - int autocommit; - struct ECPGtype_information_cache *cache_head; - struct connection *next; + char *name; + PGconn *connection; + bool committed; + int autocommit; + struct ECPGtype_information_cache *cache_head; + struct connection *next; }; /* structure to store descriptors */ struct descriptor { - char *name; - PGresult *result; - struct descriptor *next; + char *name; + PGresult *result; + struct descriptor *next; + int count; + struct descriptor_item *items; +}; + +extern struct descriptor *all_descriptors; + +struct descriptor_item +{ + int num; + char *data; + int indicator; + int length; + int precision; + int scale; + int type; + struct descriptor_item *next; }; struct variable { - enum ECPGttype type; - void *value; - void *pointer; - long varcharsize; - long arrsize; - long offset; - enum ECPGttype ind_type; - void *ind_value; - void *ind_pointer; - long ind_varcharsize; - long ind_arrsize; - long ind_offset; - struct variable *next; + enum ECPGttype type; + void *value; + void *pointer; + long varcharsize; + long arrsize; + long offset; + enum ECPGttype ind_type; + void *ind_value; + void *ind_pointer; + long ind_varcharsize; + long ind_arrsize; + long ind_offset; + struct variable *next; }; -PGresult ** - ECPGdescriptor_lvalue(int line, const char *descriptor); +PGresult **ECPGdescriptor_lvalue (int line, const char *descriptor); -bool ECPGstore_result(const PGresult *results, int act_field, - const struct statement * stmt, struct variable * var); +bool ECPGstore_result (const PGresult * results, int act_field, + const struct statement *stmt, struct variable *var); /* SQLSTATE values generated or processed by ecpglib (intentionally * not exported -- users should refer to the codes directly) */ @@ -133,4 +151,4 @@ bool ECPGstore_result(const PGresult *results, int act_field, #define ECPG_SQLSTATE_ECPG_INTERNAL_ERROR "YE000" #define ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY "YE001" -#endif /* _ECPG_LIB_EXTERN_H */ +#endif /* _ECPG_LIB_EXTERN_H */ diff --git a/src/interfaces/ecpg/include/ecpglib.h b/src/interfaces/ecpg/include/ecpglib.h index b76cd4d19c..9f3e3aa150 100644 --- a/src/interfaces/ecpg/include/ecpglib.h +++ b/src/interfaces/ecpg/include/ecpglib.h @@ -76,6 +76,8 @@ void ECPGraise(int line, int code, const char *sqlstate, const char *str); void ECPGraise_backend(int line, PGresult *result, PGconn *conn, int compat); bool ECPGget_desc_header(int, char *, int *); bool ECPGget_desc(int, char *, int,...); +bool ECPGset_desc_header(int, char *, int *); +bool ECPGset_desc(int, char *, int,...); void ECPGset_noind_null(enum ECPGttype, void *); bool ECPGis_noind_null(enum ECPGttype, void *); diff --git a/src/interfaces/ecpg/preproc/descriptor.c b/src/interfaces/ecpg/preproc/descriptor.c index 742002b4c0..6861a91dc7 100644 --- a/src/interfaces/ecpg/preproc/descriptor.c +++ b/src/interfaces/ecpg/preproc/descriptor.c @@ -58,9 +58,7 @@ ECPGnumeric_lvalue(FILE *f, char *name) fputs(name, yyout); break; default: - snprintf(errortext, sizeof errortext, "variable %s: numeric type needed" - ,name); - mmerror(PARSE_ERROR, ET_ERROR, errortext); + mmerror(PARSE_ERROR, ET_ERROR, "variable %s: numeric type needed", name); break; } } @@ -120,8 +118,7 @@ drop_descriptor(char *name, char *connection) } } } - snprintf(errortext, sizeof errortext, "unknown descriptor %s", name); - mmerror(PARSE_ERROR, ET_WARNING, errortext); + mmerror(PARSE_ERROR, ET_WARNING, "unknown descriptor %s", name); } struct descriptor @@ -143,8 +140,7 @@ lookup_descriptor(char *name, char *connection) return i; } } - snprintf(errortext, sizeof errortext, "unknown descriptor %s", name); - mmerror(PARSE_ERROR, ET_WARNING, errortext); + mmerror(PARSE_ERROR, ET_WARNING, "unknown descriptor %s", name); return NULL; } @@ -153,16 +149,13 @@ output_get_descr_header(char *desc_name) { struct assignment *results; - fprintf(yyout, "{ ECPGget_desc_header(%d, %s, &(", yylineno, desc_name); + fprintf(yyout, "{ ECPGget_desc_header(__LINE__, %s, &(", desc_name); for (results = assignments; results != NULL; results = results->next) { if (results->value == ECPGd_count) ECPGnumeric_lvalue(yyout, results->variable); else - { - snprintf(errortext, sizeof errortext, "unknown descriptor header item '%d'", results->value); - mmerror(PARSE_ERROR, ET_WARNING, errortext); - } + mmerror(PARSE_ERROR, ET_WARNING, "unknown descriptor header item '%d'", results->value); } drop_assignments(); @@ -175,7 +168,7 @@ output_get_descr(char *desc_name, char *index) { struct assignment *results; - fprintf(yyout, "{ ECPGget_desc(%d, %s, %s,", yylineno, desc_name, index); + fprintf(yyout, "{ ECPGget_desc(__LINE__, %s, %s,", desc_name, index); for (results = assignments; results != NULL; results = results->next) { const struct variable *v = find_variable(results->variable); @@ -200,6 +193,116 @@ output_get_descr(char *desc_name, char *index) whenever_action(2 | 1); } +void +output_set_descr_header(char *desc_name) +{ + struct assignment *results; + + fprintf(yyout, "{ ECPGset_desc_header(__LINE__, %s, &(", desc_name); + for (results = assignments; results != NULL; results = results->next) + { + if (results->value == ECPGd_count) + ECPGnumeric_lvalue(yyout, results->variable); + else + mmerror(PARSE_ERROR, ET_WARNING, "unknown descriptor header item '%d'", results->value); + } + + drop_assignments(); + fprintf(yyout, "));\n"); + whenever_action(3); +} + +static const char * +descriptor_item_name(enum ECPGdtype itemcode) +{ + switch (itemcode) + { + case ECPGd_cardinality: + return "CARDINALITY"; + case ECPGd_count: + return "COUNT"; + case ECPGd_data: + return "DATA"; + case ECPGd_di_code: + return "DATETIME_INTERVAL_CODE"; + case ECPGd_di_precision: + return "DATETIME_INTERVAL_PRECISION"; + case ECPGd_indicator: + return "INDICATOR"; + case ECPGd_key_member: + return "KEY_MEMBER"; + case ECPGd_length: + return "LENGTH"; + case ECPGd_name: + return "NAME"; + case ECPGd_nullable: + return "NULLABLE"; + case ECPGd_octet: + return "OCTET_LENGTH"; + case ECPGd_precision: + return "PRECISION"; + case ECPGd_ret_length: + return "RETURNED_LENGTH"; + case ECPGd_ret_octet: + return "RETURNED_OCTET_LENGTH"; + case ECPGd_scale: + return "SCALE"; + case ECPGd_type: + return "TYPE"; + default: + return NULL; + } +} + +void +output_set_descr(char *desc_name, char *index) +{ + struct assignment *results; + + fprintf(yyout, "{ ECPGset_desc(__LINE__, %s, %s,", desc_name, index); + for (results = assignments; results != NULL; results = results->next) + { + const struct variable *v = find_variable(results->variable); + + switch (results->value) + { + case ECPGd_cardinality: + case ECPGd_di_code: + case ECPGd_di_precision: + case ECPGd_precision: + case ECPGd_scale: + mmerror(PARSE_ERROR, ET_FATAL, "descriptor item %s is not implemented", + descriptor_item_name(results->value)); + break; + + case ECPGd_key_member: + case ECPGd_name: + case ECPGd_nullable: + case ECPGd_octet: + case ECPGd_ret_length: + case ECPGd_ret_octet: + mmerror(PARSE_ERROR, ET_FATAL, "descriptor item %s cannot be set", + descriptor_item_name(results->value)); + break; + + case ECPGd_data: + case ECPGd_indicator: + case ECPGd_length: + case ECPGd_type: + fprintf(yyout, "%s,", get_dtype(results->value)); + ECPGdump_a_type(yyout, v->name, v->type, NULL, NULL, NULL, NULL, make_str("0"), NULL, NULL); + break; + + default: + ; + } + } + drop_assignments(); + fputs("ECPGd_EODT);\n", yyout); + + whenever_action(2 | 1); +} + /* I consider dynamic allocation overkill since at most two descriptor variables are possible per statement. (input and output descriptor) And descriptors are no normal variables, so they don't belong into @@ -211,11 +314,10 @@ struct variable * descriptor_variable(const char *name, int input) { static char descriptor_names[2][MAX_DESCRIPTOR_NAMELEN]; - static const struct ECPGtype descriptor_type = - {ECPGt_descriptor, 0}; - static const struct variable varspace[2] = - {{descriptor_names[0], (struct ECPGtype *) & descriptor_type, 0, NULL}, - {descriptor_names[1], (struct ECPGtype *) & descriptor_type, 0, NULL} + static const struct ECPGtype descriptor_type = { ECPGt_descriptor, 0 }; + static const struct variable varspace[2] = { + { descriptor_names[0], (struct ECPGtype *) & descriptor_type, 0, NULL }, + { descriptor_names[1], (struct ECPGtype *) & descriptor_type, 0, NULL } }; strncpy(descriptor_names[input], name, MAX_DESCRIPTOR_NAMELEN); diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h index 3d1088a207..6f9518f7e6 100644 --- a/src/interfaces/ecpg/preproc/extern.h +++ b/src/interfaces/ecpg/preproc/extern.h @@ -25,8 +25,7 @@ extern char *descriptor_name; extern char *connection; extern char *input_filename; extern char *yytext, - *token_start, - errortext[128]; + *token_start; #ifdef YYDEBUG extern int yydebug; @@ -63,11 +62,13 @@ extern int yylex(void); extern void yyerror(char *); extern void *mm_alloc(size_t), *mm_realloc(void *, size_t); extern char *mm_strdup(const char *); -extern void mmerror(int, enum errortype, char *); +extern void mmerror(int, enum errortype, char *, ...); extern ScanKeyword *ScanECPGKeywordLookup(char *); extern ScanKeyword *ScanCKeywordLookup(char *); extern void output_get_descr_header(char *); extern void output_get_descr(char *, char *); +extern void output_set_descr_header(char *); +extern void output_set_descr(char *, char *); extern void push_assignment(char *, enum ECPGdtype); extern struct variable *find_variable(char *); extern void whenever_action(int); diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l index a6d9d75543..e4ab68634f 100644 --- a/src/interfaces/ecpg/preproc/pgc.l +++ b/src/interfaces/ecpg/preproc/pgc.l @@ -12,7 +12,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.128 2004/05/05 15:03:04 meskes Exp $ + * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.129 2004/06/30 15:01:57 meskes Exp $ * *------------------------------------------------------------------------- */ @@ -1164,10 +1164,7 @@ parse_include(void) } } if (!yyin) - { - snprintf(errortext, sizeof(errortext), "Cannot open include file %s in line %d\n", yytext, yylineno); - mmerror(NO_INCLUDE_FILE, ET_FATAL, errortext); - } + mmerror(NO_INCLUDE_FILE, ET_FATAL, "Cannot open include file %s in line %d\n", yytext, yylineno); input_filename = mm_strdup(inc_file); yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE )); diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index b4cf02e6e2..ee9f25bad1 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.289 2004/06/27 12:28:42 meskes Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.290 2004/06/30 15:01:57 meskes Exp $ */ /* Copyright comment */ %{ @@ -12,7 +12,6 @@ int struct_level = 0; int braces_open; /* brace level counter */ int ecpg_informix_var = 0; -char errortext[128]; char *connection = NULL; char *input_filename = NULL; @@ -52,19 +51,37 @@ static struct inf_compat_val * Handle parsing errors and warnings */ void -mmerror(int error_code, enum errortype type, char * error) +mmerror(int error_code, enum errortype type, char * error, ...) { + va_list ap; + + fprintf(stderr, "%s:%d: ", input_filename, yylineno); + + switch(type) + { + case ET_WARNING: + fprintf(stderr, "WARNING: "); + break; + case ET_ERROR: + case ET_FATAL: + fprintf(stderr, "ERROR: "); + break; + } + + va_start(ap, error); + vfprintf(stderr, error, ap); + va_end(ap); + + fprintf(stderr, "\n"); + switch(type) { case ET_WARNING: - fprintf(stderr, "%s:%d: WARNING: %s\n", input_filename, yylineno, error); break; case ET_ERROR: - fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error); ret_value = error_code; break; case ET_FATAL: - fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error); exit(error_code); } } @@ -261,8 +278,7 @@ add_additional_variables(char *name, bool insert) if (ptr == NULL) { - snprintf(errortext, sizeof(errortext), "trying to access an undeclared cursor %s\n", name); - mmerror(PARSE_ERROR, ET_ERROR, errortext); + mmerror(PARSE_ERROR, ET_ERROR, "trying to access an undeclared cursor %s\n", name); return NULL; } if (insert) @@ -540,14 +556,14 @@ add_additional_variables(char *name, bool insert) %type col_name_keyword func_name_keyword precision opt_scale %type ECPGTypeName using_list ECPGColLabelCommon UsingConst %type inf_val_list inf_col_list using_descriptor into_descriptor -%type ecpg_into_using prepared_name struct_union_type_with_symbol +%type prepared_name struct_union_type_with_symbol %type ECPGunreserved ECPGunreserved_interval cvariable %type AlterOwnerStmt OptTableSpaceOwner CreateTableSpaceStmt -%type DropTableSpaceStmt indirection indirection_el +%type DropTableSpaceStmt indirection indirection_el ECPGSetDescriptorHeader %type s_struct_union_symbol -%type ECPGGetDescriptor +%type ECPGGetDescriptor ECPGSetDescriptor %type simple_type signed_type unsigned_type @@ -811,6 +827,19 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); } whenever_action(2); free($1); } + | ECPGSetDescriptor + { + lookup_descriptor($1.name, connection); + output_set_descr($1.name, $1.str); + free($1.name); + free($1.str); + } + | ECPGSetDescriptorHeader + { + lookup_descriptor($1, connection); + output_set_descr_header($1); + free($1); + } | ECPGTypedef { if (connection) @@ -1925,22 +1954,22 @@ TruncateStmt: TRUNCATE opt_table qualified_name * embedded SQL implementations. So we accept their syntax as well and * translate it to the PGSQL syntax. */ -FetchStmt: FETCH fetch_direction from_in name ecpg_into_using +FetchStmt: FETCH fetch_direction from_in name ecpg_into { add_additional_variables($4, false); $$ = cat_str(4, make_str("fetch"), $2, $3, $4); } - | FETCH fetch_direction name ecpg_into_using + | FETCH fetch_direction name ecpg_into { add_additional_variables($3, false); $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3); } - | FETCH from_in name ecpg_into_using + | FETCH from_in name ecpg_into { add_additional_variables($3, false); $$ = cat_str(3, make_str("fetch"), $2, $3); } - | FETCH name ecpg_into_using + | FETCH name ecpg_into { add_additional_variables($2, false); $$ = cat2_str(make_str("fetch"), $2); @@ -2895,11 +2924,8 @@ DeclareCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR SelectStmt for (ptr = cur; ptr != NULL; ptr = ptr->next) { if (strcmp($2, ptr->name) == 0) - { - /* re-definition is a bug */ - snprintf(errortext, sizeof(errortext), "cursor %s already defined", $2); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + /* re-definition is a bug */ + mmerror(PARSE_ERROR, ET_ERROR, "cursor %s already defined", $2); } this = (struct cursor *) mm_alloc(sizeof(struct cursor)); @@ -2987,7 +3013,7 @@ into_clause: INTO OptTempTableName FoundInto = 1; $$= cat2_str(make_str("into"), $2); } - | ecpg_into_using { $$ = EMPTY; } + | ecpg_into { $$ = EMPTY; } | /*EMPTY*/ { $$ = EMPTY; } ; @@ -4246,11 +4272,7 @@ connection_target: database_name opt_server opt_port { /* old style: dbname[@server][:port] */ if (strlen($2) > 0 && *($2) != '@') - { - snprintf(errortext, sizeof(errortext), - "Expected '@', found '%s'", $2); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "Expected '@', found '%s'", $2); $$ = make3_str(make_str("\""), make3_str($1, $2, $3), make_str("\"")); } @@ -4258,24 +4280,15 @@ connection_target: database_name opt_server opt_port { /* new style: :postgresql://server[:port][/dbname] */ if (strncmp($1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp($1, "tcp:postgresql", strlen("tcp:postgresql")) != 0) - { - snprintf(errortext, sizeof(errortext), "only protocols 'tcp' and 'unix' and database type 'postgresql' are supported"); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "only protocols 'tcp' and 'unix' and database type 'postgresql' are supported"); if (strncmp($3, "//", strlen("//")) != 0) - { - snprintf(errortext, sizeof(errortext), "Expected '://', found '%s'", $3); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "Expected '://', found '%s'", $3); if (strncmp($1, "unix", strlen("unix")) == 0 && strncmp($3 + strlen("//"), "localhost", strlen("localhost")) != 0 && strncmp($3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0) - { - snprintf(errortext, sizeof(errortext), "unix domain sockets only work on 'localhost' but not on '%9.9s'", $3 + strlen("//")); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "unix domain sockets only work on 'localhost' but not on '%9.9s'", $3 + strlen("//")); $$ = make3_str(make3_str(make_str("\""), $1, make_str(":")), $3, make3_str(make3_str($4, make_str("/"), $6), $7, make_str("\""))); } @@ -4295,16 +4308,10 @@ connection_target: database_name opt_server opt_port db_prefix: ident cvariable { if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0) - { - snprintf(errortext, sizeof(errortext), "Expected 'postgresql', found '%s'", $2); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "Expected 'postgresql', found '%s'", $2); if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0) - { - snprintf(errortext, sizeof(errortext), "Illegal connection type %s", $1); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "Illegal connection type %s", $1); $$ = make3_str($1, make_str(":"), $2); } @@ -4313,10 +4320,7 @@ db_prefix: ident cvariable server: Op server_name { if (strcmp($1, "@") != 0 && strcmp($1, "//") != 0) - { - snprintf(errortext, sizeof(errortext), "Expected '@' or '://', found '%s'", $1); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "Expected '@' or '://', found '%s'", $1); $$ = make2_str($1, $2); } @@ -4421,10 +4425,7 @@ opt_options: Op ColId mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement"); if (strcmp($1, "?") != 0) - { - snprintf(errortext, sizeof(errortext), "unrecognised token '%s'", $1); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "unrecognised token '%s'", $1); $$ = make2_str(make_str("?"), $2); } @@ -4443,11 +4444,8 @@ ECPGCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR prepared_name for (ptr = cur; ptr != NULL; ptr = ptr->next) { if (strcmp($2, ptr->name) == 0) - { - /* re-definition is a bug */ - snprintf(errortext, sizeof(errortext), "cursor %s already defined", $2); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + /* re-definition is a bug */ + mmerror(PARSE_ERROR, ET_ERROR, "cursor %s already defined", $2); } this = (struct cursor *) mm_alloc(sizeof(struct cursor)); @@ -4595,11 +4593,8 @@ type_declaration: S_TYPEDEF for (ptr = types; ptr != NULL; ptr = ptr->next) { if (strcmp($5, ptr->name) == 0) - { /* re-definition is a bug */ - snprintf(errortext, sizeof(errortext), "Type %s already defined", $5); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "Type %s already defined", $5); } adjust_array($3.type_enum, &dimension, &length, $3.type_dimension, $3.type_index, *$4?1:0, true); @@ -4912,11 +4907,8 @@ struct_union_type_with_symbol: s_struct_union_symbol for (ptr = types; ptr != NULL; ptr = ptr->next) { if (strcmp(su_type.type_str, ptr->name) == 0) - { /* re-definition is a bug */ - snprintf(errortext, sizeof(errortext), "Type %s already defined", su_type.type_str); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "Type %s already defined", su_type.type_str); } this = (struct typedefs *) mm_alloc(sizeof(struct typedefs)); @@ -5215,28 +5207,25 @@ opt_ecpg_using: /*EMPTY*/ { $$ = EMPTY; } ; ecpg_using: USING using_list { $$ = EMPTY; } + | using_descriptor { $$ = $1; } ; using_descriptor: USING opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { - add_variable_to_head(&argsresult, descriptor_variable($4,0), &no_indicator); + add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator); $$ = EMPTY; } ; into_descriptor: INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { - add_variable_to_head(&argsresult, descriptor_variable($4,0), &no_indicator); + add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator); $$ = EMPTY; } ; opt_sql: /*EMPTY*/ | SQL_SQL; -ecpg_into_using: ecpg_into { $$ = EMPTY; } - | using_descriptor { $$ = $1; } - ; - ecpg_into: INTO into_list { $$ = EMPTY; } | into_descriptor { $$ = $1; } ; @@ -5295,8 +5284,19 @@ opt_output: SQL_OUTPUT { $$ = make_str("output"); } /* * dynamic SQL: descriptor based access * written by Christof Petig + * and Peter Eisentraut */ +/* + * allocate a descriptor + */ +ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar + { + add_descriptor($3,connection); + $$ = $3; + }; + + /* * deallocate a descriptor */ @@ -5308,63 +5308,85 @@ ECPGDeallocateDescr: DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar ; /* - * allocate a descriptor + * manipulate a descriptor header */ -ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar - { - add_descriptor($3,connection); - $$ = $3; - }; -/* - * read from descriptor - */ +ECPGGetDescriptorHeader: GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescHeaderItems + { $$ = $3; } + ; -ECPGGetDescHeaderItem: cvariable '=' desc_header_item +ECPGGetDescHeaderItems: ECPGGetDescHeaderItem + | ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem + ; + +ECPGGetDescHeaderItem: CVARIABLE '=' desc_header_item { push_assignment($1, $3); } ; -desc_header_item: SQL_COUNT { $$ = ECPGd_count; } + +ECPGSetDescriptorHeader: SET SQL_DESCRIPTOR quoted_ident_stringvar ECPGSetDescHeaderItems + { $$ = $3; } + +ECPGSetDescHeaderItems: ECPGSetDescHeaderItem + | ECPGSetDescHeaderItems ',' ECPGSetDescHeaderItem + ; + +ECPGSetDescHeaderItem: desc_header_item '=' CVARIABLE + { push_assignment($3, $1); } ; -ECPGGetDescItem: cvariable '=' descriptor_item { push_assignment($1, $3); }; -descriptor_item: SQL_CARDINALITY { $$ = ECPGd_cardinality; } - | SQL_DATA { $$ = ECPGd_data; } - | SQL_DATETIME_INTERVAL_CODE { $$ = ECPGd_di_code; } - | SQL_DATETIME_INTERVAL_PRECISION { $$ = ECPGd_di_precision; } - | SQL_INDICATOR { $$ = ECPGd_indicator; } - | SQL_KEY_MEMBER { $$ = ECPGd_key_member; } - | SQL_LENGTH { $$ = ECPGd_length; } - | SQL_NAME { $$ = ECPGd_name; } - | SQL_NULLABLE { $$ = ECPGd_nullable; } - | SQL_OCTET_LENGTH { $$ = ECPGd_octet; } - | PRECISION { $$ = ECPGd_precision; } - | SQL_RETURNED_LENGTH { $$ = ECPGd_length; } - | SQL_RETURNED_OCTET_LENGTH { $$ = ECPGd_ret_octet; } - | SQL_SCALE { $$ = ECPGd_scale; } - | TYPE_P { $$ = ECPGd_type; } +desc_header_item: SQL_COUNT { $$ = ECPGd_count; } ; -ECPGGetDescHeaderItems: ECPGGetDescHeaderItem - | ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem +/* + * manipulate a descriptor + */ + +ECPGGetDescriptor: GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE CVARIABLE ECPGGetDescItems + { $$.str = $5; $$.name = $3; } + | GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE Iconst ECPGGetDescItems + { $$.str = $5; $$.name = $3; } ; ECPGGetDescItems: ECPGGetDescItem | ECPGGetDescItems ',' ECPGGetDescItem ; -ECPGGetDescriptorHeader: GET SQL_DESCRIPTOR quoted_ident_stringvar - ECPGGetDescHeaderItems - { $$ = $3; } - ; +ECPGGetDescItem: CVARIABLE '=' descriptor_item { push_assignment($1, $3); }; + -ECPGGetDescriptor: GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE cvariable ECPGGetDescItems +ECPGSetDescriptor: SET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE CVARIABLE ECPGSetDescItems { $$.str = $5; $$.name = $3; } - | GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE Iconst ECPGGetDescItems + | SET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE Iconst ECPGSetDescItems { $$.str = $5; $$.name = $3; } ; +ECPGSetDescItems: ECPGSetDescItem + | ECPGSetDescItems ',' ECPGSetDescItem + ; + +ECPGSetDescItem: descriptor_item '=' CVARIABLE { push_assignment($3, $1); }; + + +descriptor_item: SQL_CARDINALITY { $$ = ECPGd_cardinality; } + | SQL_DATA { $$ = ECPGd_data; } + | SQL_DATETIME_INTERVAL_CODE { $$ = ECPGd_di_code; } + | SQL_DATETIME_INTERVAL_PRECISION { $$ = ECPGd_di_precision; } + | SQL_INDICATOR { $$ = ECPGd_indicator; } + | SQL_KEY_MEMBER { $$ = ECPGd_key_member; } + | SQL_LENGTH { $$ = ECPGd_length; } + | SQL_NAME { $$ = ECPGd_name; } + | SQL_NULLABLE { $$ = ECPGd_nullable; } + | SQL_OCTET_LENGTH { $$ = ECPGd_octet; } + | PRECISION { $$ = ECPGd_precision; } + | SQL_RETURNED_LENGTH { $$ = ECPGd_length; } + | SQL_RETURNED_OCTET_LENGTH { $$ = ECPGd_ret_octet; } + | SQL_SCALE { $$ = ECPGd_scale; } + | TYPE_P { $$ = ECPGd_type; } + ; + + /* * for compatibility with ORACLE we will also allow the keyword RELEASE * after a transaction statement to disconnect from the database. @@ -5431,11 +5453,8 @@ ECPGTypedef: TYPE_P for (ptr = types; ptr != NULL; ptr = ptr->next) { if (strcmp($3, ptr->name) == 0) - { /* re-definition is a bug */ - snprintf(errortext, sizeof(errortext), "Type %s already defined", $3); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "Type %s already defined", $3); } adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7?1:0, false); diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c index 70db72ebab..77caff9ac2 100644 --- a/src/interfaces/ecpg/preproc/type.c +++ b/src/interfaces/ecpg/preproc/type.c @@ -195,8 +195,7 @@ get_type(enum ECPGttype type) return ("ECPGt_timestamp"); break; default: - sprintf(errortext, "illegal variable type %d\n", type); - yyerror(errortext); + mmerror(PARSE_ERROR, ET_ERROR, "illegal variable type %d\n", type); } return NULL; @@ -538,8 +537,7 @@ ECPGfree_type(struct ECPGtype * type) ECPGfree_struct_member(type->u.members); break; default: - sprintf(errortext, "illegal variable type %d\n", type->type); - yyerror(errortext); + mmerror(PARSE_ERROR, ET_ERROR, "illegal variable type %d\n", type->type); break; } } @@ -598,8 +596,7 @@ get_dtype(enum ECPGdtype type) case ECPGd_cardinality: return ("ECPGd_cardinality"); default: - sprintf(errortext, "illegal descriptor item %d\n", type); - yyerror(errortext); + mmerror(PARSE_ERROR, ET_ERROR, "illegal descriptor item %d\n", type); } return NULL; diff --git a/src/interfaces/ecpg/preproc/variable.c b/src/interfaces/ecpg/preproc/variable.c index f13f7375cb..081ed27ca3 100644 --- a/src/interfaces/ecpg/preproc/variable.c +++ b/src/interfaces/ecpg/preproc/variable.c @@ -84,10 +84,7 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member * members, in case '\0': /* found the end, but this time it has to * be an array element */ if (members->type->type != ECPGt_array) - { - snprintf(errortext, sizeof(errortext), "incorrectly formed variable %s", name); - mmerror(PARSE_ERROR, ET_FATAL, errortext); - } + mmerror(PARSE_ERROR, ET_FATAL, "incorrectly formed variable %s", name); switch (members->type->u.element->type) { @@ -110,8 +107,7 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member * members, in return (find_struct_member(name, end, members->type->u.members, brace_level)); break; default: - snprintf(errortext, sizeof(errortext), "incorrectly formed variable %s", name); - mmerror(PARSE_ERROR, ET_FATAL, errortext); + mmerror(PARSE_ERROR, ET_FATAL, "incorrectly formed variable %s", name); break; } } @@ -134,16 +130,10 @@ find_struct(char *name, char *next, char *end) if (c == '-') { if (p->type->type != ECPGt_array) - { - snprintf(errortext, sizeof(errortext), "variable %s is not a pointer", name); - mmerror(PARSE_ERROR, ET_FATAL, errortext); - } + mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not a pointer", name); if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union) - { - snprintf(errortext, sizeof(errortext), "variable %s is not a pointer to a structure or a union", name); - mmerror(PARSE_ERROR, ET_FATAL, errortext); - } + mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not a pointer to a structure or a union", name); /* restore the name, we will need it later */ *next = c; @@ -155,10 +145,7 @@ find_struct(char *name, char *next, char *end) if (next == end) { if (p->type->type != ECPGt_struct && p->type->type != ECPGt_union) - { - snprintf(errortext, sizeof(errortext), "variable %s is neither a structure nor a union", name); - mmerror(PARSE_ERROR, ET_FATAL, errortext); - } + mmerror(PARSE_ERROR, ET_FATAL, "variable %s is neither a structure nor a union", name); /* restore the name, we will need it later */ *next = c; @@ -168,16 +155,10 @@ find_struct(char *name, char *next, char *end) else { if (p->type->type != ECPGt_array) - { - snprintf(errortext, sizeof(errortext), "variable %s is not an array", name); - mmerror(PARSE_ERROR, ET_FATAL, errortext); - } + mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not an array", name); if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union) - { - snprintf(errortext, sizeof(errortext), "variable %s is not a pointer to a structure or a union", name); - mmerror(PARSE_ERROR, ET_FATAL, errortext); - } + mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not a pointer to a structure or a union", name); /* restore the name, we will need it later */ *next = c; @@ -243,10 +224,8 @@ find_variable(char *name) *next = '\0'; p = find_simple(name); if (p == NULL) - { - snprintf(errortext, sizeof(errortext), "The variable %s is not declared", name); - mmerror(PARSE_ERROR, ET_FATAL, errortext); - } + mmerror(PARSE_ERROR, ET_FATAL, "The variable %s is not declared", name); + *next = c; switch (p->type->u.element->type) { @@ -267,10 +246,7 @@ find_variable(char *name) p = find_simple(name); if (p == NULL) - { - snprintf(errortext, sizeof(errortext), "The variable %s is not declared", name); - mmerror(PARSE_ERROR, ET_FATAL, errortext); - } + mmerror(PARSE_ERROR, ET_FATAL, "The variable %s is not declared", name); return (p); } @@ -490,10 +466,7 @@ get_typedef(char *name) for (this = types; this && strcmp(this->name, name); this = this->next); if (!this) - { - snprintf(errortext, sizeof(errortext), "invalid datatype '%s'", name); - mmerror(PARSE_ERROR, ET_FATAL, errortext); - } + mmerror(PARSE_ERROR, ET_FATAL, "invalid datatype '%s'", name); return (this); } @@ -521,10 +494,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty } if (pointer_len > 2) - { - snprintf(errortext, sizeof(errortext), "No multilevel (more than 2) pointer supported %d", pointer_len); - mmerror(PARSE_ERROR, ET_FATAL, errortext); - } + mmerror(PARSE_ERROR, ET_FATAL, "No multilevel (more than 2) pointer supported %d", pointer_len); if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char) mmerror(PARSE_ERROR, ET_FATAL, "No pointer to pointer supported for this type"); diff --git a/src/interfaces/ecpg/test/test_desc.pgc b/src/interfaces/ecpg/test/test_desc.pgc new file mode 100644 index 0000000000..edfa699cdc --- /dev/null +++ b/src/interfaces/ecpg/test/test_desc.pgc @@ -0,0 +1,69 @@ +EXEC SQL WHENEVER SQLERROR SQLPRINT; + +int +main() +{ + EXEC SQL BEGIN DECLARE SECTION; + char *stmt1 = "INSERT INTO test1 VALUES (?, ?)"; + char *stmt2 = "SELECT * from test1 where a = ? and b = ?"; + + int val1 = 1; + char val2[] = "one", val2output[] = "AAA"; + int val1output = 2, val2i = 0; + int val2null = 1; + EXEC SQL END DECLARE SECTION; + FILE *dbgs; + + if ((dbgs = fopen("log", "w")) != NULL) + ECPGdebug(1, dbgs); + + EXEC SQL ALLOCATE DESCRIPTOR indesc; + EXEC SQL ALLOCATE DESCRIPTOR outdesc; + + EXEC SQL SET DESCRIPTOR indesc VALUE 1 DATA = :val1; + EXEC SQL SET DESCRIPTOR indesc VALUE 2 INDICATOR = :val2i, DATA = :val2; + + EXEC SQL CONNECT TO mm; + + EXEC SQL CREATE TABLE test1 (a int, b text); + EXEC SQL PREPARE foo1 FROM :stmt1; + EXEC SQL PREPARE foo2 FROM :stmt2; + + EXEC SQL EXECUTE foo1 USING DESCRIPTOR indesc; + + //EXEC SQL SET DESCRIPTOR indesc VALUE 1 DATA = 2; + EXEC SQL SET DESCRIPTOR indesc VALUE 1 DATA = :val1output; + EXEC SQL SET DESCRIPTOR indesc VALUE 2 INDICATOR = :val2null, DATA = :val2; + + EXEC SQL EXECUTE foo1 USING DESCRIPTOR indesc; + + EXEC SQL SET DESCRIPTOR indesc VALUE 1 DATA = :val1; + EXEC SQL SET DESCRIPTOR indesc VALUE 2 INDICATOR = :val2i, DATA = :val2; + + EXEC SQL EXECUTE foo2 USING DESCRIPTOR indesc INTO DESCRIPTOR outdesc; + + EXEC SQL GET DESCRIPTOR outdesc VALUE 1 :val2output = DATA; + printf("output = %s\n", val2output); + + EXEC SQL DECLARE c CURSOR FOR foo2; + EXEC SQL OPEN c USING DESCRIPTOR indesc; + + EXEC SQL FETCH next FROM c INTO :val1output, :val2output; + printf("val1=%d val2=%s\n", val1output, val2output); + + EXEC SQL CLOSE c; + + EXEC SQL SELECT * INTO :val1output, :val2output FROM test1 where a = 2; + printf("val1=%d val2=%s\n", val1output, val2output); + + EXEC SQL DROP TABLE test1; + EXEC SQL DISCONNECT; + + EXEC SQL DEALLOCATE DESCRIPTOR indesc; + EXEC SQL DEALLOCATE DESCRIPTOR outdesc; + + if (dbgs != NULL) + fclose(dbgs); + + return 0; +}