From: Michael Meskes <meskes@topsystem.de>

+ Thu Apr 23 09:27:16 CEST 1998
+
+       - Also allow call in whenever statement with the same functionality
+         as do.
+
+ Thu Apr 23 12:29:28 CEST 1998
+
+       - Also rewrote variable declaration part. It is now possible to
+         declare more than one variable per line.
+       - Set version to 2.1.0
+
+ Fri Apr 24 13:50:15 CEST 1998
+
+       - Fixed some bugs.
+       - Set version to 2.1.1
This commit is contained in:
Marc G. Fournier 1998-04-24 12:10:20 +00:00
parent f2b64d3593
commit 7500a961f1
13 changed files with 341 additions and 258 deletions

View File

@ -121,8 +121,24 @@ Mon Apr 20 16:13:25 CEST 1998
Mon Apr 20 16:39:23 CEST 1998
- Cursor is opened when the open command is issued, not at declare time.
- Set version to 2.0.0
Tue Apr 21 12:53:49 CEST 1998
- Set indicator to amount of data really written (truncation).
Thu Apr 23 09:27:16 CEST 1998
- Also allow call in whenever statement with the same functionality
as do.
Thu Apr 23 12:29:28 CEST 1998
- Also rewrote variable declaration part. It is now possible to
declare more than one variable per line.
- Set version to 2.1.0
Fri Apr 24 13:50:15 CEST 1998
- Fixed some bugs.
- Set version to 2.1.1

View File

@ -35,8 +35,6 @@ There is no exec sql prepare statement.
The complete structure definition has to be listed inside the declare
section for ecpg to be able to understand it.
Each variable has to be defined on a line on its own.
There is no way yet to fill a complete array with one call except arrays of
[unsigned] char which are considered strings.
@ -54,4 +52,7 @@ exec sql disconnect {current|default|all|connectionname|connection_hostvar};
| CURRENT
commit release|commit work release auch disconnect
It is not neccessary to check for sql not found after all commands.
It is not neccessary to check for "not found" after all commands.
It would be nice to be able to specify parts of a structure like :foo.bar or
:foo->bar.

View File

@ -21,7 +21,6 @@ ifeq ($(PORTNAME), linux)
install-shlib-dep := install-shlib
shlib := libecpg.so.$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION)
LDFLAGS_SL = -shared -soname libecpg.so.$(SO_MAJOR_VERSION)
CFLAGS += $(CFLAGS_SL)
endif
endif
ifeq ($(PORTNAME), bsd)
@ -47,12 +46,12 @@ endif
all: libecpg.a $(shlib)
$(shlib): ecpglib.o typename.o
$(LD) $(LDFLAGS_SL) -o $@ ecpglib.o typename.o
$(shlib): ecpglib.sho typename.sho
$(LD) $(LDFLAGS_SL) -o $@ ecpglib.sho typename.sho
ln -sf $@ libecpg.so
clean:
rm -f *.o *.a core a.out *~ $(shlib) libecpg.so
rm -f *.o *.sho *.a core a.out *~ $(shlib) libecpg.so
dep depend:
@ -70,6 +69,11 @@ uninstall::
libecpg.a : libecpg.a(ecpglib.o) libecpg.a(typename.o)
ecpglib.o : ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h
$(CC) $(CFLAGS) -I../include $(PQ_INCLUDE) -c ecpglib.c
$(CC) $(CFLAGS) -I../include $(PQ_INCLUDE) -c $< -o $@
typename.o : typename.c ../include/ecpgtype.h
$(CC) $(CFLAGS) -I../include $(PQ_INCLUDE) -c typename.c
$(CC) $(CFLAGS) -I../include $(PQ_INCLUDE) -c $< -o $@
ecpglib.sho : ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h
$(CC) $(CFLAGS) $(CFLAGS_SL) -I../include $(PQ_INCLUDE) -c $< -o $@
typename.sho : typename.c ../include/ecpgtype.h
$(CC) $(CFLAGS) $(CFLAGS_SL) -I../include $(PQ_INCLUDE) -c $< -o $@

View File

@ -2,8 +2,8 @@ SRCDIR= ../../..
include $(SRCDIR)/Makefile.global
MAJOR_VERSION=2
MINOR_VERSION=0
PATCHLEVEL=0
MINOR_VERSION=1
PATCHLEVEL=1
CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \
-DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) \

View File

