From: Michael Meskes <meskes@topsystem.de>

Here's my next patch. this one should fix some more bugs. ecpg now fully
understands the whenever statement.
This commit is contained in:
Marc G. Fournier 1998-02-19 13:52:17 +00:00
parent ed875a4132
commit 1d6424b1fb
11 changed files with 243 additions and 52 deletions

View File

@ -29,3 +29,12 @@ Mon Feb 16 16:17:21 CET 1998
- enable initialisation in declare section.
- connect call accepts a variable as well.
Wed Feb 18 21:41:30 CET 1998
- added whenever statement
Thu Feb 19 12:48:14 CET 1998
- added do option to whenever statement

View File

@ -3,7 +3,7 @@ This list is still from Linus. MM
The variables should be static.
Preprocessor cannot do syntax checking on your SQL statements Whatever you
write is copied more or less exactly to the postgres95 and you will not be
write is copied more or less exactly to the PostgreSQL and you will not be
able to locate your errors until run-time.
No restriction to strings only The PQ interface, and most of all the PQexec
@ -42,4 +42,6 @@ Now comes my list (MM):
What do we do with enum data types?
'signed' isn't understood so far
The cursor is opened when the declare statement is issued.
The is no exec sql prepare statement.

View File

@ -24,4 +24,9 @@ struct ECPGgeneric_varchar {
char arr[1];
};
/* print an error message */
void sqlprint(void);
/* define this for simplicity as well as compatibility */
#define SQLCODE sqlca.sqlcode

View File

@ -232,7 +232,7 @@ ECPGdo(int lineno, char *query,...)
return false;
}
/* Now then request is built. */
/* Now the request is built. */
if (committed)
{
@ -646,3 +646,10 @@ ECPGlog(const char *format,...)
free(f);
}
}
/* print out an error message */
void sqlprint(void)
{
sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml] = '\0';
printf ("sql error %s\n", sqlca.sqlerrm.sqlerrmc);
}

View File

@ -54,8 +54,9 @@ main(int argc, char *const argv[])
for (fnr = optind; fnr < argc; fnr++)
{
char *filename, *ptr2ext;
int ext = 0;
filename = mm_alloc(strlen(argv[fnr]) + 2);
filename = mm_alloc(strlen(argv[fnr]) + 4);
strcpy(filename, argv[fnr]);
@ -63,6 +64,8 @@ main(int argc, char *const argv[])
/* no extension or extension not equal .pgc */
if (ptr2ext == NULL || strcmp(ptr2ext, ".pgc") != 0)
{
if (ptr2ext == NULL)
ext = 1; /* we need this information a while later */
ptr2ext = filename + strlen(filename);
ptr2ext[0] = '.';
}
@ -82,7 +85,19 @@ main(int argc, char *const argv[])
}
}
yyin = fopen(input_filename = argv[fnr], "r");
if (ext == 1)
{
/* no extension => add .pgc */
ptr2ext = strrchr(filename, '.');
ptr2ext[1] = 'p';
ptr2ext[2] = 'g';
ptr2ext[3] = 'c';
ptr2ext[4] = '\0';
input_filename = filename;
}
else
input_filename = argv[fnr];
yyin = fopen(input_filename, "r");
if (yyin == NULL)
perror(argv[fnr]);
else

View File

@ -11,4 +11,4 @@ extern FILE *yyin, *yyout;
extern void lex_init(void);
extern char * input_filename;
extern int yyparse(void);
extern void *mm_alloc(size_t);
extern void *mm_alloc(size_t), *mm_realloc(void *, size_t);

View File

