Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1o835P-0001Lz-8F for pgsql-hackers@arkaria.postgresql.org; Sun, 03 Jul 2022 17:08:43 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1o835O-00085R-1w for pgsql-hackers@arkaria.postgresql.org; Sun, 03 Jul 2022 17:08:42 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1o835N-00085I-GF for pgsql-hackers@lists.postgresql.org; Sun, 03 Jul 2022 17:08:41 +0000 Received: from sss.pgh.pa.us ([66.207.139.130]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1o835K-00030J-8U; Sun, 03 Jul 2022 17:08:40 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.15.2/8.15.2) with ESMTP id 263H8a651277984; Sun, 3 Jul 2022 13:08:36 -0400 From: Tom Lane To: Noah Misch cc: Michael Meskes , pgsql-hackers@lists.postgresql.org Subject: Re: SQL/JSON functions vs. ECPG vs. STRING as a reserved word In-reply-to: <20220703080127.GA2476530@rfd.leadboat.com> References: <3661437.1653855582@sss.pgh.pa.us> <4158666.1653945615@sss.pgh.pa.us> <20220703080127.GA2476530@rfd.leadboat.com> Comments: In-reply-to Noah Misch message dated "Sun, 03 Jul 2022 01:01:27 -0700" MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <1277937.1656868088.0@sss.pgh.pa.us> Date: Sun, 03 Jul 2022 13:08:36 -0400 Message-ID: <1277983.1656868116@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk ------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <1277937.1656868088.1@sss.pgh.pa.us> Content-Transfer-Encoding: quoted-printable Noah Misch writes: > On Mon, May 30, 2022 at 05:20:15PM -0400, Tom Lane wrote: >> [allow EXEC SQL TYPE unreserved_keyword IS ...] > I didn't locate any problems beyond the test and doc gaps that you menti= oned, > so I've marked this Ready for Committer. Thanks! Here's a fleshed-out version with doc changes, plus adjustment of preproc/type.pgc so that it exposes the existing problem. (No code changes from v1.) I'll push this in a few days if there are not objections. regards, tom lane ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="handle-unreserved-typedef-names-2.patch"; charset="us-ascii" Content-ID: <1277937.1656868088.2@sss.pgh.pa.us> Content-Description: handle-unreserved-typedef-names-2.patch Content-Transfer-Encoding: quoted-printable diff --git a/doc/src/sgml/ecpg.sgml b/doc/src/sgml/ecpg.sgml index 7f8b4dd5c0..0ba1bf93a6 100644 --- a/doc/src/sgml/ecpg.sgml +++ b/doc/src/sgml/ecpg.sgml @@ -1483,6 +1483,10 @@ EXEC SQL END DECLARE SECTION; = Typedefs + + typedef + in ECPG + = Use the typedef keyword to map new types to alre= ady @@ -1497,8 +1501,38 @@ EXEC SQL END DECLARE SECTION; EXEC SQL TYPE serial_t IS long; - This declaration does not need to be part of a declare section. + This declaration does not need to be part of a declare section; + that is, you can also write typedefs as normal C statements. + + + Any word you declare as a typedef cannot be used as a SQL keyword + in EXEC SQL commands later in the same program. + For example, this won't work: + +EXEC SQL BEGIN DECLARE SECTION; + typedef int start; +EXEC SQL END DECLARE SECTION; +... +EXEC SQL START TRANSACTION; + + ECPG will report a syntax error for START + TRANSACTION, because it no longer + recognizes START as a SQL keyword, + only as a typedef. + + + + + In PostgreSQL releases before v16, use + of SQL keywords as typedef names was likely to result in syntax + errors associated with use of the typedef itself, rather than use + of the name as a SQL keyword. The new behavior is less likely to + cause problems when an existing ECPG application is recompiled in + a new PostgreSQL release with new + keywords. + + = diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecp= g/preproc/ecpg.trailer index b95fc44314..fba35f6be6 100644 --- a/src/interfaces/ecpg/preproc/ecpg.trailer +++ b/src/interfaces/ecpg/preproc/ecpg.trailer @@ -564,8 +564,29 @@ var_type: simple_type $$.type_index =3D mm_strdup("-1"); $$.type_sizeof =3D NULL; } - | ECPGColLabelCommon '(' precision opt_scale ')' + | NUMERIC '(' precision opt_scale ')' { + $$.type_enum =3D ECPGt_numeric; + $$.type_str =3D mm_strdup("numeric"); + $$.type_dimension =3D mm_strdup("-1"); + $$.type_index =3D mm_strdup("-1"); + $$.type_sizeof =3D NULL; + } + | DECIMAL_P '(' precision opt_scale ')' + { + $$.type_enum =3D ECPGt_decimal; + $$.type_str =3D mm_strdup("decimal"); + $$.type_dimension =3D mm_strdup("-1"); + $$.type_index =3D mm_strdup("-1"); + $$.type_sizeof =3D NULL; + } + | IDENT '(' precision opt_scale ')' + { + /* + * In C parsing mode, NUMERIC and DECIMAL are not keywords, so + * they will show up here as a plain identifier, and we need + * this duplicate code to recognize them. + */ if (strcmp($1, "numeric") =3D=3D 0) { $$.type_enum =3D ECPGt_numeric; @@ -587,15 +608,98 @@ var_type: simple_type $$.type_index =3D mm_strdup("-1"); $$.type_sizeof =3D NULL; } - | ECPGColLabelCommon ecpg_interval + | VARCHAR { - if (strlen($2) !=3D 0 && strcmp ($1, "datetime") !=3D 0 && strcmp ($1,= "interval") !=3D 0) - mmerror (PARSE_ERROR, ET_ERROR, "interval specification not allowed h= ere"); + $$.type_enum =3D ECPGt_varchar; + $$.type_str =3D EMPTY; /*mm_strdup("varchar");*/ + $$.type_dimension =3D mm_strdup("-1"); + $$.type_index =3D mm_strdup("-1"); + $$.type_sizeof =3D NULL; + } + | FLOAT_P + { + /* Note: DOUBLE is handled in simple_type */ + $$.type_enum =3D ECPGt_float; + $$.type_str =3D mm_strdup("float"); + $$.type_dimension =3D mm_strdup("-1"); + $$.type_index =3D mm_strdup("-1"); + $$.type_sizeof =3D NULL; + } + | NUMERIC + { + $$.type_enum =3D ECPGt_numeric; + $$.type_str =3D mm_strdup("numeric"); + $$.type_dimension =3D mm_strdup("-1"); + $$.type_index =3D mm_strdup("-1"); + $$.type_sizeof =3D NULL; + } + | DECIMAL_P + { + $$.type_enum =3D ECPGt_decimal; + $$.type_str =3D mm_strdup("decimal"); + $$.type_dimension =3D mm_strdup("-1"); + $$.type_index =3D mm_strdup("-1"); + $$.type_sizeof =3D NULL; + } + | TIMESTAMP + { + $$.type_enum =3D ECPGt_timestamp; + $$.type_str =3D mm_strdup("timestamp"); + $$.type_dimension =3D mm_strdup("-1"); + $$.type_index =3D mm_strdup("-1"); + $$.type_sizeof =3D NULL; + } + | INTERVAL ecpg_interval + { + $$.type_enum =3D ECPGt_interval; + $$.type_str =3D mm_strdup("interval"); + $$.type_dimension =3D mm_strdup("-1"); + $$.type_index =3D mm_strdup("-1"); + $$.type_sizeof =3D NULL; + } + | STRING + { + if (INFORMIX_MODE) + { + /* In Informix mode, "string" is automatically a typedef */ + $$.type_enum =3D ECPGt_string; + $$.type_str =3D mm_strdup("char"); + $$.type_dimension =3D mm_strdup("-1"); + $$.type_index =3D mm_strdup("-1"); + $$.type_sizeof =3D NULL; + } + else + { + /* Otherwise, legal only if user typedef'ed it */ + struct typedefs *this =3D get_typedef("string", false); + + $$.type_str =3D (this->type->type_enum =3D=3D ECPGt_varchar || this->= type->type_enum =3D=3D ECPGt_bytea) ? EMPTY : mm_strdup(this->name); + $$.type_enum =3D this->type->type_enum; + $$.type_dimension =3D this->type->type_dimension; + $$.type_index =3D this->type->type_index; + if (this->type->type_sizeof && strlen(this->type->type_sizeof) !=3D 0= ) + $$.type_sizeof =3D this->type->type_sizeof; + else + $$.type_sizeof =3D cat_str(3, mm_strdup("sizeof("), mm_strdup(this->= name), mm_strdup(")")); = + struct_member_list[struct_level] =3D ECPGstruct_member_dup(this->stru= ct_member_list); + } + } + | IDENT ecpg_interval + { /* - * Check for type names that the SQL grammar treats as - * unreserved keywords + * In C parsing mode, the above SQL type names are not keywords, + * so they will show up here as a plain identifier, and we need + * this duplicate code to recognize them. + * + * Note that we also handle the type names bytea, date, and + * datetime here, but not above because those are not currently + * SQL keywords. If they ever become so, they must gain duplicate + * productions above. */ + if (strlen($2) !=3D 0 && strcmp ($1, "datetime") !=3D 0 && strcmp ($1,= "interval") !=3D 0) + mmerror (PARSE_ERROR, ET_ERROR, "interval specification not allowed h= ere"); + if (strcmp($1, "varchar") =3D=3D 0) { $$.type_enum =3D ECPGt_varchar; @@ -686,45 +790,8 @@ var_type: simple_type } else { - /* this is for typedef'ed types */ - struct typedefs *this =3D get_typedef($1); - - $$.type_str =3D (this->type->type_enum =3D=3D ECPGt_varchar || this->= type->type_enum =3D=3D ECPGt_bytea) ? EMPTY : mm_strdup(this->name); - $$.type_enum =3D this->type->type_enum; - $$.type_dimension =3D this->type->type_dimension; - $$.type_index =3D this->type->type_index; - if (this->type->type_sizeof && strlen(this->type->type_sizeof) !=3D 0= ) - $$.type_sizeof =3D this->type->type_sizeof; - else - $$.type_sizeof =3D cat_str(3, mm_strdup("sizeof("), mm_strdup(this->= name), mm_strdup(")")); - - struct_member_list[struct_level] =3D ECPGstruct_member_dup(this->stru= ct_member_list); - } - } - | STRING - { - /* - * It's quite horrid that ECPGColLabelCommon excludes - * unreserved_keyword, meaning that unreserved keywords can't be - * used as type names in var_type. However, this is hard to avoid - * since what follows ecpgstart can be either a random SQL - * statement or an ECPGVarDeclaration (beginning with var_type). - * Pending a bright idea about how to fix that, we must - * special-case STRING (and any other unreserved keywords that are - * likely to be needed here). - */ - if (INFORMIX_MODE) - { - $$.type_enum =3D ECPGt_string; - $$.type_str =3D mm_strdup("char"); - $$.type_dimension =3D mm_strdup("-1"); - $$.type_index =3D mm_strdup("-1"); - $$.type_sizeof =3D NULL; - } - else - { - /* this is for typedef'ed types */ - struct typedefs *this =3D get_typedef("string"); + /* Otherwise, it must be a user-defined typedef name */ + struct typedefs *this =3D get_typedef($1, false); = $$.type_str =3D (this->type->type_enum =3D=3D ECPGt_varchar || this->= type->type_enum =3D=3D ECPGt_bytea) ? EMPTY : mm_strdup(this->name); $$.type_enum =3D this->type->type_enum; @@ -751,7 +818,7 @@ var_type: simple_type { /* No */ = - this =3D get_typedef(name); + this =3D get_typedef(name, false); $$.type_str =3D mm_strdup(this->name); $$.type_enum =3D this->type->type_enum; $$.type_dimension =3D this->type->type_dimension; @@ -1657,17 +1724,14 @@ ColLabel: ECPGColLabel { $$ =3D $1; } | ECPGunreserved_interval { $$ =3D $1; } ; = -ECPGColLabel: ECPGColLabelCommon { $$ =3D $1; } +ECPGColLabel: ecpg_ident { $$ =3D $1; } | unreserved_keyword { $$ =3D $1; } - | reserved_keyword { $$ =3D $1; } - | ECPGKeywords_rest { $$ =3D $1; } - | CONNECTION { $$ =3D mm_strdup("connection"); } - ; - -ECPGColLabelCommon: ecpg_ident { $$ =3D $1; } | col_name_keyword { $$ =3D $1; } | type_func_name_keyword { $$ =3D $1; } + | reserved_keyword { $$ =3D $1; } | ECPGKeywords_vanames { $$ =3D $1; } + | ECPGKeywords_rest { $$ =3D $1; } + | CONNECTION { $$ =3D mm_strdup("connection"); } ; = ECPGCKeywords: S_AUTO { $$ =3D mm_strdup("auto"); } diff --git a/src/interfaces/ecpg/preproc/ecpg.type b/src/interfaces/ecpg/p= reproc/ecpg.type index d1cde691c0..4fe80a5a4b 100644 --- a/src/interfaces/ecpg/preproc/ecpg.type +++ b/src/interfaces/ecpg/preproc/ecpg.type @@ -3,7 +3,6 @@ %type ECPGCKeywords %type ECPGColId %type ECPGColLabel -%type ECPGColLabelCommon %type ECPGConnect %type ECPGCursorStmt %type ECPGDeallocateDescr diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/prepr= oc/pgc.l index 996718cb8a..c344f8f30f 100644 --- a/src/interfaces/ecpg/preproc/pgc.l +++ b/src/interfaces/ecpg/preproc/pgc.l @@ -983,10 +983,19 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifnd= ef}|{import})((\/\*[^*/]*\*+ { int kwvalue; = - /* Is it an SQL/ECPG keyword? */ - kwvalue =3D ScanECPGKeywordLookup(yytext); - if (kwvalue >=3D 0) - return kwvalue; + /* + * User-defined typedefs override SQL keywords, but + * not C keywords. Currently, a typedef name is just + * reported as IDENT, but someday we might need to + * return a distinct token type. + */ + if (get_typedef(yytext, true) =3D=3D NULL) + { + /* Is it an SQL/ECPG keyword? */ + kwvalue =3D ScanECPGKeywordLookup(yytext); + if (kwvalue >=3D 0) + return kwvalue; + } = /* Is it a C keyword? */ kwvalue =3D ScanCKeywordLookup(yytext); diff --git a/src/interfaces/ecpg/preproc/preproc_extern.h b/src/interfaces= /ecpg/preproc/preproc_extern.h index 992797b8bb..6be59b7193 100644 --- a/src/interfaces/ecpg/preproc/preproc_extern.h +++ b/src/interfaces/ecpg/preproc/preproc_extern.h @@ -93,7 +93,7 @@ extern void add_variable_to_head(struct arguments **, st= ruct variable *, struct extern void add_variable_to_tail(struct arguments **, struct variable *, = struct variable *); extern void remove_variable_from_list(struct arguments **list, struct var= iable *var); extern void dump_variables(struct arguments *, int); -extern struct typedefs *get_typedef(char *); +extern struct typedefs *get_typedef(const char *name, bool noerror); extern void adjust_array(enum ECPGttype, char **, char **, char *, char *= , int, bool); extern void reset_variables(void); extern void check_indicator(struct ECPGtype *); diff --git a/src/interfaces/ecpg/preproc/variable.c b/src/interfaces/ecpg/= preproc/variable.c index 887d479e73..2a2b953118 100644 --- a/src/interfaces/ecpg/preproc/variable.c +++ b/src/interfaces/ecpg/preproc/variable.c @@ -497,15 +497,20 @@ check_indicator(struct ECPGtype *var) } = struct typedefs * -get_typedef(char *name) +get_typedef(const char *name, bool noerror) { struct typedefs *this; = - for (this =3D types; this && strcmp(this->name, name) !=3D 0; this =3D t= his->next); - if (!this) + for (this =3D types; this !=3D NULL; this =3D this->next) + { + if (strcmp(this->name, name) =3D=3D 0) + return this; + } + + if (!noerror) mmfatal(PARSE_ERROR, "unrecognized data type name \"%s\"", name); = - return this; + return NULL; } = void diff --git a/src/interfaces/ecpg/test/expected/preproc-type.c b/src/interf= aces/ecpg/test/expected/preproc-type.c index 1968a87574..9323cb66f8 100644 --- a/src/interfaces/ecpg/test/expected/preproc-type.c +++ b/src/interfaces/ecpg/test/expected/preproc-type.c @@ -33,20 +33,26 @@ typedef char mmChar ; = #line 7 "type.pgc" = -typedef short mmSmallInt ; +typedef short access ; = #line 8 "type.pgc" = #line 8 "type.pgc" + /* matches an unreserved SQL keyword */ +typedef access access_renamed ; + +#line 9 "type.pgc" + +#line 9 "type.pgc" = = /* exec sql type string is char [ 11 ] */ -#line 10 "type.pgc" +#line 11 "type.pgc" = typedef char string[11]; = /* exec sql type c is char reference */ -#line 13 "type.pgc" +#line 14 "type.pgc" = typedef char* c; = @@ -58,16 +64,16 @@ typedef char* c; = = struct TBempl { = -#line 19 "type.pgc" +#line 20 "type.pgc" mmInteger idnum ; = -#line 20 "type.pgc" +#line 21 "type.pgc" mmChar name [ 21 ] ; = -#line 21 "type.pgc" - mmSmallInt accs ; +#line 22 "type.pgc" + access accs ; } ;/* exec sql end declare section */ -#line 23 "type.pgc" +#line 24 "type.pgc" = = int @@ -77,41 +83,45 @@ main (void) = = = + = = = = = = = -#line 29 "type.pgc" +#line 30 "type.pgc" struct TBempl empl ; = -#line 30 "type.pgc" +#line 31 "type.pgc" string str ; = -#line 31 "type.pgc" +#line 32 "type.pgc" + access accs_val =3D 320 ; + = +#line 33 "type.pgc" c ptr =3D NULL ; = -#line 36 "type.pgc" +#line 38 "type.pgc" struct varchar { = -#line 34 "type.pgc" +#line 36 "type.pgc" int len ; = -#line 35 "type.pgc" +#line 37 "type.pgc" char text [ 10 ] ; } vc ; /* exec sql end declare section */ -#line 37 "type.pgc" +#line 39 "type.pgc" = = /* exec sql var vc is [ 10 ] */ -#line 39 "type.pgc" +#line 41 "type.pgc" = ECPGdebug (1, stderr); = empl.idnum =3D 1; { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); = } -#line 43 "type.pgc" +#line 45 "type.pgc" = if (sqlca.sqlcode) { @@ -120,7 +130,7 @@ main (void) } = { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table empl ( i= dnum integer , name char ( 20 ) , accs smallint , string1 char ( 10 ) , st= ring2 char ( 10 ) , string3 char ( 10 ) )", ECPGt_EOIT, ECPGt_EORT);} -#line 51 "type.pgc" +#line 53 "type.pgc" = if (sqlca.sqlcode) { @@ -128,8 +138,10 @@ main (void) exit (sqlca.sqlcode); } = - { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into empl valu= es ( 1 , 'user name' , 320 , 'first str' , 'second str' , 'third str' )", = ECPGt_EOIT, ECPGt_EORT);} -#line 58 "type.pgc" + { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into empl valu= es ( 1 , 'user name' , $1 , 'first str' , 'second str' , 'third str' )", = + ECPGt_short,&(accs_val),(long)1,(long)1,sizeof(short), = + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);} +#line 60 "type.pgc" = if (sqlca.sqlcode) { @@ -152,7 +164,7 @@ main (void) ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, = ECPGt_varchar,&(vc),(long)10,(long)1,sizeof(struct varchar), = ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);} -#line 68 "type.pgc" +#line 70 "type.pgc" = if (sqlca.sqlcode) { @@ -162,7 +174,7 @@ main (void) printf ("id=3D%ld name=3D'%s' accs=3D%d str=3D'%s' ptr=3D'%s' vc=3D'%10= .10s'\n", empl.idnum, empl.name, empl.accs, str, ptr, vc.text); = { ECPGdisconnect(__LINE__, "CURRENT");} -#line 76 "type.pgc" +#line 78 "type.pgc" = = free(ptr); diff --git a/src/interfaces/ecpg/test/expected/preproc-type.stderr b/src/i= nterfaces/ecpg/test/expected/preproc-type.stderr index 678eceff70..85e3094ed5 100644 --- a/src/interfaces/ecpg/test/expected/preproc-type.stderr +++ b/src/interfaces/ecpg/test/expected/preproc-type.stderr @@ -2,39 +2,41 @@ [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database ecpg1_regression on por= t = [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 50: query: create table empl ( idnum integ= er , name char ( 20 ) , accs smallint , string1 char ( 10 ) , string2 char= ( 10 ) , string3 char ( 10 ) ); with 0 parameter(s) on connection ecpg1_r= egression +[NO_PID]: ecpg_execute on line 52: query: create table empl ( idnum integ= er , name char ( 20 ) , accs smallint , string1 char ( 10 ) , string2 char= ( 10 ) , string3 char ( 10 ) ); with 0 parameter(s) on connection ecpg1_r= egression [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 50: using PQexec +[NO_PID]: ecpg_execute on line 52: using PQexec [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_process_output on line 50: OK: CREATE TABLE +[NO_PID]: ecpg_process_output on line 52: OK: CREATE TABLE [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 58: query: insert into empl values ( 1 , '= user name' , 320 , 'first str' , 'second str' , 'third str' ); with 0 para= meter(s) on connection ecpg1_regression +[NO_PID]: ecpg_execute on line 60: query: insert into empl values ( 1 , '= user name' , $1 , 'first str' , 'second str' , 'third str' ); with 1 para= meter(s) on connection ecpg1_regression [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 58: using PQexec +[NO_PID]: ecpg_execute on line 60: using PQexecParams [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_process_output on line 58: OK: INSERT 0 1 +[NO_PID]: ecpg_free_params on line 60: parameter 1 =3D 320 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 65: query: select idnum , name , accs , st= ring1 , string2 , string3 from empl where idnum =3D $1 ; with 1 parameter(= s) on connection ecpg1_regression +[NO_PID]: ecpg_process_output on line 60: OK: INSERT 0 1 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 65: using PQexecParams +[NO_PID]: ecpg_execute on line 67: query: select idnum , name , accs , st= ring1 , string2 , string3 from empl where idnum =3D $1 ; with 1 parameter(= s) on connection ecpg1_regression [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_free_params on line 65: parameter 1 =3D 1 +[NO_PID]: ecpg_execute on line 67: using PQexecParams [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_process_output on line 65: correctly got 1 tuples with 6 f= ields +[NO_PID]: ecpg_free_params on line 67: parameter 1 =3D 1 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_get_data on line 65: RESULT: 1 offset: -1; array: no +[NO_PID]: ecpg_process_output on line 67: correctly got 1 tuples with 6 f= ields [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_get_data on line 65: RESULT: user name offset: = -1; array: no +[NO_PID]: ecpg_get_data on line 67: RESULT: 1 offset: -1; array: no [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_get_data on line 65: RESULT: 320 offset: -1; array: no +[NO_PID]: ecpg_get_data on line 67: RESULT: user name offset: = -1; array: no [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_get_data on line 65: RESULT: first str offset: -1; array:= no +[NO_PID]: ecpg_get_data on line 67: RESULT: 320 offset: -1; array: no [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_store_result on line 65: allocating memory for 1 tuples +[NO_PID]: ecpg_get_data on line 67: RESULT: first str offset: -1; array:= no [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_get_data on line 65: RESULT: second str offset: -1; array:= no +[NO_PID]: ecpg_store_result on line 67: allocating memory for 1 tuples [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_get_data on line 65: RESULT: third str offset: -1; array:= no +[NO_PID]: ecpg_get_data on line 67: RESULT: second str offset: -1; array:= no +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_get_data on line 67: RESULT: third str offset: -1; array:= no [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection ecpg1_regression closed [NO_PID]: sqlca: code: 0, state: 00000 diff --git a/src/interfaces/ecpg/test/preproc/type.pgc b/src/interfaces/ec= pg/test/preproc/type.pgc index 3200c91dc2..12459ccde8 100644 --- a/src/interfaces/ecpg/test/preproc/type.pgc +++ b/src/interfaces/ecpg/test/preproc/type.pgc @@ -5,7 +5,8 @@ EXEC SQL include ../regression; = EXEC SQL typedef long mmInteger; EXEC SQL typedef char mmChar; -EXEC SQL typedef short mmSmallInt; +EXEC SQL typedef short access; /* matches an unreserved SQL keyword */ +EXEC SQL typedef access access_renamed; = exec sql type string is char[11]; typedef char string[11]; @@ -18,7 +19,7 @@ struct TBempl { mmInteger idnum; mmChar name[21]; - mmSmallInt accs; + access accs; }; EXEC SQL END DECLARE SECTION; = @@ -28,6 +29,7 @@ main (void) EXEC SQL BEGIN DECLARE SECTION; struct TBempl empl; string str; + access accs_val =3D 320; c ptr =3D NULL; struct varchar { @@ -55,7 +57,7 @@ main (void) exit (sqlca.sqlcode); } = - EXEC SQL insert into empl values (1, 'user name', 320, 'first str', 'se= cond str', 'third str'); + EXEC SQL insert into empl values (1, 'user name', :accs_val, 'first str= ', 'second str', 'third str'); if (sqlca.sqlcode) { printf ("insert error =3D %ld\n", sqlca.sqlcode); ------- =_aaaaaaaaaa0--