@ -27,7 +27,7 @@ static void
usage(char *progname)
{
fprintf(stderr, "ecpg - the postgresql preprocessor, version: %d.%d.%d\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL);
fprintf(stderr, "Usage: %s: [-v] [-d] [-I include path] [ -o output file name] file1 [file2] ...\n", progname);
fprintf(stderr, "Usage: %s: [-v] [-I include path] [ -o output file name] file1 [file2] ...\n", progname);
}
static void
@ -51,7 +51,7 @@ main(int argc, char *const argv[])
add_include_path("/usr/local/include");
add_include_path(".");
while ((c = getopt(argc, argv, "vdo:I:")) != EOF)
while ((c = getopt(argc, argv, "vo:I:")) != EOF)
{
switch (c)
{
@ -62,9 +62,6 @@ main(int argc, char *const argv[])
else
out_option = 1;
break;
case 'd':
debugging = 1;
break;
case 'I':
add_include_path(optarg);
break;

View File

@ -21,6 +21,7 @@
*/
static ScanKeyword ScanKeywords[] = {
/* name value */
{"call", SQL_CALL},
{"connect", SQL_CONNECT},
{"continue", SQL_CONTINUE},
{"found", SQL_FOUND},

View File

@ -2,8 +2,7 @@
/* variables */
extern int debugging,
braces_open;
extern int braces_open;
extern char *yytext;
extern int yylineno,
yyleng;
@ -23,6 +22,18 @@ struct cursor { char *name;
extern struct cursor *cur;
/* This is a linked list of the variable names and types. */
struct variable
{
char * name;
struct ECPGtype * type;
int brace_level;
struct variable * next;
};
extern struct ECPGtype ecpg_no_indicator;
extern struct variable no_indicator;
/* functions */
extern void lex_init(void);

View File

@ -70,6 +70,7 @@ struct _yy_buffer { YY_BUFFER_STATE buffer;
%x xb
%x xc
%x xd
%x xdc
%x xh
%x xm
%x xq
@ -261,7 +262,7 @@ sql [sS][qQ][lL]
<xd>{xdstop} {
BEGIN(SQL);
yylval.str = strdup(literal);
return (IDENT);
return (CSTRING);
}
<xd>{xdinside} {
if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
@ -269,7 +270,22 @@ sql [sS][qQ][lL]
memcpy(literal+llen, yytext, yyleng+1);
llen += yyleng;
}
<C>{xdstart} {
BEGIN(xdc);
llen = 0;
*literal = '\0';
}
<xdc>{xdstop} {
BEGIN(C);
yylval.str = strdup(literal);
return (CSTRING);
}
<xdc>{xdinside} {
if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
yyerror("ERROR: quoted string parse buffer exceeded");
memcpy(literal+llen, yytext, yyleng+1);
llen += yyleng;
}
<xm>{space}* { /* ignore */ }
<xm>{xmstop} {
@ -283,7 +299,7 @@ sql [sS][qQ][lL]
<SQL>{self}/-[\.0-9] {
return (yytext[0]);
}
<SQL>{self} { return (yytext[0]); }
<SQL>{self} { return (yytext[0]); }
<SQL>{operator}/-[\.0-9] {
yylval.str = strdup((char*)yytext);
return (Op);
@ -379,6 +395,10 @@ sql [sS][qQ][lL]
return (FCONST);
}
<SQL>:{identifier} {
yylval.str = strdup((char*)yytext+1);
return(CVARIABLE);
}
<SQL>{identifier} {
int i;
ScanKeyword *keyword;
@ -423,12 +443,14 @@ sql [sS][qQ][lL]
}
}
<C>";" { return(';'); }
<C>"," { return(','); }
<C>"*" { return('*'); }
<C>{space} { ECHO; }
\{ { return('{'); }
\} { return('}'); }
\[ { return('['); }
\] { return(']'); }
\= { return('='); }
<C>\{ { return('{'); }
<C>\} { return('}'); }
<C>\[ { return('['); }
<C>\] { return(']'); }
<C>\= { return('='); }
<C>{other} { return (S_ANYTHING); }
<C>{exec}{space}{sql}{space}{include} { BEGIN(incl); }
<incl>{space} /* eat the whitespace */

View File

@ -12,9 +12,10 @@
* Variables containing simple states.
*/
static int struct_level = 0;
static char *do_str = NULL, errortext[128];
static int do_length = 0;
static char errortext[128];
static int QueryIsRule = 0;
static enum ECPGttype actual_type[128];
static char *actual_storage[128];
/* temporarily store record members while creating the data structure */
struct ECPGrecord_member *record_member_list[128] = { NULL };
@ -22,6 +23,9 @@ struct ECPGrecord_member *record_member_list[128] = { NULL };
/* keep a list of cursors */
struct cursor *cur = NULL;
struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, 0L, {NULL}};
struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};
/*
* Handle the filename and line numbering.
*/
@ -82,15 +86,6 @@ whenever_action()
*/
int braces_open;
/* This is a linked list of the variable names and types. */
struct variable
{
char * name;
struct ECPGtype * type;
int brace_level;
struct variable * next;
};
static struct variable * allvariables = NULL;
static struct variable *
@ -105,7 +100,7 @@ find_variable(char * name)
return p;
}
sprintf(errorstring, "The variable :%s is not declared", name);
sprintf(errorstring, "The variable %s is not declared", name);
yyerror(errorstring);
free (errorstring);
@ -167,9 +162,6 @@ struct arguments {
static struct arguments * argsinsert = NULL;
static struct arguments * argsresult = NULL;
static struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, 0L, {NULL}};
static struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};
static void
reset_variables(void)
{
@ -209,7 +201,9 @@ dump_variables(struct arguments * list)
dump_variables(list->next);
/* Then the current element and its indicator */
ECPGdump_a_type(yyout, list->variable->name, list->variable->type, list->indicator->name, list->indicator->type, NULL, NULL);
ECPGdump_a_type(yyout, list->variable->name, list->variable->type,
(list->indicator->type->typ != ECPGt_NO_INDICATOR) ? list->indicator->name : NULL,
(list->indicator->type->typ != ECPGt_NO_INDICATOR) ? list->indicator->type : NULL, NULL, NULL);
/* Then release the list element. */
free(list);
@ -360,7 +354,15 @@ make_name(void)
static void
output_statement(const char * stmt)
{
fprintf(yyout, "ECPGdo(__LINE__, \"%s\", ", stmt);
int i, j=strlen(stmt);
fputs("ECPGdo(__LINE__, \"", yyout);
/* do this char by char as we have to filter '\"' */
for (i = 0;i < j; i++)
if (stmt[i] != '\"')
fputc(stmt[i], yyout);
fputs("\", ", yyout);
/* dump variables to C file*/
dump_variables(argsinsert);
@ -375,14 +377,14 @@ output_statement(const char * stmt)
double dval;
int ival;
char * str;
struct ECPGtemp_type type;
struct when action;
struct index index;
int tagname;
enum ECPGttype type_enum;
}
/* special embedded SQL token */
%token SQL_CONNECT SQL_CONTINUE SQL_FOUND SQL_GO SQL_GOTO
%token SQL_CALL SQL_CONNECT SQL_CONTINUE SQL_FOUND SQL_GO SQL_GOTO
%token SQL_IMMEDIATE SQL_INDICATOR SQL_OPEN
%token SQL_SECTION SQL_SEMI SQL_SQLERROR SQL_SQLPRINT SQL_START
%token SQL_STOP SQL_WHENEVER
@ -449,7 +451,7 @@ output_statement(const char * stmt)
%token USER, PASSWORD, CREATEDB, NOCREATEDB, CREATEUSER, NOCREATEUSER, VALID, UNTIL
/* Special keywords, not in the query language - see the "lex" file */
%token <str> IDENT SCONST Op
%token <str> IDENT SCONST Op CSTRING CVARIABLE
%token <ival> ICONST PARAM
%token <dval> FCONST
@ -538,11 +540,18 @@ output_statement(const char * stmt)
%type <str> GrantStmt privileges operation_commalist operation
%type <str> ECPGWhenever ECPGConnect db_name ECPGOpen open_opts
%type <str> indicator ECPGExecute c_expr
%type <str> indicator ECPGExecute c_expr variable_list dotext
%type <str> storage_clause opt_initializer vartext c_anything blockstart
%type <str> blockend variable_list variable var_anything sql_anything
%type <str> opt_pointer ecpg_ident cvariable identlist
%type <str> stmt symbol
%type <type_enum> simple_type type struct_type
%type <action> action
%type <index> opt_index
%%
prog: statements;
@ -551,9 +560,9 @@ statements: /* empty */
statement: ecpgstart stmt SQL_SEMI
| ECPGDeclaration
| c_anything
| blockstart
| blockend
| c_anything { fputs($1, yyout); }
| blockstart { fputs($1, yyout); }
| blockend { fputs($1, yyout); }
stmt: AddAttrStmt { output_statement($1); }
| AlterUserStmt { output_statement($1); }
@ -1332,7 +1341,7 @@ TriggerFuncArg: Iconst
$$ = make_name();
}
| Sconst { $$ = $1; }
| IDENT { $$ = $1; }
| ecpg_ident { $$ = $1; }
;
DropTrigStmt: DROP TRIGGER name ON relation_name
@ -1829,7 +1838,7 @@ OptStmtMulti: OptStmtMulti OptimizableStmt ';'
event_object: relation_name '.' attr_name
{
$$ = make3_str($1, ",", $3);
$$ = cat3_str($1, ".", $3);
}
| relation_name
{
@ -2243,7 +2252,7 @@ sortby: ColId OptUseOp
}
| ColId '.' ColId OptUseOp
{
$$ = make4_str($1, ".", $3, $4);
$$ = make2_str(cat3_str($1, ".", $3), $4);
}
| Iconst OptUseOp
{
@ -2292,7 +2301,7 @@ groupby: ColId
}
| ColId '.' ColId
{
$$ = make3_str($1, ",", $3);
$$ = cat3_str($1, ",", $3);
}
| Iconst
{
@ -2383,7 +2392,7 @@ join_using: ColId
}
| ColId '.' ColId
{
$$ = make3_str($1, ".", $3);
$$ = cat3_str($1, ".", $3);
}
| Iconst
{
@ -2455,7 +2464,7 @@ Generic: generic
}
;
generic: IDENT { $$ = $1; }
generic: ecpg_ident { $$ = $1; }
| TYPE_P { $$ = "type"; }
;
@ -3409,20 +3418,20 @@ not_in_expr_nodes: AexprConst
attr: relation_name '.' attrs
{
$$ = make3_str($1, ".", $3);
$$ = cat3_str($1, ".", $3);
}
| ParamNo '.' attrs
{
$$ = make3_str($1, ".", $3);
$$ = cat3_str($1, ".", $3);
}
;
attrs: attr_name
{ $$ = $1; }
| attrs '.' attr_name
{ $$ = make3_str($1, ".", $3); }
{ $$ = cat3_str($1, ".", $3); }
| attrs '.' '*'
{ $$ = make2_str($1, ".*"); }
{ $$ = cat2_str($1, ".*"); }
;
@ -3449,7 +3458,7 @@ res_target_el: ColId opt_indirection '=' a_expr_or_null
}
| relation_name '.' '*'
{
$$ = make2_str($1, ".*");
$$ = cat2_str($1, ".*");
}
;
@ -3475,7 +3484,7 @@ res_target_el2: a_expr_or_null AS ColLabel
}
| relation_name '.' '*'
{
$$ = make2_str($1, ".*");
$$ = cat2_str($1, ".*");
}
| '*'
{
@ -3505,9 +3514,9 @@ relation_name: SpecialRuleRelation
;
database_name: ColId { $$ = $1; };
access_method: IDENT { $$ = $1; };
access_method: ecpg_ident { $$ = $1; };
attr_name: ColId { $$ = $1; };
class: IDENT { $$ = $1; };
class: ecpg_ident { $$ = $1; };
index_name: ColId { $$ = $1; };
/* Functions
@ -3518,7 +3527,7 @@ name: ColId { $$ = $1; };
func_name: ColId { $$ = $1; };
file_name: Sconst { $$ = $1; };
recipe_name: IDENT { $$ = $1; };
recipe_name: ecpg_ident { $$ = $1; };
/* Constants
* Include TRUE/FALSE for SQL3 support. - thomas 1997-10-24
@ -3569,7 +3578,7 @@ Sconst: SCONST {
$$[strlen($1)+2]='\0';
$$[strlen($1)+1]='\'';
}
UserId: IDENT { $$ = $1;};
UserId: ecpg_ident { $$ = $1;};
/* Column and type identifier
* Does not include explicit datetime types
@ -3591,7 +3600,7 @@ TypeId: ColId
* list due to shift/reduce conflicts in yacc. If so, move
* down to the ColLabel entity. - thomas 1997-11-06
*/
ColId: IDENT { $$ = $1; }
ColId: ecpg_ident { $$ = $1; }
| datetime { $$ = $1; }
| ACTION { $$ = "action"; }
| CACHE { $$ = "cache"; }
@ -3688,169 +3697,139 @@ sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION SQL_SEMI {
output_line_number();
}
variable_declarations : /* empty */
| variable_declarations variable_declaration;
variable_declarations: /* empty */
| declaration variable_declarations;
/* Here is where we can enter support for typedef. */
variable_declaration: type initializer ';' {
/* don't worry about our list when we're working on a struct */
if (struct_level == 0)
{
new_variable($<type>1.name, $<type>1.typ);
free((void *)$<type>1.name);
}
fputs(";", yyout);
}
declaration: storage_clause type
{
actual_storage[struct_level] = $1;
actual_type[struct_level] = $2;
if ($2 != ECPGt_varchar && $2 != ECPGt_record)
fprintf(yyout, "%s %s", $1, ECPGtype_name($2));
}
variable_list ';' { fputc(';', yyout); }
initializer : /*empty */
| '=' {fwrite(yytext, yyleng, 1, yyout);} vartext;
storage_clause : S_EXTERN { $$ = "extern"; }
| S_STATIC { $$ = "static"; }
| S_SIGNED { $$ = "signed"; }
| S_CONST { $$ = "const"; }
| S_REGISTER { $$ = "register"; }
| S_AUTO { $$ = "auto"; }
| /* empty */ { $$ = "" ; }
type : maybe_storage_clause type_detailed { $<type>$ = $<type>2; };
type_detailed : varchar_type { $<type>$ = $<type>1; }
| simple_type { $<type>$ = $<type>1; }
| string_type { $<type>$ = $<type>1; }
/* | array_type {$<type>$ = $<type>1; }
| pointer_type {$<type>$ = $<type>1; }*/
| struct_type {$<type>$ = $<type>1; };
type: simple_type
| struct_type
varchar_type : varchar_tag symbol index {
if ($<ival>3 > 0L)
fprintf(yyout, "struct varchar_%s { int len; char arr[%d]; } %s", $2, $<ival>3, $2);
else
fprintf(yyout, "struct varchar_%s { int len; char arr[]; } %s", $2, $2);
if (struct_level == 0)
{
$<type>$.name = $2;
$<type>$.typ = ECPGmake_varchar_type(ECPGt_varchar, $<ival>3);
}
else
ECPGmake_record_member($2, ECPGmake_varchar_type(ECPGt_varchar, $<ival>3), &(record_member_list[struct_level-1]));
}
struct_type: s_struct '{' variable_declarations '}'
{
struct_level--;
$$ = actual_type[struct_level] = ECPGt_record;
}
varchar_tag: S_VARCHAR /*| S_VARCHAR2 */;
s_struct : S_STRUCT symbol
{
struct_level++;
fprintf(yyout, "struct %s {", $2);
}
simple_type : simple_tag symbol {
fprintf(yyout, "%s %s", ECPGtype_name($<type_enum>1), $2);
if (struct_level == 0)
{
$<type>$.name = $2;
$<type>$.typ = ECPGmake_simple_type($<type_enum>1, 1);
}
else
ECPGmake_record_member($2, ECPGmake_simple_type($<type_enum>1, 1), &(record_member_list[struct_level-1]));
}
simple_type: S_SHORT { $$ = ECPGt_short; }
| S_UNSIGNED S_SHORT { $$ = ECPGt_unsigned_short; }
| S_INT { $$ = ECPGt_int; }
| S_UNSIGNED S_INT { $$ = ECPGt_unsigned_int; }
| S_LONG { $$ = ECPGt_long; }
| S_UNSIGNED S_LONG { $$ = ECPGt_unsigned_long; }
| S_FLOAT { $$ = ECPGt_float; }
| S_DOUBLE { $$ = ECPGt_double; }
| S_BOOL { $$ = ECPGt_bool; };
| S_CHAR { $$ = ECPGt_char; }
| S_UNSIGNED S_CHAR { $$ = ECPGt_unsigned_char; }
| S_VARCHAR { $$ = ECPGt_varchar; }
string_type : char_tag symbol index {
if ($<ival>3 > 0L)
fprintf(yyout, "%s %s [%d]", ECPGtype_name($<type_enum>1), $2, $<ival>3);
else
fprintf(yyout, "%s %s []", ECPGtype_name($<type_enum>1), $2);
if (struct_level == 0)
{
$<type>$.name = $2;
$<type>$.typ = ECPGmake_simple_type($<type_enum>1, $<ival>3);
}
else
ECPGmake_record_member($2, ECPGmake_simple_type($<type_enum>1, $<ival>3), &(record_member_list[struct_level-1]));
}
| char_tag '*' symbol {
fprintf(yyout, "%s *%s", ECPGtype_name($<type_enum>1), $3);
if (struct_level == 0)
{
$<type>$.name = $3;
$<type>$.typ = ECPGmake_simple_type($<type_enum>1, 0);
}
else
ECPGmake_record_member($3, ECPGmake_simple_type($<type_enum>1, 0), &(record_member_list[struct_level-1]));
}
| char_tag symbol {
fprintf(yyout, "%s %s", ECPGtype_name($<type_enum>1), $2);
if (struct_level == 0)
{
$<type>$.name = $2;
$<type>$.typ = ECPGmake_simple_type($<type_enum>1, 1);
}
else
ECPGmake_record_member($2, ECPGmake_simple_type($<type_enum>1, 1), &(record_member_list[struct_level-1]));
}
variable_list: variable
| variable_list ','
{
if (actual_type[struct_level] != ECPGt_varchar)
fputs(", ", yyout);
else
fputs(";\n ", yyout);
} variable
char_tag : S_CHAR { $<type_enum>$ = ECPGt_char; }
| S_UNSIGNED S_CHAR { $<type_enum>$ = ECPGt_unsigned_char; }
variable: opt_pointer symbol opt_index opt_initializer
{
int length = $3.ival;
/*
array_type : simple_tag symbol index {
if ($<ival>3 > 0)
fprintf(yyout, "%s %s [%ld]", ECPGtype_name($<type_enum>1), $2, $<ival>3);
else
fprintf(yyout, "%s %s []", ECPGtype_name($<type_enum>1), $2);
if (struct_level == 0)
{
$<type>$.name = $2;
$<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<ival>3);
}
else
ECPGmake_record_member($2, ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<ival>3), &(record_member_list[struct_level-1]));
}
/* pointer has to get length 0 */
if (strlen($1) > 0)
length = 0;
pointer_type : simple_tag '*' symbol {
fprintf(yyout, "%s * %s", ECPGtype_name($<type_enum>1), $3);
if (struct_level == 0)
{
$<type>$.name = $3;
$<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), 0);
}
else
ECPGmake_record_member($3, ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), 0), &(record_member_list[struct_level-1]));
}
*/
switch (actual_type[struct_level])
{
case ECPGt_record:
if (struct_level == 0)
new_variable($2, ECPGmake_record_type(record_member_list[struct_level]));
else
ECPGmake_record_member($2, ECPGmake_record_type(record_member_list[struct_level]), &(record_member_list[struct_level-1]));
s_struct : S_STRUCT symbol {
struct_level++;
fprintf(yyout, "struct %s {", $2);
}
record_member_list[struct_level] = NULL;
fprintf(yyout, "} %s%s%s%s", $1, $2, $3.str, $4);
struct_type : s_struct '{' variable_declarations '}' symbol {
struct_level--;
if (struct_level == 0)
{
$<type>$.name = $5;
$<type>$.typ = ECPGmake_record_type(record_member_list[struct_level]);
}
else
ECPGmake_record_member($5, ECPGmake_record_type(record_member_list[struct_level]), &(record_member_list[struct_level-1]));
fprintf(yyout, "} %s", $5);
record_member_list[struct_level] = NULL;
}
break;
case ECPGt_varchar:
if (strlen($4) != 0)
yyerror("varchar initilization impossible");
simple_tag : S_SHORT { $<type_enum>$ = ECPGt_short; }
| S_UNSIGNED S_SHORT { $<type_enum>$ = ECPGt_unsigned_short; }
| S_INT { $<type_enum>$ = ECPGt_int; }
| S_UNSIGNED S_INT { $<type_enum>$ = ECPGt_unsigned_int; }
| S_LONG { $<type_enum>$ = ECPGt_long; }
| S_UNSIGNED S_LONG { $<type_enum>$ = ECPGt_unsigned_long; }
| S_FLOAT { $<type_enum>$ = ECPGt_float; }
| S_DOUBLE { $<type_enum>$ = ECPGt_double; }
| S_BOOL { $<type_enum>$ = ECPGt_bool; };
if (struct_level == 0)
new_variable($2, ECPGmake_varchar_type(actual_type[struct_level], length));
else
ECPGmake_record_member($2, ECPGmake_varchar_type(actual_type[struct_level], length), &(record_member_list[struct_level-1]));
if (length > 0)
fprintf(yyout, "%s struct varchar_%s { int len; char arr[%d]; } %s", actual_storage[struct_level], $2, length, $2);
else
fprintf(yyout, "%s struct varchar_%s { int len; char arr[]; } %s", actual_storage[struct_level], $2, $2);
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); }
| /* empty */ { };
index : '[' Iconst ']' { $<ival>$ = atol($2); }
| '[' ']' { $<ival>$ = 0L; }
break;
default:
if (struct_level == 0)
new_variable($2, ECPGmake_simple_type(actual_type[struct_level], length));
else
ECPGmake_record_member($2, ECPGmake_simple_type(actual_type[struct_level], length), &(record_member_list[struct_level-1]));
fprintf(yyout, "%s%s%s%s", $1, $2, $3.str, $4);
break;
}
}
opt_initializer: /* empty */ { $$ = ""; }
| '=' vartext { $$ = cat2_str("=", $2); }
opt_pointer: /* empty */ { $$ = ""; }
| '*' { $$ = "*"; }
opt_index: '[' Iconst ']' {
$$.ival = atol($2);
$$.str = cat3_str("[", $2, "]");
}
| '[' ']'
{
$$.ival = 0;
$$.str = "[]";
}
| /* empty */ {
$$.ival = 1;
$$.str = "";
}
/*
* the exec sql connect statement: connect to the given database
*/
ECPGConnect : SQL_CONNECT db_name { $$ = $2; }
ECPGConnect: SQL_CONNECT db_name { $$ = $2; }
db_name : database_name { $$ = $1; }
| ':' name { /* check if we have a char variable */
struct variable *p = find_variable($2);
db_name: database_name { $$ = $1; }
| cvariable { /* check if we have a char variable */
struct variable *p = find_variable($1);
enum ECPGttype typ = p->type->typ;
/* if array see what's inside */
@ -3859,13 +3838,13 @@ db_name : database_name { $$ = $1; }
if (typ != ECPGt_char && typ != ECPGt_unsigned_char)
yyerror("invalid datatype");
$$ = $2;
$$ = $1;
}
/*
* execute a given string as sql command
*/
ECPGExecute : EXECUTE SQL_IMMEDIATE ':' name { $$ = $4; };
ECPGExecute : EXECUTE SQL_IMMEDIATE cvariable { $$ = $3; };
/*
* open is an open cursor, at the moment this has to be removed
@ -3890,12 +3869,15 @@ ECPGOpen: SQL_OPEN name open_opts {
};
open_opts: /* empty */ { $$ = ""; }
| USING ':' name {
| USING cvariable {
yyerror ("open cursor with variables not implemented yet");
}
/*
* whenever statement: decide what to do in case of error/no dat
* whenever statement: decide what to do in case of error/no data found
* according to SQL standards we miss: SQLSTATE, CONSTRAINT, SQLEXCEPTION
* and SQLWARNING
*/
ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action {
when_error.code = $<action>3.code;
@ -3933,17 +3915,15 @@ action : SQL_CONTINUE {
$<action>$.command = $3;
$<action>$.str = make2_str("goto ", $3);
}
| DO name '(' {
do_str = (char *) mm_alloc(do_length = strlen($2) + 4);
sprintf(do_str, "%s (", $2);
} dotext ')' {
do_str[strlen(do_str)+1]='\0';
do_str[strlen(do_str)]=')';
| DO name '(' dotext ')' {
$<action>$.code = W_DO;
$<action>$.command = do_str;
$<action>$.str = make2_str("do ", do_str);
do_str = NULL;
do_length = 0;
$<action>$.command = cat4_str($2, "(", $4, ")");
$<action>$.str = make2_str("do", $<action>$.command);
}
| SQL_CALL name '(' dotext ')' {
$<action>$.code = W_DO;
$<action>$.command = cat4_str($2, "(", $4, ")");
$<action>$.str = make2_str("call", $<action>$.command);
}
/* some other stuff for ecpg */
@ -4231,59 +4211,94 @@ into_list : coutputvariable | into_list ',' coutputvariable;
ecpgstart: SQL_START { reset_variables();}
dotext: /* empty */
| dotext sql_anything {
if (strlen(do_str) + yyleng + 1 >= do_length)
do_str = mm_realloc(do_str, do_length += yyleng);
dotext: /* empty */ { $$ = ""; }
| dotext sql_anything { $$ = cat2_str($1, $2); }
strcat(do_str, yytext);
vartext: var_anything { $$ = $1; }
| vartext var_anything { $$ = cat2_str($1, $2); }
coutputvariable : cvariable indicator {
add_variable(&argsresult, find_variable($1), ($2 == NULL) ? &no_indicator : find_variable($2));
}
vartext: both_anything { fwrite(yytext, yyleng, 1, yyout); }
| vartext both_anything { fwrite(yytext, yyleng, 1, yyout); }
coutputvariable : ':' name indicator {
add_variable(&argsresult, find_variable($2), ($3 == NULL) ? &no_indicator : find_variable($3));
cinputvariable : cvariable indicator {
add_variable(&argsinsert, find_variable($1), ($2 == NULL) ? &no_indicator : find_variable($2));
}
cinputvariable : ':' name indicator {
add_variable(&argsinsert, find_variable($2), ($3 == NULL) ? &no_indicator : find_variable($3));
civariableonly : cvariable name {
add_variable(&argsinsert, find_variable($1), &no_indicator);
}
civariableonly : ':' name {
add_variable(&argsinsert, find_variable($2), &no_indicator);
}
cvariable: CVARIABLE { $$ = $1; }
| CVARIABLE '.' identlist { $$ = $1; }
| CVARIABLE '-' '>' identlist { $$ = $1; }
identlist: IDENT { $$ = $1; }
| IDENT '.' identlist { $$ = $1; }
| IDENT '-' '>' identlist { $$ = $1; }
indicator: /* empty */ { $$ = NULL; }
| ':' name { check_indicator((find_variable($2))->type); $$ = $2; }
| SQL_INDICATOR ':' name { check_indicator((find_variable($3))->type); $$ = $3; }
| cvariable { check_indicator((find_variable($1))->type); $$ = $1; }
| SQL_INDICATOR cvariable { check_indicator((find_variable($2))->type); $$ = $2; }
| SQL_INDICATOR name { check_indicator((find_variable($2))->type); $$ = $2; }
ecpg_ident: IDENT { $$ = $1; }
| CSTRING { $$ = cat3_str("\"", $1, "\""); }
/*
* C stuff
*/
symbol: IDENT { $$ = $1; }
symbol: ecpg_ident { $$ = $1; }
c_anything: both_anything { fwrite(yytext, yyleng, 1, yyout); }
| ';' { fputc(';', yyout); }
c_anything: ecpg_ident { $$ = $1; }
| Iconst { $$ = $1; }
| FCONST { $$ = make_name(); }
| '*' { $$ = "*"; }
| ';' { $$ = ";"; }
| S_AUTO { $$ = "auto"; }
| S_BOOL { $$ = "bool"; }
| S_CHAR { $$ = "char"; }
| S_CONST { $$ = "const"; }
| S_DOUBLE { $$ = "double"; }
| S_EXTERN { $$ = "extern"; }
| S_FLOAT { $$ = "float"; }
| S_INT { $$ = "int"; }
| S_LONG { $$ = "long"; }
| S_REGISTER { $$ = "register"; }
| S_SHORT { $$ = "short"; }
| S_SIGNED { $$ = "signed"; }
| S_STATIC { $$ = "static"; }
| S_STRUCT { $$ = "struct"; }
| S_UNSIGNED { $$ = "unsigned"; }
| S_VARCHAR { $$ = "varchar"; }
| S_ANYTHING { $$ = make_name(); }
| '[' { $$ = "["; }
| ']' { $$ = "]"; }
| '(' { $$ = "("; }
| ')' { $$ = ")"; }
| '=' { $$ = "="; }
| ',' { $$ = ","; }
sql_anything: IDENT {} | ICONST {} | FCONST {}
sql_anything: ecpg_ident { $$ = $1; }
| Iconst { $$ = $1; }
| FCONST { $$ = make_name(); }
| ',' { $$ = ","; }
both_anything: IDENT {} | ICONST {} | FCONST {}
| S_AUTO | S_BOOL | S_CHAR | S_CONST | S_DOUBLE | S_EXTERN | S_FLOAT
| S_INT | S_LONG | S_REGISTER | S_SHORT | S_SIGNED | S_STATIC
| S_STRUCT | S_UNSIGNED | S_VARCHAR | S_ANYTHING
| '[' | ']' | '(' | ')' | '='
var_anything: ecpg_ident { $$ = $1; }
| Iconst { $$ = $1; }
| FCONST { $$ = make_name(); }
/*FIXME: | ',' { $$ = ","; }*/
| '{' { $$ = "{"; }
| '}' { $$ = "}"; }
blockstart : '{' {
braces_open++;
fputc('{', yyout);
$$ = "{";
}
blockend : '}' {
remove_variables(braces_open--);
fputc('}', yyout);
$$ = "}";
}
%%

View File

@ -130,6 +130,12 @@ ECPGdump_a_record(FILE *o, const char *name, const char *ind_name, long arrsiz,
void
ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *ind_name, struct ECPGtype * ind_typ, const char *prefix, const char *ind_prefix)
{
if (ind_typ == NULL)
{
ind_typ = &ecpg_no_indicator;
ind_name = "no_indicator";
}
if (IS_SIMPLE_TYPE(typ->typ))
{
ECPGdump_a_simple(o, name, typ->typ, typ->size, 0, 0, prefix);
@ -267,7 +273,7 @@ ECPGdump_a_record(FILE *o, const char *name, const char * ind_name, long arrsiz,
* then we are in a record in a record and the offset is used as
* offset.
*/
struct ECPGrecord_member *p, *ind_p;
struct ECPGrecord_member *p, *ind_p = NULL;
char obuf[BUFSIZ];
char pbuf[BUFSIZ], ind_pbuf[BUFSIZ];
const char *offset;
@ -288,9 +294,11 @@ ECPGdump_a_record(FILE *o, const char *name, const char * ind_name, long arrsiz,
sprintf(ind_pbuf, "%s%s.", ind_prefix ? ind_prefix : "", ind_name);
ind_prefix = ind_pbuf;
for (p = typ->u.members, ind_p = ind_typ->u.members; p; p = p->next, ind_p = ind_p->next)
if (ind_typ != NULL) ind_p = ind_typ->u.members;
for (p = typ->u.members; p; p = p->next)
{
ECPGdump_a_type(o, p->name, p->typ, ind_p->name, ind_p->typ, prefix, ind_prefix);
ECPGdump_a_type(o, p->name, p->typ, (ind_p != NULL) ? ind_p->name : NULL, (ind_p != NULL) ? ind_p->typ : NULL, prefix, ind_prefix);
if (ind_p != NULL) ind_p = ind_p->next;
}
}

View File

@ -74,3 +74,9 @@ struct when
char *command;
char *str;
};
struct index
{
int ival;
char *str;
};

View File

@ -119,5 +119,7 @@ exec sql end declare section;
exec sql drop table perftest1;
exec sql commit;
return (0);
}

View File

@ -24,7 +24,7 @@ exec sql begin declare section;
} ind_birth;
} ind_personal;
long ind_married;
char married[9]="a";
char married[9];
exec sql end declare section;
char msg[128], command[128];
FILE *dbgs;
@ -60,7 +60,7 @@ exec sql end declare section;
while (not_found == 0) {
strcpy(msg, "fetch");
exec sql fetch cur into :personal:ind_personal, :married:ind_married;
exec sql fetch cur into :personal:ind_personal, :married:ind_married, :personal.birth.born;
if (not_found == 0)
printf ("%8.8s was born %d (age = %d) %s%s\n", personal.name.arr, personal.birth.born, personal.birth.age, ind_married ? "" : "and married ", ind_married ? "" : married);
}