@ -15,25 +15,35 @@ letter [A-Za-z_]
digit [0-9]
length {digit}+
symbol {letter}({letter}|{digit})*
label ({letter}|{digit})*
string '[^']*'
begin [bB][eE][gG][iI][nN]
break [bB][rR][eE][aA][kK]
commit [cC][oO][mM][mM][iI][tT]
connect [cC][oO][nN][nN][eE][cC][tT]
continue [cC][oO][nN][tT][iI][nN][uU][eE]
declare [dD][eE][cC][lL][aA][rR][eE]
do [dD][oO]
end [eE][nN][dD]
exec [eE][xX][eE][cC]
execute [eE][xX][eE][cC][uU][tT][eE]
sql [sS][qQ][lL]
varchar [vV][aA][rR][cC][hH][aA][rR]
varchar2 [vV][aA][rR][cC][hH][aA][rR]2
into [iI][nN][tT][oO]
begin [bB][eE][gG][iI][nN]
end [eE][nN][dD]
declare [dD][eE][cC][lL][aA][rR][eE]
section [sS][eE][cC][tT][iI][oO][nN]
include [iI][nN][cC][lL][uU][dD][eE]
connect [cC][oO][nN][nN][eE][cC][tT]
open [oO][pP][eE][nN]
commit [cC][oO][mM][mM][iI][tT]
found [fF][oO][uU][nN][dD]
goto [gG][oO][tT][oO]
immediate [iI][mM][mM][eE][dD][iI][aA][tT][eE]
include [iI][nN][cC][lL][uU][dD][eE]
into [iI][nN][tT][oO]
not [nN][oO][tT]
open [oO][pP][eE][nN]
release [rR][eE][lL][eE][aA][sS][eE]
rollback [rR][oO][lL][lL][bB][aA][cC][kK]
section [sS][eE][cC][tT][iI][oO][nN]
sql [sS][qQ][lL]
sqlerror [sS][qQ][lL][eE][rR][rR][oO][rR]
sqlprint [sS][qQ][lL][pP][rR][iI][nN][tT]
varchar [vV][aA][rR][cC][hH][aA][rR]
varchar2 [vV][aA][rR][cC][hH][aA][rR]2
whenever [wW][hH][eE][nN][eE][vV][eE][rR]
work [wW][oO][rR][kK]
%%
<C>{exec}{ws}{sql} { BEGIN SQL; dbg(SQL_START); return SQL_START; }
@ -51,8 +61,15 @@ work [wW][oO][rR][kK]
<SQL>{release} { dbg(SQL_RELEASE); return SQL_RELEASE; }
<SQL>{work} { dbg(SQL_WORK); return SQL_WORK; }
<SQL>{rollback} { dbg(SQL_ROLLBACK); return SQL_ROLLBACK; }
<SQL>{whenever} { dbg(SQL_WHENEVER); return SQL_WHENEVER; }
<SQL>{sqlerror} { dbg(SQL_SQLERROR); return SQL_SQLERROR; }
<SQL>{sqlprint} { dbg(SQL_SQLPRINT); return SQL_SQLPRINT; }
<SQL>{not}{ws}{found} { dbg(SQL_NOT_FOUND); return SQL_NOT_FOUND; }
<SQL>{break} { dbg(SQL_BREAK); return SQL_BREAK; }
<SQL>{continue} { dbg(SQL_CONTINUE); return SQL_CONTINUE; }
<SQL>{into} { dbg(SQL_INTO); return SQL_INTO; }
<SQL>{goto} { dbg(SQL_GOTO); return SQL_GOTO; }
<SQL>{do} { dbg(SQL_DO); return SQL_DO; }
{length} { dbg(S_LENGTH); return S_LENGTH; }
@ -67,6 +84,7 @@ double { dbg(S_DOUBLE); return S_DOUBLE; }
bool { dbg(S_BOOL); return S_BOOL; }
static { dbg(S_STATIC); return S_STATIC; }
signed { dbg(S_SIGNED); return S_SIGNED; }
extern { dbg(S_EXTERN); return S_EXTERN; }
auto { dbg(S_AUTO); return S_AUTO; }
const { dbg(S_CONST); return S_CONST; }
@ -77,6 +95,7 @@ struct { dbg(S_STRUCT); return S_STRUCT; }
{string} { dbg(SQL_STRING); return SQL_STRING; }
<SQL>{ws} ;
{symbol} { dbg(S_SYMBOL); return S_SYMBOL; }
{label} { dbg(S_LABEL); return S_LABEL; }
<SQL>"!<" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"!>" { dbg(S_SYMBOL); return S_SYMBOL; }
@ -114,8 +133,10 @@ struct { dbg(S_STRUCT); return S_STRUCT; }
";" { dbg(;); return ';'; }
"=" { dbg(=); return '='; }
"," { dbg(komma); return ','; }
\( { dbg(braceopen); return '('; }
\) { dbg(braceclose); return ')'; }
\{ { dbg(blockstart); return '{'; }
\} { dbg(blockend); return'}'; }
\} { dbg(blockend); return '}'; }
\* { dbg(*); return('*'); }
<SQL>":" { dbg(:); return ':'; }

View File

@ -14,6 +14,8 @@ static void yyerror(char *);
*/
int debugging = 0;
static int struct_level = 0;
static char *do_str = NULL;
static int do_length = 0;
/* temporarily store record members while creating the data structure */
struct ECPGrecord_member *record_member_list[128] = { NULL };
@ -23,13 +25,54 @@ struct ECPGrecord_member *record_member_list[128] = { NULL };
*/
char * input_filename = NULL;
void
static void
output_line_number()
{
if (input_filename)
fprintf(yyout, "\n#line %d \"%s\"\n", yylineno, input_filename);
}
/*
* store the whenever action here
*/
static struct when when_error, when_nf;
static void
print_action(struct when *w)
{
switch (w->code)
{
case W_CONTINUE: fprintf(yyout, "continue;");
break;
case W_BREAK: fprintf(yyout, "break;");
break;
case W_SQLPRINT: fprintf(yyout, "sqlprint();");
break;
case W_GOTO: fprintf(yyout, "goto %s;", w->str);
break;
case W_DO: fprintf(yyout, "%s;", w->str);
break;
default: fprintf(yyout, "{/* not implemented yet */}");
break;
}
}
static void
whenever_action()
{
if (when_nf.code != W_NOTHING)
{
fprintf(yyout, "\nif (SQLCODE > 0) ");
print_action(&when_nf);
}
if (when_error.code != W_NOTHING)
{
fprintf(yyout, "\nif (SQLCODE < 0) ");
print_action(&when_error);
}
output_line_number();
}
/*
* Handling of the variables.
*/
@ -176,28 +219,31 @@ dump_variables(struct arguments * list)
char * symbolname;
int indexsize;
enum ECPGttype type_enum;
struct when action;
}
%token <tagname> SQL_START SQL_SEMI SQL_STRING SQL_INTO
%token <tagname> SQL_BEGIN SQL_END SQL_DECLARE SQL_SECTION SQL_INCLUDE
%token <tagname> SQL_CONNECT SQL_OPEN SQL_EXECUTE SQL_IMMEDIATE
%token <tagname> SQL_COMMIT SQL_ROLLBACK SQL_RELEASE SQL_WORK
%token <tagname> SQL_COMMIT SQL_ROLLBACK SQL_RELEASE SQL_WORK SQL_WHENEVER
%token <tagname> SQL_SQLERROR SQL_NOT_FOUND SQL_BREAK SQL_CONTINUE
%token <tagname> SQL_DO SQL_GOTO SQL_SQLPRINT
%token <tagname> S_SYMBOL S_LENGTH S_ANYTHING
%token <tagname> S_SYMBOL S_LENGTH S_ANYTHING S_LABEL
%token <tagname> S_VARCHAR S_VARCHAR2
%token <tagname> S_EXTERN S_STATIC S_AUTO S_CONST S_REGISTER S_STRUCT
%token <tagname> S_EXTERN S_STATIC S_AUTO S_CONST S_REGISTER S_STRUCT S_SIGNED
%token <tagname> S_UNSIGNED S_SIGNED
%token <tagname> S_LONG S_SHORT S_INT S_CHAR S_FLOAT S_DOUBLE S_BOOL
%token <tagname> '[' ']' ';' ',' '{' '}' '=' '*'
%token <tagname> '[' ']' ';' ',' '{' '}' '=' '*' '(' ')'
%type <type> type type_detailed varchar_type simple_type array_type struct_type
%type <symbolname> symbol
%type <symbolname> symbol label
%type <tagname> maybe_storage_clause varchar_tag db_name
%type <type_enum> simple_tag
%type <indexsize> index length
%type <action> action
%type <tagname> canything sqlanything both_anything vartext commit_release
%%
prog : statements;
@ -211,6 +257,7 @@ statement : sqldeclaration
| sqlcommit
| sqlrollback
| sqlexecute
| sqlwhenever
| sqlstatement
| cthing
| blockstart
@ -247,8 +294,18 @@ variable_declaration : type initializer ';' {
initializer : /*empty */
| '=' {fwrite(yytext, yyleng, 1, yyout);} vartext;
vartext : both_anything {fwrite(yytext, yyleng, 1, yyout);}
| vartext both_anything {fwrite(yytext, yyleng, 1, yyout);}
vartext : /* empty */ {}
| vartext both_anything {
if (do_length == 0)
fwrite(yytext, yyleng, 1, yyout);
else
{
if (strlen(do_str) + yyleng + 1 >= do_length)
do_str = mm_realloc(do_str, do_length += yyleng);
strcat(do_str, yytext);
}
}
symbol : S_SYMBOL {
char * name = (char *)malloc(yyleng + 1);
@ -351,6 +408,7 @@ simple_tag : S_CHAR { $<type_enum>$ = ECPGt_char; }
maybe_storage_clause : S_EXTERN { fwrite(yytext, yyleng, 1, yyout); }
| S_STATIC { fwrite(yytext, yyleng, 1, yyout); }
| S_SIGNED { fwrite(yytext, yyleng, 1, yyout); }
| S_CONST { fwrite(yytext, yyleng, 1, yyout); }
| S_REGISTER { fwrite(yytext, yyleng, 1, yyout); }
| S_AUTO { fwrite(yytext, yyleng, 1, yyout); }
@ -369,7 +427,7 @@ filename : cthing
sqlconnect : SQL_START SQL_CONNECT { fprintf(yyout, "ECPGconnect("); }
db_name
SQL_SEMI { fprintf(yyout, ");"); output_line_number();}
SQL_SEMI { fprintf(yyout, ");"); whenever_action();}
db_name : SQL_STRING { fprintf(yyout, "\""); fwrite(yytext + 1, yyleng - 2, 1, yyout); fprintf(yyout, "\""); }
| ':' symbol { /* check if we have a char variabnle */
@ -395,7 +453,7 @@ sqlgarbage : /* Empty */
sqlcommit : SQL_START commit_release SQL_SEMI {
fprintf(yyout, "ECPGcommit(__LINE__);");
output_line_number();
whenever_action();
}
commit_release : SQL_COMMIT
@ -404,7 +462,7 @@ commit_release : SQL_COMMIT
sqlrollback : SQL_START SQL_ROLLBACK SQL_SEMI {
fprintf(yyout, "ECPGrollback(__LINE__);");
output_line_number();
whenever_action();
};
sqlexecute : SQL_START { /* Reset stack */
@ -415,11 +473,59 @@ sqlexecute : SQL_START { /* Reset stack */
fprintf(yyout, "\", ");
dump_variables(argsinsert);
fprintf(yyout, "ECPGt_EOIT, ");
dump_variables(argsresult);
/* dump_variables(argsresult); output variables must not exist here */
fprintf(yyout, "ECPGt_EORT );");
output_line_number();
whenever_action();
};
sqlwhenever : SQL_START SQL_WHENEVER SQL_SQLERROR action SQL_SEMI{
when_error = $<action>4;
}
| SQL_START SQL_WHENEVER SQL_NOT_FOUND action SQL_SEMI{
when_nf = $<action>4;
}
action : SQL_BREAK {
$<action>$.code = W_BREAK;
$<action>$.str = NULL;
}
| SQL_CONTINUE {
$<action>$.code = W_CONTINUE;
$<action>$.str = NULL;
}
| SQL_SQLPRINT {
$<action>$.code = W_SQLPRINT;
$<action>$.str = NULL;
}
| SQL_GOTO label {
$<action>$.code = W_GOTO;
$<action>$.str = $<symbolname>2;
}
| SQL_GOTO symbol {
$<action>$.code = W_GOTO;
$<action>$.str = $<symbolname>2;
}
| SQL_DO symbol '(' {
do_str = (char *) mm_alloc(do_length = strlen($<symbolname>2) + 4);
sprintf(do_str, "%s (", $<symbolname>2);
} vartext ')' {
do_str[strlen(do_str)+1]='\0';
do_str[strlen(do_str)]=')';
$<action>$.code = W_DO;
$<action>$.str = do_str;
do_str = NULL;
do_length = 0;
}
label : S_LABEL {
char * name = (char *)malloc(yyleng + 1);
strncpy(name, yytext, yyleng);
name[yyleng] = '\0';
$<symbolname>$ = name;
}
sqlstatement : SQL_START { /* Reset stack */
reset_variables();
fprintf(yyout, "ECPGdo(__LINE__, \"");
@ -430,7 +536,7 @@ sqlstatement : SQL_START { /* Reset stack */
fprintf(yyout, "ECPGt_EOIT, ");
dump_variables(argsresult);
fprintf(yyout, "ECPGt_EORT );");
output_line_number();
whenever_action();
};
sqlstatement_words : sqlstatement_word
@ -478,9 +584,9 @@ both_anything : S_LENGTH | S_VARCHAR | S_VARCHAR2
| SQL_BEGIN | SQL_END
| SQL_DECLARE | SQL_SECTION
| SQL_INCLUDE
| S_SYMBOL
| S_SYMBOL | S_LABEL
| S_STATIC | S_EXTERN | S_AUTO | S_CONST | S_REGISTER | S_STRUCT
| '[' | ']' | ',' | '=' | '*'
| '[' | ']' | ',' | '=' | '*' | '(' | ')'
| S_ANYTHING;
blockstart : '{' {
@ -495,6 +601,6 @@ blockend : '}' {
%%
static void yyerror(char * error)
{
fprintf(stderr, "%s\n", error);
fprintf(stderr, "%s in line %d\n", error, yylineno);
exit(1);
}

View File

@ -18,6 +18,20 @@ void *mm_alloc(size_t size)
return (ptr);
}
/* realloc + error check */
void *mm_realloc(void * ptr, size_t size)
{
ptr = realloc(ptr, size);
if (ptr == NULL)
{
fprintf(stderr, "Out of memory\n");
exit(1);
}
return (ptr);
}
/* Constructors
Yes, I mostly write c++-code
*/

View File

@ -51,3 +51,19 @@ struct ECPGtemp_type {
};
extern const char * ECPGtype_name(enum ECPGttype typ);
/* some stuff for whenever statements */
enum WHEN {
W_NOTHING,
W_CONTINUE,
W_BREAK,
W_SQLPRINT,
W_GOTO,
W_DO
};
struct when
{
enum WHEN code;
char * str;
};

View File

@ -2,10 +2,11 @@
exec sql include sqlca;
#define SQLCODE sqlca.sqlcode
extern void ECPGdebug(int n, FILE *dbgs);
exec sql whenever not found sqlprint;
exec sql whenever sqlerror db_error(msg);
void
db_error (char *msg)
{
@ -24,37 +25,32 @@ exec sql begin declare section;
} birth;
} personal;
exec sql end declare section;
char msg[128];
FILE *dbgs;
if ((dbgs = fopen("log", "w")) != NULL)
ECPGdebug(1, dbgs);
strcpy(msg, "connect");
exec sql connect 'mm';
if (SQLCODE)
db_error ("connect");
strcpy(msg, "declare");
exec sql declare cur cursor for
select name, born, age from meskes;
if (SQLCODE) db_error ("declare");
exec sql open cur;
if (SQLCODE)
db_error ("open");
while (1) {
strcpy(msg, "fetch");
exec sql fetch in cur into :personal;
if (SQLCODE)
break;
printf ("%8.8s was born %d (age = %d)\n", personal.name.arr, personal.birth.born, personal.birth.age);
}
if (SQLCODE < 0)
db_error ("fetch");
strcpy(msg, "close");
exec sql close cur;
if (SQLCODE) db_error ("close");
strcpy(msg, "commit");
exec sql commit;
if (SQLCODE) db_error ("commit");
if (dbgs != NULL)
fclose(dbgs);