Re: SQL/JSON functions vs. ECPG vs. STRING as a reserved word - Mailing list pgsql-hackers
From | Tom Lane |
---|---|
Subject | Re: SQL/JSON functions vs. ECPG vs. STRING as a reserved word |
Date | |
Msg-id | 1277983.1656868116@sss.pgh.pa.us Whole thread Raw |
In response to | SQL/JSON functions vs. ECPG vs. STRING as a reserved word (Tom Lane <tgl@sss.pgh.pa.us>) |
List | pgsql-hackers |
Noah Misch <noah@leadboat.com> 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 mentioned, > 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 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; <sect4> <title>Typedefs</title> + <indexterm> + <primary>typedef</primary> + <secondary>in ECPG</secondary> + </indexterm> <para> Use the <literal>typedef</literal> keyword to map new types to already @@ -1497,8 +1501,38 @@ EXEC SQL END DECLARE SECTION; <programlisting> EXEC SQL TYPE serial_t IS long; </programlisting> - 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. </para> + + <para> + Any word you declare as a typedef cannot be used as a SQL keyword + in <literal>EXEC SQL</literal> commands later in the same program. + For example, this won't work: +<programlisting> +EXEC SQL BEGIN DECLARE SECTION; + typedef int start; +EXEC SQL END DECLARE SECTION; +... +EXEC SQL START TRANSACTION; +</programlisting> + ECPG will report a syntax error for <literal>START + TRANSACTION</literal>, because it no longer + recognizes <literal>START</literal> as a SQL keyword, + only as a typedef. + </para> + + <note> + <para> + In <productname>PostgreSQL</productname> 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 <productname>PostgreSQL</productname> release with new + keywords. + </para> + </note> </sect4> <sect4> diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/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 = mm_strdup("-1"); $$.type_sizeof = NULL; } - | ECPGColLabelCommon '(' precision opt_scale ')' + | NUMERIC '(' precision opt_scale ')' { + $$.type_enum = ECPGt_numeric; + $$.type_str = mm_strdup("numeric"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | DECIMAL_P '(' precision opt_scale ')' + { + $$.type_enum = ECPGt_decimal; + $$.type_str = mm_strdup("decimal"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = 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") == 0) { $$.type_enum = ECPGt_numeric; @@ -587,15 +608,98 @@ var_type: simple_type $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - | ECPGColLabelCommon ecpg_interval + | VARCHAR { - if (strlen($2) != 0 && strcmp ($1, "datetime") != 0 && strcmp ($1, "interval") != 0) - mmerror (PARSE_ERROR, ET_ERROR, "interval specification not allowed here"); + $$.type_enum = ECPGt_varchar; + $$.type_str = EMPTY; /*mm_strdup("varchar");*/ + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | FLOAT_P + { + /* Note: DOUBLE is handled in simple_type */ + $$.type_enum = ECPGt_float; + $$.type_str = mm_strdup("float"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | NUMERIC + { + $$.type_enum = ECPGt_numeric; + $$.type_str = mm_strdup("numeric"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | DECIMAL_P + { + $$.type_enum = ECPGt_decimal; + $$.type_str = mm_strdup("decimal"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | TIMESTAMP + { + $$.type_enum = ECPGt_timestamp; + $$.type_str = mm_strdup("timestamp"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | INTERVAL ecpg_interval + { + $$.type_enum = ECPGt_interval; + $$.type_str = mm_strdup("interval"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | STRING + { + if (INFORMIX_MODE) + { + /* In Informix mode, "string" is automatically a typedef */ + $$.type_enum = ECPGt_string; + $$.type_str = mm_strdup("char"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + else + { + /* Otherwise, legal only if user typedef'ed it */ + struct typedefs *this = get_typedef("string", false); + + $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY :mm_strdup(this->name); + $$.type_enum = this->type->type_enum; + $$.type_dimension = this->type->type_dimension; + $$.type_index = this->type->type_index; + if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0) + $$.type_sizeof = this->type->type_sizeof; + else + $$.type_sizeof = cat_str(3, mm_strdup("sizeof("), mm_strdup(this->name), mm_strdup(")")); + struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_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) != 0 && strcmp ($1, "datetime") != 0 && strcmp ($1, "interval") != 0) + mmerror (PARSE_ERROR, ET_ERROR, "interval specification not allowed here"); + if (strcmp($1, "varchar") == 0) { $$.type_enum = ECPGt_varchar; @@ -686,45 +790,8 @@ var_type: simple_type } else { - /* this is for typedef'ed types */ - struct typedefs *this = get_typedef($1); - - $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY :mm_strdup(this->name); - $$.type_enum = this->type->type_enum; - $$.type_dimension = this->type->type_dimension; - $$.type_index = this->type->type_index; - if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0) - $$.type_sizeof = this->type->type_sizeof; - else - $$.type_sizeof = cat_str(3, mm_strdup("sizeof("), mm_strdup(this->name), mm_strdup(")")); - - struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_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 = ECPGt_string; - $$.type_str = mm_strdup("char"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = NULL; - } - else - { - /* this is for typedef'ed types */ - struct typedefs *this = get_typedef("string"); + /* Otherwise, it must be a user-defined typedef name */ + struct typedefs *this = get_typedef($1, false); $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY :mm_strdup(this->name); $$.type_enum = this->type->type_enum; @@ -751,7 +818,7 @@ var_type: simple_type { /* No */ - this = get_typedef(name); + this = get_typedef(name, false); $$.type_str = mm_strdup(this->name); $$.type_enum = this->type->type_enum; $$.type_dimension = this->type->type_dimension; @@ -1657,17 +1724,14 @@ ColLabel: ECPGColLabel { $$ = $1; } | ECPGunreserved_interval { $$ = $1; } ; -ECPGColLabel: ECPGColLabelCommon { $$ = $1; } +ECPGColLabel: ecpg_ident { $$ = $1; } | unreserved_keyword { $$ = $1; } - | reserved_keyword { $$ = $1; } - | ECPGKeywords_rest { $$ = $1; } - | CONNECTION { $$ = mm_strdup("connection"); } - ; - -ECPGColLabelCommon: ecpg_ident { $$ = $1; } | col_name_keyword { $$ = $1; } | type_func_name_keyword { $$ = $1; } + | reserved_keyword { $$ = $1; } | ECPGKeywords_vanames { $$ = $1; } + | ECPGKeywords_rest { $$ = $1; } + | CONNECTION { $$ = mm_strdup("connection"); } ; ECPGCKeywords: S_AUTO { $$ = mm_strdup("auto"); } diff --git a/src/interfaces/ecpg/preproc/ecpg.type b/src/interfaces/ecpg/preproc/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 <str> ECPGCKeywords %type <str> ECPGColId %type <str> ECPGColLabel -%type <str> ECPGColLabelCommon %type <str> ECPGConnect %type <str> ECPGCursorStmt %type <str> ECPGDeallocateDescr diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/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}|{ifndef}|{import})((\/\*[^*/]*\*+ { int kwvalue; - /* Is it an SQL/ECPG keyword? */ - kwvalue = ScanECPGKeywordLookup(yytext); - if (kwvalue >= 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) == NULL) + { + /* Is it an SQL/ECPG keyword? */ + kwvalue = ScanECPGKeywordLookup(yytext); + if (kwvalue >= 0) + return kwvalue; + } /* Is it a C keyword? */ kwvalue = 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 **, struct variable *, struct 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); -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 = types; this && strcmp(this->name, name) != 0; this = this->next); - if (!this) + for (this = types; this != NULL; this = this->next) + { + if (strcmp(this->name, name) == 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/interfaces/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 = 320 ; + +#line 33 "type.pgc" c ptr = 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 = 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 ( idnum integer , name char ( 20 ) , accs smallint, string1 char ( 10 ) , string2 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 values ( 1 , 'user name' , 320 , 'first str' , 'secondstr' , 'third str' )", ECPGt_EOIT, ECPGt_EORT);} -#line 58 "type.pgc" + { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into empl values ( 1 , 'user name' , $1 , 'first str' , 'secondstr' , '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=%ld name='%s' accs=%d str='%s' ptr='%s' vc='%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/interfaces/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 <DEFAULT> port <DEFAULT> [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 50: query: create table empl ( idnum integer , name char ( 20 ) , accs smallint , string1char ( 10 ) , string2 char ( 10 ) , string3 char ( 10 ) ); with 0 parameter(s) on connection ecpg1_regression +[NO_PID]: ecpg_execute on line 52: query: create table empl ( idnum integer , name char ( 20 ) , accs smallint , string1char ( 10 ) , string2 char ( 10 ) , string3 char ( 10 ) ); with 0 parameter(s) on connection ecpg1_regression [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 parameter(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 parameter(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 = 320 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 65: query: select idnum , name , accs , string1 , string2 , string3 from empl where idnum= $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 , string1 , string2 , string3 from empl where idnum= $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 = 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 fields +[NO_PID]: ecpg_free_params on line 67: parameter 1 = 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 fields [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/ecpg/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 = 320; c ptr = NULL; struct varchar { @@ -55,7 +57,7 @@ main (void) exit (sqlca.sqlcode); } - EXEC SQL insert into empl values (1, 'user name', 320, 'first str', 'second 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 = %ld\n", sqlca.sqlcode);
pgsql-hackers by date: