Added typedef patches and a new option '-c' to automatically create C typedefs from SQL ones.

This commit is contained in:
Michael Meskes 2002-03-21 09:42:52 +00:00
parent a13ddd36b0
commit 73b92d10c6
6 changed files with 123 additions and 35 deletions

View File

@ -1225,6 +1225,12 @@ Wed Mar 6 10:40:28 CET 2002
Sun Mar 10 13:08:22 CET 2002 Sun Mar 10 13:08:22 CET 2002
- Fixed two bugs in define command in lexer. - Fixed two bugs in define command in lexer.
Thu Mar 21 08:25:08 CET 2002
- Applied patch by Nicolas Bazin <nbazin@ingenico.com.au> for improved
typedef handling.
- Added option '-c' to automatically create C typedef from SQL one.
- Set ecpg version to 2.10.0. - Set ecpg version to 2.10.0.
- Set library version to 3.4.0. - Set library version to 3.4.0.

View File

@ -36,6 +36,7 @@ static ScanKeyword ScanKeywords[] = {
{"signed", SQL_SIGNED}, {"signed", SQL_SIGNED},
{"static", S_STATIC}, {"static", S_STATIC},
{"struct", SQL_STRUCT}, {"struct", SQL_STRUCT},
{"typedef", S_TYPEDEF},
{"union", UNION}, {"union", UNION},
{"unsigned", SQL_UNSIGNED}, {"unsigned", SQL_UNSIGNED},
{"varchar", VARCHAR}, {"varchar", VARCHAR},

View File

@ -1,4 +1,4 @@
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/ecpg.c,v 1.53 2002/01/10 10:42:54 meskes Exp $ */ /* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/ecpg.c,v 1.54 2002/03/21 09:42:50 meskes Exp $ */
/* New main for ecpg, the PostgreSQL embedded SQL precompiler. */ /* New main for ecpg, the PostgreSQL embedded SQL precompiler. */
/* (C) Michael Meskes <meskes@postgresql.org> Feb 5th, 1998 */ /* (C) Michael Meskes <meskes@postgresql.org> Feb 5th, 1998 */
@ -17,7 +17,8 @@ extern char *optarg;
#include "extern.h" #include "extern.h"
int ret_value = 0, int ret_value = 0,
autocommit = 0; autocommit = false;
auto_create_c = false;
struct _include_path *include_paths = NULL; struct _include_path *include_paths = NULL;
struct cursor *cur = NULL; struct cursor *cur = NULL;
struct typedefs *types = NULL; struct typedefs *types = NULL;
@ -31,11 +32,11 @@ help(const char *progname)
/* printf is a macro some places; don't #ifdef inside its arguments */ /* printf is a macro some places; don't #ifdef inside its arguments */
#ifdef YYDEBUG #ifdef YYDEBUG
printf("Usage:\n" printf("Usage:\n"
" %s [-d] [-I DIRECTORY] [-o OUTFILE] [-t] file1 [file2...]\n\n", " %s [-d] [-I DIRECTORY] [-o OUTFILE] [-t] [-c] [-D symbol] file1 [file2...]\n\n",
progname); progname);
#else #else
printf("Usage:\n" printf("Usage:\n"
" %s [-I DIRECTORY] [-o OUTFILE] [-t] file1 [file2...]\n\n", " %s [-I DIRECTORY] [-o OUTFILE] [-t] [-c] [-D symbol] file1 [file2...]\n\n",
progname); progname);
#endif #endif
printf("Options:\n"); printf("Options:\n");
@ -45,6 +46,8 @@ help(const char *progname)
printf(" -I DIRECTORY search DIRECTORY for include files\n"); printf(" -I DIRECTORY search DIRECTORY for include files\n");
printf(" -o OUTFILE write result to OUTFILE\n"); printf(" -o OUTFILE write result to OUTFILE\n");
printf(" -t turn on autocommit of transactions\n"); printf(" -t turn on autocommit of transactions\n");
printf(" -c automatically generate C code from embedded SQL code\n currently this works for EXEC SQL TYPE\n");
printf(" -D symbol define symbo\n");
printf("\nIf no output file is specified, the name is formed by adding .c\n" printf("\nIf no output file is specified, the name is formed by adding .c\n"
"to the input file name, after stripping off .pgc if present.\n"); "to the input file name, after stripping off .pgc if present.\n");
printf("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"); printf("\nReport bugs to <pgsql-bugs@postgresql.org>.\n");
@ -58,6 +61,7 @@ add_include_path(char *path)
include_paths = mm_alloc(sizeof(struct _include_path)); include_paths = mm_alloc(sizeof(struct _include_path));
include_paths->path = path; include_paths->path = path;
include_paths->next = ip; include_paths->next = ip;
} }
static void static void
@ -107,7 +111,7 @@ main(int argc, char *const argv[])
add_include_path("/usr/local/include"); add_include_path("/usr/local/include");
add_include_path("."); add_include_path(".");
while ((c = getopt(argc, argv, "vo:I:tD:d")) != -1) while ((c = getopt(argc, argv, "vco:I:tD:d")) != -1)
{ {
switch (c) switch (c)
{ {
@ -122,13 +126,15 @@ main(int argc, char *const argv[])
add_include_path(optarg); add_include_path(optarg);
break; break;
case 't': case 't':
autocommit = 1; autocommit = true;
break; break;
case 'v': case 'v':
verbose = true; verbose = true;
break; break;
case 'c':
auto_create_c = true;
break;
case 'D': case 'D':
/* XXX not documented */
add_preprocessor_define(optarg); add_preprocessor_define(optarg);
break; break;
case 'd': case 'd':

View File

@ -11,6 +11,7 @@
extern int braces_open, extern int braces_open,
autocommit, autocommit,
auto_create_c,
ret_value, ret_value,
struct_level; struct_level;
extern char *descriptor_index; extern char *descriptor_index;

View File

@ -169,6 +169,7 @@ make_name(void)
S_DOTPOINT S_EQUAL S_EXTERN S_INC S_LSHIFT S_MEMPOINT S_DOTPOINT S_EQUAL S_EXTERN S_INC S_LSHIFT S_MEMPOINT
S_MEMBER S_MOD S_MUL S_NEQUAL S_OR S_REGISTER S_RSHIFT S_MEMBER S_MOD S_MUL S_NEQUAL S_OR S_REGISTER S_RSHIFT
S_STATIC S_SUB S_VOLATILE S_STATIC S_SUB S_VOLATILE
S_TYPEDEF
/* I need this and don't know where it is defined inside the backend */ /* I need this and don't know where it is defined inside the backend */
%token TYPECAST %token TYPECAST
@ -354,12 +355,13 @@ make_name(void)
%type <str> stmt ECPGRelease execstring server_name %type <str> stmt ECPGRelease execstring server_name
%type <str> connection_object opt_server opt_port c_stuff c_stuff_item %type <str> connection_object opt_server opt_port c_stuff c_stuff_item
%type <str> user_name opt_user char_variable ora_user ident opt_reference %type <str> user_name opt_user char_variable ora_user ident opt_reference
%type <str> quoted_ident_stringvar %type <str> quoted_ident_stringvar var_type_declarations
%type <str> db_prefix server opt_options opt_connection_name c_list %type <str> db_prefix server opt_options opt_connection_name c_list
%type <str> ECPGSetConnection cpp_line ECPGTypedef c_args ECPGKeywords %type <str> ECPGSetConnection cpp_line ECPGTypedef c_args ECPGKeywords
%type <str> enum_type civar civarind ECPGCursorStmt ECPGDeallocate %type <str> enum_type civar civarind ECPGCursorStmt ECPGDeallocate
%type <str> ECPGFree ECPGDeclare ECPGVar opt_at enum_definition %type <str> ECPGFree ECPGDeclare ECPGVar opt_at enum_definition
%type <str> struct_type s_struct declaration declarations variable_declarations %type <str> struct_type s_struct vt_declarations variable_declarations
%type <str> var_declaration type_declaration
%type <str> s_union union_type ECPGSetAutocommit on_off %type <str> s_union union_type ECPGSetAutocommit on_off
%type <str> ECPGAllocateDescr ECPGDeallocateDescr symbol opt_symbol %type <str> ECPGAllocateDescr ECPGDeallocateDescr symbol opt_symbol
%type <str> ECPGGetDescriptorHeader ECPGColLabel %type <str> ECPGGetDescriptorHeader ECPGColLabel
@ -418,7 +420,7 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); }
| AlterUserSetStmt { output_statement($1, 0, connection); } | AlterUserSetStmt { output_statement($1, 0, connection); }
| ClosePortalStmt { output_statement($1, 0, connection); } | ClosePortalStmt { output_statement($1, 0, connection); }
| CommentStmt { output_statement($1, 0, connection); } | CommentStmt { output_statement($1, 0, connection); }
| CopyStmt { output_statement($1, 0, connection); } | CopyStmt { output_statement($1, 0, connection); }
| CreateStmt { output_statement($1, 0, connection); } | CreateStmt { output_statement($1, 0, connection); }
| CreateAsStmt { output_statement($1, 0, connection); } | CreateAsStmt { output_statement($1, 0, connection); }
| CreateSchemaStmt { output_statement($1, 0, connection); } | CreateSchemaStmt { output_statement($1, 0, connection); }
@ -429,7 +431,7 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); }
| CreateUserStmt { output_statement($1, 0, connection); } | CreateUserStmt { output_statement($1, 0, connection); }
| ClusterStmt { output_statement($1, 0, connection); } | ClusterStmt { output_statement($1, 0, connection); }
| DefineStmt { output_statement($1, 0, connection); } | DefineStmt { output_statement($1, 0, connection); }
| DropStmt { output_statement($1, 0, connection); } | DropStmt { output_statement($1, 0, connection); }
| DropSchemaStmt { output_statement($1, 0, connection); } | DropSchemaStmt { output_statement($1, 0, connection); }
| TruncateStmt { output_statement($1, 0, connection); } | TruncateStmt { output_statement($1, 0, connection); }
| DropGroupStmt { output_statement($1, 0, connection); } | DropGroupStmt { output_statement($1, 0, connection); }
@ -437,12 +439,12 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); }
| DropTrigStmt { output_statement($1, 0, connection); } | DropTrigStmt { output_statement($1, 0, connection); }
| DropUserStmt { output_statement($1, 0, connection); } | DropUserStmt { output_statement($1, 0, connection); }
| ExplainStmt { output_statement($1, 0, connection); } | ExplainStmt { output_statement($1, 0, connection); }
| FetchStmt { output_statement($1, 1, connection); } | FetchStmt { output_statement($1, 1, connection); }
| GrantStmt { output_statement($1, 0, connection); } | GrantStmt { output_statement($1, 0, connection); }
| IndexStmt { output_statement($1, 0, connection); } | IndexStmt { output_statement($1, 0, connection); }
| ListenStmt { output_statement($1, 0, connection); } | ListenStmt { output_statement($1, 0, connection); }
| UnlistenStmt { output_statement($1, 0, connection); } | UnlistenStmt { output_statement($1, 0, connection); }
| LockStmt { output_statement($1, 0, connection); } | LockStmt { output_statement($1, 0, connection); }
| NotifyStmt { output_statement($1, 0, connection); } | NotifyStmt { output_statement($1, 0, connection); }
| ProcedureStmt { output_statement($1, 0, connection); } | ProcedureStmt { output_statement($1, 0, connection); }
| ReindexStmt { output_statement($1, 0, connection); } | ReindexStmt { output_statement($1, 0, connection); }
@ -458,23 +460,23 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); }
else else
output_statement($1, 1, connection); output_statement($1, 1, connection);
} }
| RuleStmt { output_statement($1, 0, connection); } | RuleStmt { output_statement($1, 0, connection); }
| TransactionStmt | TransactionStmt
{ {
fprintf(yyout, "{ ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1); fprintf(yyout, "{ ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1);
whenever_action(2); whenever_action(2);
free($1); free($1);
} }
| ViewStmt { output_statement($1, 0, connection); } | ViewStmt { output_statement($1, 0, connection); }
| LoadStmt { output_statement($1, 0, connection); } | LoadStmt { output_statement($1, 0, connection); }
| CreatedbStmt { output_statement($1, 0, connection); } | CreatedbStmt { output_statement($1, 0, connection); }
| DropdbStmt { output_statement($1, 0, connection); } | DropdbStmt { output_statement($1, 0, connection); }
| VacuumStmt { output_statement($1, 0, connection); } | VacuumStmt { output_statement($1, 0, connection); }
| AnalyzeStmt { output_statement($1, 0, connection); } | AnalyzeStmt { output_statement($1, 0, connection); }
| VariableSetStmt { output_statement($1, 0, connection); } | VariableSetStmt { output_statement($1, 0, connection); }
| VariableShowStmt { output_statement($1, 0, connection); } | VariableShowStmt { output_statement($1, 0, connection); }
| VariableResetStmt { output_statement($1, 0, connection); } | VariableResetStmt { output_statement($1, 0, connection); }
| ConstraintsSetStmt { output_statement($1, 0, connection); } | ConstraintsSetStmt { output_statement($1, 0, connection); }
| CheckPointStmt { output_statement($1, 0, connection); } | CheckPointStmt { output_statement($1, 0, connection); }
| ECPGAllocateDescr | ECPGAllocateDescr
{ {
@ -605,7 +607,9 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); }
if (connection) if (connection)
mmerror(PARSE_ERROR, ET_ERROR, "no at option for typedef statement.\n"); mmerror(PARSE_ERROR, ET_ERROR, "no at option for typedef statement.\n");
output_simple_statement($1); fprintf(yyout, "%s", $1);
free($1);
output_line_number();
} }
| ECPGVar | ECPGVar
{ {
@ -3666,7 +3670,7 @@ ECPGDeallocate: SQL_DEALLOCATE SQL_PREPARE ident
*/ */
ECPGDeclaration: sql_startdeclare ECPGDeclaration: sql_startdeclare
{ fputs("/* exec sql begin declare section */", yyout); } { fputs("/* exec sql begin declare section */", yyout); }
variable_declarations sql_enddeclare var_type_declarations sql_enddeclare
{ {
fprintf(yyout, "%s/* exec sql end declare section */", $3); fprintf(yyout, "%s/* exec sql end declare section */", $3);
free($3); free($3);
@ -3678,15 +3682,82 @@ sql_startdeclare: ecpgstart BEGIN_TRANS DECLARE SQL_SECTION ';' {};
sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION ';' {}; sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION ';' {};
variable_declarations: /*EMPTY*/ { $$ = EMPTY; } var_type_declarations: /*EMPTY*/ { $$ = EMPTY; }
| declarations { $$ = $1; } | vt_declarations { $$ = $1; }
; ;
declarations: declaration { $$ = $1; } vt_declarations: var_declaration { $$ = $1; }
| declarations declaration { $$ = cat2_str($1, $2); } | type_declaration { $$ = $1; }
| vt_declarations var_declaration { $$ = cat2_str($1, $2); }
| vt_declarations type_declaration { $$ = cat2_str($1, $2); }
; ;
declaration: storage_clause storage_modifier variable_declarations: var_declaration { $$ = $1; }
| variable_declarations var_declaration { $$ = cat2_str($1, $2); }
;
type_declaration: S_TYPEDEF
{
/* reset this variable so we see if there was */
/* an initializer specified */
initializer = 0;
}
type opt_pointer ECPGColLabel opt_type_array_bounds ';'
{
/* add entry to list */
struct typedefs *ptr, *this;
int dimension = $6.index1;
int length = $6.index2;
if (($3.type_enum == ECPGt_struct ||
$3.type_enum == ECPGt_union) &&
initializer == 1)
{
mmerror(PARSE_ERROR, ET_ERROR, "Initializer not allowed in typedef command");
}
else
{
for (ptr = types; ptr != NULL; ptr = ptr->next)
{
if (strcmp($5, ptr->name) == 0)
{
/* re-definition is a bug */
sprintf(errortext, "Type %s already defined", $5);
mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
}
adjust_array($3.type_enum, &dimension, &length, $3.type_dimension, $3.type_index, *$4?1:0);
this = (struct typedefs *) mm_alloc(sizeof(struct typedefs));
/* initial definition */
this->next = types;
this->name = $5;
this->type = (struct this_type *) mm_alloc(sizeof(struct this_type));
this->type->type_enum = $3.type_enum;
this->type->type_str = mm_strdup($5);
this->type->type_dimension = dimension; /* dimension of array */
this->type->type_index = length; /* lenght of string */
this->struct_member_list = ($3.type_enum == ECPGt_struct || $3.type_enum == ECPGt_union) ?
struct_member_list[struct_level] : NULL;
if ($3.type_enum != ECPGt_varchar &&
$3.type_enum != ECPGt_char &&
$3.type_enum != ECPGt_unsigned_char &&
this->type->type_index >= 0)
mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types");
types = this;
}
fprintf(yyout, "typedef %s %s %s %s;\n", $3.type_str, *$4?"*":"", $5, $6.str);
output_line_number();
$$ = make_str("");
};
var_declaration: storage_clause storage_modifier
{ {
actual_storage[struct_level] = cat2_str(mm_strdup($1), mm_strdup($2)); actual_storage[struct_level] = cat2_str(mm_strdup($1), mm_strdup($2));
actual_startline[struct_level] = hashline_number(); actual_startline[struct_level] = hashline_number();
@ -4239,7 +4310,7 @@ ECPGTypedef: TYPE_P
if (($5.type_enum == ECPGt_struct || if (($5.type_enum == ECPGt_struct ||
$5.type_enum == ECPGt_union) && $5.type_enum == ECPGt_union) &&
initializer == 1) initializer == 1)
mmerror(PARSE_ERROR, ET_ERROR, "Initializer not allowed in EXEC SQL VAR command"); mmerror(PARSE_ERROR, ET_ERROR, "Initializer not allowed in EXEC SQL TYPE command");
else else
{ {
for (ptr = types; ptr != NULL; ptr = ptr->next) for (ptr = types; ptr != NULL; ptr = ptr->next)
@ -4276,7 +4347,10 @@ ECPGTypedef: TYPE_P
types = this; types = this;
} }
$$ = cat_str(7, make_str("/* exec sql type"), mm_strdup($3), make_str("is"), mm_strdup($5.type_str), mm_strdup($6.str), $7, make_str("*/")); if (auto_create_c == false)
$$ = cat_str(7, make_str("/* exec sql type"), mm_strdup($3), make_str("is"), mm_strdup($5.type_str), mm_strdup($6.str), $7, make_str("*/"));
else
$$ = cat_str(6, make_str("typedef "), mm_strdup($5.type_str), *$7?make_str("*"):make_str(""), mm_strdup($6.str), mm_strdup($3), make_str(";"));
} }
; ;
@ -4504,10 +4578,10 @@ ECPGKeywords: SQL_BREAK { $$ = make_str("break"); }
; ;
/* additional keywords that can be SQL type names (but not ECPGColLabels) */ /* additional keywords that can be SQL type names (but not ECPGColLabels) */
ECPGTypeName: SQL_BOOL { $$ = make_str("bool"); } ECPGTypeName: SQL_BOOL { $$ = make_str("bool"); }
| SQL_INT { $$ = make_str("int"); } | SQL_INT { $$ = make_str("int"); }
| SQL_LONG { $$ = make_str("long"); } | SQL_LONG { $$ = make_str("long"); }
| SQL_SHORT { $$ = make_str("short"); } | SQL_SHORT { $$ = make_str("short"); }
| SQL_STRUCT { $$ = make_str("struct"); } | SQL_STRUCT { $$ = make_str("struct"); }
| SQL_SIGNED { $$ = make_str("signed"); } | SQL_SIGNED { $$ = make_str("signed"); }
| SQL_UNSIGNED { $$ = make_str("unsigned"); } | SQL_UNSIGNED { $$ = make_str("unsigned"); }
@ -5006,6 +5080,7 @@ c_anything: IDENT { $$ = $1; }
| S_RSHIFT { $$ = make_str(">>"); } | S_RSHIFT { $$ = make_str(">>"); }
| S_STATIC { $$ = make_str("static"); } | S_STATIC { $$ = make_str("static"); }
| S_SUB { $$ = make_str("-="); } | S_SUB { $$ = make_str("-="); }
| S_TYPEDEF { $$ = make_str("typedef"); }
| SQL_BOOL { $$ = make_str("bool"); } | SQL_BOOL { $$ = make_str("bool"); }
| SQL_ENUM { $$ = make_str("enum"); } | SQL_ENUM { $$ = make_str("enum"); }
| SQL_INT { $$ = make_str("int"); } | SQL_INT { $$ = make_str("int"); }

View File

@ -11,9 +11,8 @@ exec sql type str is varchar[10];
int int
main () main ()
{ {
typedef struct { long born; short age; } birthinfo;
exec sql type birthinfo is struct { long born; short age; };
exec sql begin declare section; exec sql begin declare section;
typedef struct { long born; short age; } birthinfo;
struct personal_struct { str name; struct personal_struct { str name;
birthinfo birth; birthinfo birth;
} personal; } personal;