ECPG support for struct in INTO list - Mailing list pgsql-hackers
From | Boszormenyi Zoltan |
---|---|
Subject | ECPG support for struct in INTO list |
Date | |
Msg-id | 4A605225.4050205@cybertec.at Whole thread Raw |
Responses |
Re: ECPG support for struct in INTO list
|
List | pgsql-hackers |
Hi, one of our clients wants to port their application suite from Informix to PostgreSQL, they use constructs like SELECT * INTO :tablerec FROM table ... where "tablerec" mirrors the table fields in a C struct. Currently ECPG dumps core on this, more exactly aborts on it in ecpg_type_name(). Patch is attached that solves it by introducing add_struct_to_head() called from rule "coutputvariable" that also catches C unions now, emitting an error because unions cannot be unambiguously unrolled. It tries to handle NULL indicator, expecting a struct with at least the same amount of members. Best regards, Zoltán Böszörményi -- Bible has answers for everything. Proof: "But let your communication be, Yea, yea; Nay, nay: for whatsoever is more than these cometh of evil." (Matthew 5:37) - basics of digital technology. "May your kingdom come" - superficial description of plate tectonics ---------------------------------- Zoltán Böszörményi Cybertec Schönig & Schönig GmbH http://www.postgresql.at/ diff -dcrpN pgsql85dev.4string/src/interfaces/ecpg/preproc/ecpg.trailer pgsql85dev.5struct/src/interfaces/ecpg/preproc/ecpg.trailer *** pgsql85dev.4string/src/interfaces/ecpg/preproc/ecpg.trailer 2009-07-14 21:36:58.000000000 +0200 --- pgsql85dev.5struct/src/interfaces/ecpg/preproc/ecpg.trailer 2009-07-17 12:24:30.000000000 +0200 *************** c_args: /*EMPTY*/ { $$ = EMPTY; } *** 1835,1843 **** ; coutputvariable: cvariable indicator ! { add_variable_to_head(&argsresult, find_variable($1), find_variable($2)); } | cvariable ! { add_variable_to_head(&argsresult, find_variable($1), &no_indicator); } ; --- 1835,1873 ---- ; coutputvariable: cvariable indicator ! { ! struct variable *var = find_variable($1); ! ! switch (var->type->type) ! { ! case ECPGt_struct: ! add_struct_to_head(&argsresult, var, find_variable($2)); ! break; ! case ECPGt_union: ! mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is a union", var->name); ! break; ! default: ! add_variable_to_head(&argsresult, var, find_variable($2)); ! break; ! } ! } | cvariable ! { ! struct variable *var = find_variable($1); ! ! switch (var->type->type) ! { ! case ECPGt_struct: ! add_struct_to_head(&argsresult, var, &no_indicator); ! break; ! case ECPGt_union: ! mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is a union", var->name); ! break; ! default: ! add_variable_to_head(&argsresult, var, &no_indicator); ! break; ! } ! } ; diff -dcrpN pgsql85dev.4string/src/interfaces/ecpg/preproc/extern.h pgsql85dev.5struct/src/interfaces/ecpg/preproc/extern.h *** pgsql85dev.4string/src/interfaces/ecpg/preproc/extern.h 2009-07-14 21:36:58.000000000 +0200 --- pgsql85dev.5struct/src/interfaces/ecpg/preproc/extern.h 2009-07-17 12:24:30.000000000 +0200 *************** extern struct descriptor *lookup_descrip *** 91,96 **** --- 91,97 ---- extern struct variable *descriptor_variable(const char *name, int input); extern struct variable *sqlda_variable(const char *name); extern void add_variable_to_head(struct arguments **, struct variable *, struct variable *); + extern void add_struct_to_head(struct arguments **, struct variable *, struct variable *); extern void add_variable_to_tail(struct arguments **, struct variable *, struct variable *); extern void remove_variable_from_list(struct arguments ** list, struct variable * var); extern void dump_variables(struct arguments *, int); diff -dcrpN pgsql85dev.4string/src/interfaces/ecpg/preproc/variable.c pgsql85dev.5struct/src/interfaces/ecpg/preproc/variable.c *** pgsql85dev.4string/src/interfaces/ecpg/preproc/variable.c 2009-07-14 21:36:58.000000000 +0200 --- pgsql85dev.5struct/src/interfaces/ecpg/preproc/variable.c 2009-07-17 12:24:30.000000000 +0200 *************** add_variable_to_head(struct arguments ** *** 382,387 **** --- 382,461 ---- *list = p; } + /* + * Insert a struct's members unrolled into our request list. + * This is needed for the case when the user says + * + * SELECT * INTO :mystruct FROM ... + * or + * SELECT a.*, b.* INTO :struct_a, :struct_b FROM a, b ... + * + * Just in case, implement it recursively. + */ + void + add_struct_to_head(struct arguments ** list, struct variable * var, struct variable * ind) + { + struct ECPGstruct_member *member; + struct ECPGstruct_member *ind_member = NULL; + bool no_ind; + + if (var->type->type != ECPGt_struct) + mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is not a struct", var->name); + + no_ind = (ind == &no_indicator); + + if (!no_ind && ind->type->type != ECPGt_struct) + mmerror(INDICATOR_NOT_STRUCT, ET_FATAL, "struct variable \"%s\" was associated with a non-struct indicator variable", var->name); + + member = var->type->u.members; + if (!no_ind) + ind_member = ind->type->u.members; + + while (member && (no_ind || ind_member)) + { + char *newvarname; + char *newindname; + struct variable *newvar; + struct variable *newind = &no_indicator; + + newvarname = mm_alloc(strlen(var->name) + strlen(member->name) + 2); + sprintf(newvarname, "%s.%s", var->name, member->name); + newvar = find_variable(newvarname); + if (newvar == NULL) + mmerror(PARSE_ERROR, ET_FATAL, "internal error: variable \"%s\" is not found", newvarname); + + if (!no_ind) + { + newindname = mm_alloc(strlen(ind->name) + strlen(ind_member->name) + 2); + sprintf(newindname, "%s.%s", ind->name, ind_member->name); + newind = find_variable(newindname); + if (newind == NULL) + mmerror(PARSE_ERROR, ET_FATAL, "internal error: variable \"%s\" is not found", newvarname); + } + + switch (newvar->type->type) + { + case ECPGt_struct: + add_struct_to_head(list, newvar, newind); + break; + case ECPGt_union: + mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is a union", newvarname); + break; + default: + add_variable_to_head(list, newvar, newind); + break; + } + free(newvarname); + + member = member->next; + if (!no_ind) + ind_member = ind_member->next; + } + + if (member != NULL && !no_ind && ind_member == NULL) + mmerror(PARSE_ERROR, ET_FATAL, "indicator struct has less members than variable struct"); + } + /* Append a new variable to our request list. */ void add_variable_to_tail(struct arguments ** list, struct variable * var, struct variable * ind)
pgsql-hackers by date: