Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
64e35e14
Commit
64e35e14
authored
Apr 21, 1998
by
Marc G. Fournier
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Upgrade ECPG to 2.0
Michael Meskes <meskes@topsystem.de>
parent
5e6b0a57
Changes
20
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
5000 additions
and
639 deletions
+5000
-639
src/interfaces/ecpg/ChangeLog
src/interfaces/ecpg/ChangeLog
+40
-0
src/interfaces/ecpg/TODO
src/interfaces/ecpg/TODO
+12
-20
src/interfaces/ecpg/include/Makefile
src/interfaces/ecpg/include/Makefile
+6
-6
src/interfaces/ecpg/include/ecpglib.h
src/interfaces/ecpg/include/ecpglib.h
+0
-5
src/interfaces/ecpg/include/ecpgtype.h
src/interfaces/ecpg/include/ecpgtype.h
+2
-1
src/interfaces/ecpg/lib/Makefile.in
src/interfaces/ecpg/lib/Makefile.in
+3
-2
src/interfaces/ecpg/lib/ecpglib.c
src/interfaces/ecpg/lib/ecpglib.c
+117
-26
src/interfaces/ecpg/preproc/Makefile
src/interfaces/ecpg/preproc/Makefile
+16
-12
src/interfaces/ecpg/preproc/c_keywords.c
src/interfaces/ecpg/preproc/c_keywords.c
+63
-0
src/interfaces/ecpg/preproc/ecpg.c
src/interfaces/ecpg/preproc/ecpg.c
+23
-4
src/interfaces/ecpg/preproc/ecpg_keywords.c
src/interfaces/ecpg/preproc/ecpg_keywords.c
+60
-0
src/interfaces/ecpg/preproc/extern.h
src/interfaces/ecpg/preproc/extern.h
+12
-0
src/interfaces/ecpg/preproc/keywords.c
src/interfaces/ecpg/preproc/keywords.c
+242
-0
src/interfaces/ecpg/preproc/pgc.l
src/interfaces/ecpg/preproc/pgc.l
+410
-155
src/interfaces/ecpg/preproc/preproc.y
src/interfaces/ecpg/preproc/preproc.y
+3923
-319
src/interfaces/ecpg/preproc/type.c
src/interfaces/ecpg/preproc/type.c
+24
-64
src/interfaces/ecpg/preproc/type.h
src/interfaces/ecpg/preproc/type.h
+3
-2
src/interfaces/ecpg/test/Makefile
src/interfaces/ecpg/test/Makefile
+4
-6
src/interfaces/ecpg/test/perftest.pgc
src/interfaces/ecpg/test/perftest.pgc
+14
-3
src/interfaces/ecpg/test/test2.pgc
src/interfaces/ecpg/test/test2.pgc
+26
-14
No files found.
src/interfaces/ecpg/ChangeLog
View file @
64e35e14
...
...
@@ -86,3 +86,43 @@ Fri Mar 13 13:35:13 CET 1998
Mon Mar 16 15:09:10 CET 1998
- fixed parser to print correct filename and line number
Wed Mar 18 14:28:49 CET 1998
- started working on indicator variables
Mon Mar 23 13:49:15 CET 1998
- fixed some bugs in indicator variable handling
- completely rewrote parser for fetch and insert statements
- indicator variables are also allowed in insert statements now
Mon Mar 23 16:09:05 CET 1998
- fixed whenever command goto to only allow valid lables
Thu Mar 26 13:33:02 MEZ 1998
- some minor bugfixes
Mon Apr 20 13:06:09 CEST 1998
- database name no longer has to entered as string constant, i.e.
just remove the '...' around the name
Mon Apr 20 14:38:45 CEST 1998
- both test cases compile cleanly
Mon Apr 20 16:13:25 CEST 1998
- Phew! Finally finished parser rewriting.
Mon Apr 20 16:39:23 CEST 1998
- Cursor is opened when the open command is issued, not at declare time.
Tue Apr 21 12:53:49 CEST 1998
- Set indicator to amount of data really written (truncation).
src/interfaces/ecpg/TODO
View file @
64e35e14
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 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
function, that is used by the ecpg relies on that the request is built up as
a string. In some cases, like when the data contains the null character,
this will be a serious problem.
There should be different error numbers for the different errors instead of
just -1 for them all.
...
...
@@ -21,12 +12,6 @@ ecpg it is done for compatibility reasons only. For them to improve speed
would require a lot more insight in the postgres internal mechanisms than I
possess.
Oracle has indicator variables that tell if a value is null or if it is
empty. This largely simplifies array operations and provides for a way to
hack around some design flaws in the handling of VARCHAR2 (like that an
empty string isn't distinguishable from a null value). I am not sure if this
is an Oracle extension or part of the ANSI standard.
As well as complex types like records and arrays, typedefs would be a good
thing to take care of.
...
...
@@ -43,8 +28,6 @@ Now comes my list (MM):
The return code is alway -1 in case of an error. You cannot see which error
occured by examining the return code.
The cursor is opened when the declare statement is issued.
ecpg does not understand enum datatypes.
There is no exec sql prepare statement.
...
...
@@ -59,7 +42,16 @@ There is no way yet to fill a complete array with one call except arrays of
ecpg cannot use pointer variables except [unsigned] char *
List all commands as sqlcommand, not just S_SYMBOL or even better rewrite
pareser to be equivalent to backend´s parser.
give back the number of tuples affected via sqlca
exec sql disconnect {current|default|all|connectionname|connection_hostvar};
oder <disconnect statement> ::=
DISCONNECT <disconnect object>
<disconnect object> ::=
<connection object>
| ALL
| CURRENT
commit release|commit work release auch disconnect
Set standard include path
s.
It is not neccessary to check for sql not found after all command
s.
src/interfaces/ecpg/include/Makefile
View file @
64e35e14
...
...
@@ -6,13 +6,13 @@ all clean::
@
echo
Nothing to be
done
.
install
::
$(INSTALL)
$(INSTLOPTS)
ecpglib.h
$(HEADERDIR)
$(INSTALL)
$(INSTLOPTS)
ecpgtype.h
$(HEADERDIR)
$(INSTALL)
$(INSTLOPTS)
sqlca.h
$(HEADERDIR)
$(INSTALL)
$(INSTLOPTS)
ecpglib.h
$(
DESTDIR)$(
HEADERDIR)
$(INSTALL)
$(INSTLOPTS)
ecpgtype.h
$(
DESTDIR)$(
HEADERDIR)
$(INSTALL)
$(INSTLOPTS)
sqlca.h
$(
DESTDIR)$(
HEADERDIR)
uninstall
::
rm
-f
$(HEADERDIR)
/ecpglib.h
rm
-f
$(HEADERDIR)
/ecpgtype.h
rm
-f
$(HEADERDIR)
/sqlca.h
rm
-f
$(
DESTDIR)$(
HEADERDIR)
/ecpglib.h
rm
-f
$(
DESTDIR)$(
HEADERDIR)
/ecpgtype.h
rm
-f
$(
DESTDIR)$(
HEADERDIR)
/sqlca.h
dep depend
:
src/interfaces/ecpg/include/ecpglib.h
View file @
64e35e14
...
...
@@ -13,11 +13,6 @@ bool ECPGstatus(void);
void
ECPGlog
(
const
char
*
format
,...);
/* These functions are only kept for compatibility reasons. */
/* Use ECPGtrans instead. */
bool
ECPGcommit
(
int
);
bool
ECPGrollback
(
int
);
#ifdef LIBPQ_FE_H
bool
ECPGsetdb
(
PGconn
*
);
...
...
src/interfaces/ecpg/include/ecpgtype.h
View file @
64e35e14
...
...
@@ -43,7 +43,8 @@ enum ECPGttype
ECPGt_array
,
ECPGt_record
,
ECPGt_EOIT
,
/* End of insert types. */
ECPGt_EORT
/* End of result types. */
ECPGt_EORT
,
/* End of result types. */
ECPGt_NO_INDICATOR
/* no indicator */
};
#define IS_SIMPLE_TYPE(type) ((type) >= ECPGt_char && (type) <= ECPGt_varchar2)
...
...
src/interfaces/ecpg/lib/Makefile.in
View file @
64e35e14
...
...
@@ -3,8 +3,8 @@ include $(SRCDIR)/Makefile.global
PQ_INCLUDE
=
-I
$(SRCDIR)
/interfaces/libpq
SO_MAJOR_VERSION
=
1
SO_MINOR_VERSION
=
1
SO_MAJOR_VERSION
=
2
SO_MINOR_VERSION
=
0
PORTNAME
=
@PORTNAME@
...
...
@@ -16,6 +16,7 @@ endif
shlib
:=
install-shlib-dep
:=
ifeq
($(PORTNAME), linux)
LINUX_ELF
=
@LINUX_ELF@
ifdef
LINUX_ELF
install-shlib-dep
:=
install-shlib
shlib
:=
libecpg.so.
$(SO_MAJOR_VERSION)
.
$(SO_MINOR_VERSION)
...
...
src/interfaces/ecpg/lib/ecpglib.c
View file @
64e35e14
...
...
@@ -96,10 +96,11 @@ ECPGdo(int lineno, char *query,...)
*/
while
(
type
!=
ECPGt_EOIT
)
{
void
*
value
=
NULL
;
long
varcharsize
;
long
size
;
long
arrsize
;
void
*
value
=
NULL
,
*
ind_value
;
long
varcharsize
,
ind_varcharsize
;
long
size
,
ind_size
;
long
arrsize
,
ind_arrsize
;
enum
ECPGttype
ind_type
;
char
*
newcopy
;
char
*
mallocedval
=
NULL
;
...
...
@@ -117,9 +118,40 @@ ECPGdo(int lineno, char *query,...)
varcharsize
=
va_arg
(
ap
,
long
);
size
=
va_arg
(
ap
,
long
);
arrsize
=
va_arg
(
ap
,
long
);
switch
(
type
)
ind_type
=
va_arg
(
ap
,
enum
ECPGttype
);
ind_value
=
va_arg
(
ap
,
void
*
);
ind_varcharsize
=
va_arg
(
ap
,
long
);
ind_size
=
va_arg
(
ap
,
long
);
ind_arrsize
=
va_arg
(
ap
,
long
);
buff
[
0
]
=
'\0'
;
/* check for null value and set input buffer accordingly */
switch
(
ind_type
)
{
case
ECPGt_short
:
case
ECPGt_unsigned_short
:
if
(
*
(
short
*
)
ind_value
<
0
)
strcpy
(
buff
,
"null"
);
break
;
case
ECPGt_int
:
case
ECPGt_unsigned_int
:
if
(
*
(
int
*
)
ind_value
<
0
)
strcpy
(
buff
,
"null"
);
break
;
case
ECPGt_long
:
case
ECPGt_unsigned_long
:
if
(
*
(
long
*
)
ind_value
<
0L
)
strcpy
(
buff
,
"null"
);
break
;
default:
break
;
}
if
(
*
buff
==
'\0'
)
{
switch
(
type
)
{
case
ECPGt_short
:
case
ECPGt_int
:
sprintf
(
buff
,
"%d"
,
*
(
int
*
)
value
);
...
...
@@ -205,7 +237,10 @@ ECPGdo(int lineno, char *query,...)
ECPGtype_name
(
type
),
lineno
);
return
false
;
break
;
}
}
else
tobeinserted
=
buff
;
/*
* Now tobeinserted points to an area that is to be inserted at
...
...
@@ -266,7 +301,7 @@ ECPGdo(int lineno, char *query,...)
if
(
committed
)
{
if
((
results
=
PQexec
(
simple_connection
,
"begin"
))
==
NULL
)
if
((
results
=
PQexec
(
simple_connection
,
"begin
transaction
"
))
==
NULL
)
{
register_error
(
-
1
,
"Error starting transaction line %d."
,
lineno
);
return
false
;
...
...
@@ -324,10 +359,11 @@ ECPGdo(int lineno, char *query,...)
for
(
x
=
0
;
x
<
m
&&
status
;
x
++
)
{
void
*
value
=
NULL
;
long
varcharsize
;
long
size
;
long
arrsize
;
void
*
value
=
NULL
,
*
ind_value
;
long
varcharsize
,
ind_varcharsize
;
long
size
,
ind_size
;
long
arrsize
,
ind_arrsize
;
enum
ECPGttype
ind_type
;
char
*
pval
=
PQgetvalue
(
results
,
0
,
x
);
...
...
@@ -339,14 +375,38 @@ ECPGdo(int lineno, char *query,...)
ECPGlog
(
"ECPGdo line %d: RESULT: %s
\n
"
,
lineno
,
pval
?
pval
:
""
);
/* No the pval is a pointer to the value. */
/* No
w
the pval is a pointer to the value. */
/* We will have to decode the value */
type
=
va_arg
(
ap
,
enum
ECPGttype
);
value
=
va_arg
(
ap
,
void
*
);
varcharsize
=
va_arg
(
ap
,
long
);
size
=
va_arg
(
ap
,
long
);
arrsize
=
va_arg
(
ap
,
long
);
ind_type
=
va_arg
(
ap
,
enum
ECPGttype
);
ind_value
=
va_arg
(
ap
,
void
*
);
ind_varcharsize
=
va_arg
(
ap
,
long
);
ind_size
=
va_arg
(
ap
,
long
);
ind_arrsize
=
va_arg
(
ap
,
long
);
/* check for null value and set indicator accordingly */
switch
(
ind_type
)
{
case
ECPGt_short
:
case
ECPGt_unsigned_short
:
*
(
short
*
)
ind_value
=
-
PQgetisnull
(
results
,
0
,
x
);
break
;
case
ECPGt_int
:
case
ECPGt_unsigned_int
:
*
(
int
*
)
ind_value
=
-
PQgetisnull
(
results
,
0
,
x
);
break
;
case
ECPGt_long
:
case
ECPGt_unsigned_long
:
*
(
long
*
)
ind_value
=
-
PQgetisnull
(
results
,
0
,
x
);
break
;
default:
break
;
}
switch
(
type
)
{
long
res
;
...
...
@@ -486,7 +546,30 @@ ECPGdo(int lineno, char *query,...)
((
char
*
)
value
)[
strlen
(
pval
)]
=
'\0'
;
}
else
{
strncpy
((
char
*
)
value
,
pval
,
varcharsize
);
if
(
varcharsize
<
strlen
(
pval
))
{
/* truncation */
switch
(
ind_type
)
{
case
ECPGt_short
:
case
ECPGt_unsigned_short
:
*
(
short
*
)
ind_value
=
varcharsize
;
break
;
case
ECPGt_int
:
case
ECPGt_unsigned_int
:
*
(
int
*
)
ind_value
=
varcharsize
;
break
;
case
ECPGt_long
:
case
ECPGt_unsigned_long
:
*
(
long
*
)
ind_value
=
varcharsize
;
break
;
default:
break
;
}
}
}
}
break
;
...
...
@@ -498,7 +581,28 @@ ECPGdo(int lineno, char *query,...)
strncpy
(
var
->
arr
,
pval
,
varcharsize
);
var
->
len
=
strlen
(
pval
);
if
(
var
->
len
>
varcharsize
)
{
/* truncation */
switch
(
ind_type
)
{
case
ECPGt_short
:
case
ECPGt_unsigned_short
:
*
(
short
*
)
ind_value
=
varcharsize
;
break
;
case
ECPGt_int
:
case
ECPGt_unsigned_int
:
*
(
int
*
)
ind_value
=
varcharsize
;
break
;
case
ECPGt_long
:
case
ECPGt_unsigned_long
:
*
(
long
*
)
ind_value
=
varcharsize
;
break
;
default:
break
;
}
var
->
len
=
varcharsize
;
}
}
break
;
...
...
@@ -587,19 +691,6 @@ ECPGtrans(int lineno, const char * transaction)
return
(
TRUE
);
}
/* include these for compatibility */
bool
ECPGcommit
(
int
lineno
)
{
return
(
ECPGtrans
(
lineno
,
"end"
));
}
bool
ECPGrollback
(
int
lineno
)
{
return
(
ECPGtrans
(
lineno
,
"abort"
));
}
bool
ECPGsetdb
(
PGconn
*
newcon
)
{
...
...
src/interfaces/ecpg/preproc/Makefile
View file @
64e35e14
SRCDIR
=
../../..
include
$(SRCDIR)/Makefile.global
MAJOR_VERSION
=
1
MINOR_VERSION
=
1
MAJOR_VERSION
=
2
MINOR_VERSION
=
0
PATCHLEVEL
=
0
CFLAGS
+=
-I
../include
-DMAJOR_VERSION
=
$(MAJOR_VERSION)
\
-DMINOR_VERSION
=
$(MINOR_VERSION)
-DPATCHLEVEL
=
$(PATCHLEVEL)
\
-DINCLUDE_PATH
=
\"
$(HEADERDIR)
\"
-DINCLUDE_PATH
=
\"
$(DESTDIR)$(HEADERDIR)
\"
OBJ
=
y.tab.o pgc.o type.o ecpg.o ecpg_keywords.o ../../../backend/parser/scansup.o
\
keywords.o c_keywords.o ../lib/typename.o
all
::
ecpg
...
...
@@ -15,21 +18,22 @@ clean:
rm
-f
*
.o core a.out ecpg y.tab.h y.tab.c pgc.c
*
~
install
:
all
$(INSTALL)
$(INSTL_EXE_OPTS)
ecpg
$(BINDIR)
$(INSTALL)
$(INSTL_EXE_OPTS)
ecpg
$(
DESTDIR)$(
BINDIR)
uninstall
:
rm
-f
$(BINDIR)
/ecpg
dep depend
:
$(CC)
-MM
$(CFLAGS)
*
.c
>
depend
rm
-f
$(DESTDIR)$(BINDIR)
/ecpg
# Rule that really do something.
ecpg
:
y.tab.o pgc.o type.o ecpg.o ../lib/typename.o
$(CC)
-o
ecpg
y.tab.o pgc.o type.o ecpg.o ../lib/typename.o
$(LEXLIB)
$(LDFLAGS
)
ecpg
:
$(OBJ)
$(CC)
-o
ecpg
$(OBJ)
$(LEXLIB
)
y.tab.h y.tab.c
:
preproc.y
$(YACC)
$(YFLAGS)
$<
y.tab.o
:
y.tab.h ../include/ecpgtype.h
y.tab.o
:
y.tab.h ../include/ecpgtype.h
keywords.c c_keywords.c ecpg_keywords.c
type.o
:
../include/ecpgtype.h
pgc.o
:
../include/ecpgtype.h
pgc.o
:
../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c y.tab.h
keywords.o
:
../include/ecpgtype.h y.tab.h
c_keywords.o
:
../include/ecpgtype.h y.tab.h
ecpg_keywords.o
:
../include/ecpgtype.h y.tab.h
src/interfaces/ecpg/preproc/c_keywords.c
0 → 100644
View file @
64e35e14
/*-------------------------------------------------------------------------
*
* keywords.c--
* lexical token lookup for reserved words in postgres embedded SQL
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include <string.h>
#include "postgres.h"
#include "type.h"
#include "y.tab.h"
#include "extern.h"
/*
* List of (keyword-name, keyword-token-value) pairs.
*
* !!WARNING!!: This list must be sorted, because binary
* search is used to locate entries.
*/
static
ScanKeyword
ScanKeywords
[]
=
{
/* name value */
{
"auto"
,
S_AUTO
},
{
"bool"
,
S_BOOL
},
{
"char"
,
S_CHAR
},
{
"const"
,
S_CONST
},
{
"double"
,
S_DOUBLE
},
{
"extern"
,
S_EXTERN
},
{
"float"
,
S_FLOAT
},
{
"int"
,
S_INT
},
{
"long"
,
S_LONG
},
{
"register"
,
S_REGISTER
},
{
"short"
,
S_SHORT
},
{
"signed"
,
S_SIGNED
},
{
"static"
,
S_STATIC
},
{
"struct"
,
S_STRUCT
},
{
"unsigned"
,
S_UNSIGNED
},
{
"varchar"
,
S_VARCHAR
},
};
ScanKeyword
*
ScanCKeywordLookup
(
char
*
text
)
{
ScanKeyword
*
low
=
&
ScanKeywords
[
0
];
ScanKeyword
*
high
=
endof
(
ScanKeywords
)
-
1
;
ScanKeyword
*
middle
;
int
difference
;
while
(
low
<=
high
)
{
middle
=
low
+
(
high
-
low
)
/
2
;
difference
=
strcmp
(
middle
->
name
,
text
);
if
(
difference
==
0
)
return
(
middle
);
else
if
(
difference
<
0
)
low
=
middle
+
1
;
else
high
=
middle
-
1
;
}
return
(
NULL
);
}
src/interfaces/ecpg/preproc/ecpg.c
View file @
64e35e14
...
...
@@ -91,7 +91,7 @@ main(int argc, char *const argv[])
/* after the options there must not be anything but filenames */
for
(
fnr
=
optind
;
fnr
<
argc
;
fnr
++
)
{
char
*
ptr2ext
;
char
*
output_filename
=
NULL
,
*
ptr2ext
;
input_filename
=
mm_alloc
(
strlen
(
argv
[
fnr
])
+
5
);
...
...
@@ -113,7 +113,7 @@ main(int argc, char *const argv[])
if
(
out_option
==
0
)
/* calculate the output name */
{
char
*
output_filename
=
strdup
(
input_filename
);
output_filename
=
strdup
(
input_filename
);
ptr2ext
=
strrchr
(
output_filename
,
'.'
);
/* make extension = .c */
...
...
@@ -128,7 +128,6 @@ main(int argc, char *const argv[])
free
(
input_filename
);
continue
;
}
free
(
output_filename
);
}
yyin
=
fopen
(
input_filename
,
"r"
);
...
...
@@ -136,9 +135,25 @@ main(int argc, char *const argv[])
perror
(
argv
[
fnr
]);
else
{
struct
cursor
*
ptr
;
/* initialize lex */
lex_init
();
/* initialize cursor list */
for
(
ptr
=
cur
;
ptr
!=
NULL
;)
{
struct
cursor
*
c
;
free
(
ptr
->
name
);
free
(
ptr
->
command
);
c
=
ptr
;
ptr
=
ptr
->
next
;
free
(
c
);
}
cur
=
NULL
;
/* we need two includes */
fprintf
(
yyout
,
"/* Processed by ecpg (%d.%d.%d) */
\n
/*These two include files are added by the preprocessor */
\n
#include <ecpgtype.h>
\n
#include <ecpglib.h>
\n
"
,
MAJOR_VERSION
,
MINOR_VERSION
,
PATCHLEVEL
);
...
...
@@ -150,6 +165,10 @@ main(int argc, char *const argv[])
if
(
out_option
==
0
)
fclose
(
yyout
);
}
if
(
output_filename
)
free
(
output_filename
);
free
(
input_filename
);
}
}
...
...
src/interfaces/ecpg/preproc/ecpg_keywords.c
0 → 100644
View file @
64e35e14
/*-------------------------------------------------------------------------
*
* keywords.c--
* lexical token lookup for reserved words in postgres embedded SQL
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include <string.h>
#include "postgres.h"
#include "type.h"
#include "y.tab.h"
#include "extern.h"
/*
* List of (keyword-name, keyword-token-value) pairs.
*
* !!WARNING!!: This list must be sorted, because binary
* search is used to locate entries.
*/
static
ScanKeyword
ScanKeywords
[]
=
{
/* name value */
{
"connect"
,
SQL_CONNECT
},
{
"continue"
,
SQL_CONTINUE
},
{
"found"
,
SQL_FOUND
},
{
"go"
,
SQL_GO
},
{
"goto"
,
SQL_GOTO
},
{
"immediate"
,
SQL_IMMEDIATE
},
{
"indicator"
,
SQL_INDICATOR
},
{
"open"
,
SQL_OPEN
},
{
"section"
,
SQL_SECTION
},
{
"sqlerror"
,
SQL_SQLERROR
},
{
"sqlprint"
,
SQL_SQLPRINT
},
{
"stop"
,
SQL_STOP
},
{
"whenever"
,
SQL_WHENEVER
},
};
ScanKeyword
*
ScanECPGKeywordLookup
(
char
*
text
)
{
ScanKeyword
*
low
=
&
ScanKeywords
[
0
];
ScanKeyword
*
high
=
endof
(
ScanKeywords
)
-
1
;
ScanKeyword
*
middle
;
int
difference
;
while
(
low
<=
high
)
{
middle
=
low
+
(
high
-
low
)
/
2
;
difference
=
strcmp
(
middle
->
name
,
text
);
if
(
difference
==
0
)
return
(
middle
);
else
if
(
difference
<
0
)
low
=
middle
+
1
;
else
high
=
middle
-
1
;
}
return
(
NULL
);
}
src/interfaces/ecpg/preproc/extern.h
View file @
64e35e14
#include "parser/keywords.h"
/* variables */
extern
int
debugging
,
...
...
@@ -14,9 +16,19 @@ struct _include_path { char * path;
extern
struct
_include_path
*
include_paths
;
struct
cursor
{
char
*
name
;
char
*
command
;
struct
cursor
*
next
;
};
extern
struct
cursor
*
cur
;
/* functions */
extern
void
lex_init
(
void
);
extern
char
*
input_filename
;
extern
int
yyparse
(
void
);
extern
void
*
mm_alloc
(
size_t
),
*
mm_realloc
(
void
*
,
size_t
);
ScanKeyword
*
ScanECPGKeywordLookup
(
char
*
);
ScanKeyword
*
ScanCKeywordLookup
(
char
*
);
extern
void
yyerror
(
char
*
);
src/interfaces/ecpg/preproc/keywords.c
0 → 100644
View file @
64e35e14
/*-------------------------------------------------------------------------
*
* keywords.c--
* lexical token lookup for reserved words in postgres SQL
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.1 1998/04/21 13:23:06 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include <string.h>
#include "postgres.h"
#include "nodes/parsenodes.h"
#include "nodes/pg_list.h"
#include "type.h"
#include "y.tab.h"
#include "parser/keywords.h"
#include "utils/elog.h"
/*
* List of (keyword-name, keyword-token-value) pairs.
*
* !!WARNING!!: This list must be sorted, because binary
* search is used to locate entries.
*/
static
ScanKeyword
ScanKeywords
[]
=
{
/* name value */
{
"abort"
,
ABORT_TRANS
},
{
"action"
,
ACTION
},
{
"add"
,
ADD
},
{
"after"
,
AFTER
},
{
"aggregate"
,
AGGREGATE
},
{
"all"
,
ALL
},
{
"alter"
,
ALTER
},
{
"analyze"
,
ANALYZE
},
{
"and"
,
AND
},
{
"any"
,
ANY
},
{
"archive"
,
ARCHIVE
},
{
"as"
,
AS
},
{
"asc"
,
ASC
},
{
"backward"
,
BACKWARD
},
{
"before"
,
BEFORE
},
{
"begin"
,
BEGIN_TRANS
},
{
"between"
,
BETWEEN
},
{
"binary"
,
BINARY
},
{
"both"
,
BOTH
},
{
"by"
,
BY
},
{
"cache"
,
CACHE
},
{
"cascade"
,
CASCADE
},
{
"cast"
,
CAST
},
{
"char"
,
CHAR
},
{
"character"
,
CHARACTER
},
{
"check"
,
CHECK
},
{
"close"
,
CLOSE
},
{
"cluster"
,
CLUSTER
},
{
"collate"
,
COLLATE
},
{
"column"
,
COLUMN
},
{
"commit"
,
COMMIT
},
{
"constraint"
,
CONSTRAINT
},
{
"copy"
,
COPY
},
{
"create"
,
CREATE
},
{
"createdb"
,
CREATEDB
},
{
"createuser"
,
CREATEUSER
},
{
"cross"
,
CROSS
},
{
"current"
,
CURRENT
},
{
"current_date"
,
CURRENT_DATE
},
{
"current_time"
,
CURRENT_TIME
},
{
"current_timestamp"
,
CURRENT_TIMESTAMP
},
{
"current_user"
,
CURRENT_USER
},
{
"cursor"
,
CURSOR
},
{
"cycle"
,
CYCLE
},
{
"database"
,
DATABASE
},
{
"day"
,
DAY_P
},
{
"decimal"
,
DECIMAL
},
{
"declare"
,
DECLARE
},
{
"default"
,
DEFAULT
},
{
"delete"
,
DELETE
},
{
"delimiters"
,
DELIMITERS
},
{
"desc"
,
DESC
},
{
"distinct"
,
DISTINCT
},
{
"do"
,
DO
},
{
"double"
,
DOUBLE
},
{
"drop"
,
DROP
},
{
"each"
,
EACH
},
{
"end"
,
END_TRANS
},
{
"execute"
,
EXECUTE
},
{
"exists"
,
EXISTS
},
{
"explain"
,
EXPLAIN
},
{
"extend"
,
EXTEND
},
{
"extract"
,
EXTRACT
},
{
"false"
,
FALSE_P
},
{
"fetch"
,
FETCH
},
{
"float"
,
FLOAT
},
{
"for"
,
FOR
},
{
"foreign"
,
FOREIGN
},
{
"forward"
,
FORWARD
},
{
"from"
,
FROM
},
{
"full"
,
FULL
},
{
"function"
,
FUNCTION
},
{
"grant"
,
GRANT
},
{
"group"
,
GROUP
},
{
"handler"
,
HANDLER
},
{
"having"
,
HAVING
},
{
"hour"
,
HOUR_P
},
{
"in"
,
IN
},
{
"increment"
,
INCREMENT
},
{
"index"
,
INDEX
},
{
"inherits"
,
INHERITS
},
{
"inner"
,
INNER_P
},
{
"insert"
,
INSERT
},
{
"instead"
,
INSTEAD
},
{
"interval"
,
INTERVAL
},
{
"into"
,
INTO
},
{
"is"
,
IS
},
{
"isnull"
,
ISNULL
},
{
"join"
,
JOIN
},
{
"key"
,
KEY
},
{
"lancompiler"
,
LANCOMPILER
},
{
"language"
,
LANGUAGE
},
{
"leading"
,
LEADING
},
{
"left"
,
LEFT
},
{
"like"
,
LIKE
},
{
"listen"
,
LISTEN
},
{
"load"
,
LOAD
},
{
"local"
,
LOCAL
},
{
"location"
,
LOCATION
},
{
"lock"
,
LOCK_P
},
{
"match"
,
MATCH
},
{
"maxvalue"
,
MAXVALUE
},
{
"minute"
,
MINUTE_P
},
{
"minvalue"
,
MINVALUE
},
{
"month"
,
MONTH_P
},
{
"move"
,
MOVE
},
{
"national"
,
NATIONAL
},
{
"natural"
,
NATURAL
},
{
"nchar"
,
NCHAR
},
{
"new"
,
NEW
},
{
"no"
,
NO
},
{
"nocreatedb"
,
NOCREATEDB
},
{
"nocreateuser"
,
NOCREATEUSER
},
{
"none"
,
NONE
},
{
"not"
,
NOT
},
{
"nothing"
,
NOTHING
},
{
"notify"
,
NOTIFY
},
{
"notnull"
,
NOTNULL
},
{
"null"
,
NULL_P
},
{
"numeric"
,
NUMERIC
},
{
"oids"
,
OIDS
},
{
"on"
,
ON
},
{
"operator"
,
OPERATOR
},
{
"option"
,
OPTION
},
{
"or"
,
OR
},
{
"order"
,
ORDER
},
{
"outer"
,
OUTER_P
},
{
"partial"
,
PARTIAL
},
{
"password"
,
PASSWORD
},
{
"position"
,
POSITION
},
{
"precision"
,
PRECISION
},
{
"primary"
,
PRIMARY
},
{
"privileges"
,
PRIVILEGES
},
{
"procedural"
,
PROCEDURAL
},
{
"procedure"
,
PROCEDURE
},
{
"public"
,
PUBLIC
},
{
"recipe"
,
RECIPE
},
{
"references"
,
REFERENCES
},
{
"rename"
,
RENAME
},
{
"reset"
,
RESET
},
{
"returns"
,
RETURNS
},
{
"revoke"
,
REVOKE
},
{
"right"
,
RIGHT
},
{
"rollback"
,
ROLLBACK
},
{
"row"
,
ROW
},
{
"rule"
,
RULE
},
{
"second"
,
SECOND_P
},
{
"select"
,
SELECT
},
{
"sequence"
,
SEQUENCE
},
{
"set"
,
SET
},
{
"setof"
,
SETOF
},
{
"show"
,
SHOW
},
{
"start"
,
START
},
{
"statement"
,
STATEMENT
},
{
"stdin"
,
STDIN
},
{
"stdout"
,
STDOUT
},
{
"substring"
,
SUBSTRING
},
{
"table"
,
TABLE
},
{
"time"
,
TIME
},
{
"to"
,
TO
},
{
"trailing"
,
TRAILING
},
{
"transaction"
,
TRANSACTION
},
{
"trigger"
,
TRIGGER
},
{
"trim"
,
TRIM
},
{
"true"
,
TRUE_P
},
{
"trusted"
,
TRUSTED
},
{
"type"
,
TYPE_P
},
{
"union"
,
UNION
},
{
"unique"
,
UNIQUE
},
{
"until"
,
UNTIL
},
{
"update"
,
UPDATE
},
{
"user"
,
USER
},
{
"using"
,
USING
},
{
"vacuum"
,
VACUUM
},
{
"valid"
,
VALID
},
{
"values"
,
VALUES
},
{
"varchar"
,
VARCHAR
},
{
"varying"
,
VARYING
},
{
"verbose"
,
VERBOSE
},
{
"version"
,
VERSION
},
{
"view"
,
VIEW
},
{
"where"
,
WHERE
},
{
"with"
,
WITH
},
{
"work"
,
WORK
},
{
"year"
,
YEAR_P
},
{
"zone"
,
ZONE
},
};
ScanKeyword
*
ScanKeywordLookup
(
char
*
text
)
{
ScanKeyword
*
low
=
&
ScanKeywords
[
0
];
ScanKeyword
*
high
=
endof
(
ScanKeywords
)
-
1
;
ScanKeyword
*
middle
;
int
difference
;
while
(
low
<=
high
)
{
middle
=
low
+
(
high
-
low
)
/
2
;
difference
=
strcmp
(
middle
->
name
,
text
);
if
(
difference
==
0
)
return
(
middle
);
else
if
(
difference
<
0
)
low
=
middle
+
1
;
else
high
=
middle
-
1
;
}
return
(
NULL
);
}
src/interfaces/ecpg/preproc/pgc.l
View file @
64e35e14
This diff is collapsed.
Click to expand it.
src/interfaces/ecpg/preproc/preproc.y
View file @
64e35e14
This diff is collapsed.
Click to expand it.
src/interfaces/ecpg/preproc/type.c
View file @
64e35e14
...
...
@@ -123,22 +123,27 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
long
varcharsize
,
long
arrsiz
,
const
char
*
siz
,
const
char
*
prefix
);
void
ECPGdump_a_record
(
FILE
*
o
,
const
char
*
name
,
long
arrsiz
,
struct
ECPGtype
*
typ
,
const
char
*
offset
,
const
char
*
prefix
);
ECPGdump_a_record
(
FILE
*
o
,
const
char
*
name
,
const
char
*
ind_name
,
long
arrsiz
,
struct
ECPGtype
*
typ
,
struct
ECPGtype
*
ind_typ
,
const
char
*
offset
,
const
char
*
prefix
,
const
char
*
ind_
prefix
);
void
ECPGdump_a_type
(
FILE
*
o
,
const
char
*
name
,
struct
ECPGtype
*
typ
,
const
char
*
prefix
)
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
(
IS_SIMPLE_TYPE
(
typ
->
typ
))
{
ECPGdump_a_simple
(
o
,
name
,
typ
->
typ
,
typ
->
size
,
0
,
0
,
prefix
);
ECPGdump_a_simple
(
o
,
ind_name
,
ind_typ
->
typ
,
ind_typ
->
size
,
0
,
0
,
ind_prefix
);
}
else
if
(
typ
->
typ
==
ECPGt_array
)
{
if
(
IS_SIMPLE_TYPE
(
typ
->
u
.
element
->
typ
))
{
ECPGdump_a_simple
(
o
,
name
,
typ
->
u
.
element
->
typ
,
typ
->
u
.
element
->
size
,
typ
->
size
,
0
,
prefix
);
ECPGdump_a_simple
(
o
,
ind_name
,
ind_typ
->
u
.
element
->
typ
,
ind_typ
->
u
.
element
->
size
,
ind_typ
->
size
,
0
,
prefix
);
}
else
if
(
typ
->
u
.
element
->
typ
==
ECPGt_array
)
{
abort
();
/* Array of array, */
...
...
@@ -146,7 +151,7 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *pr
else
if
(
typ
->
u
.
element
->
typ
==
ECPGt_record
)
{
/* Array of records. */
ECPGdump_a_record
(
o
,
name
,
typ
->
size
,
typ
->
u
.
element
,
0
,
prefix
);
ECPGdump_a_record
(
o
,
name
,
ind_name
,
typ
->
size
,
typ
->
u
.
element
,
ind_typ
->
u
.
element
,
0
,
prefix
,
ind_
prefix
);
}
else
{
...
...
@@ -155,7 +160,7 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *pr
}
else
if
(
typ
->
typ
==
ECPGt_record
)
{
ECPGdump_a_record
(
o
,
name
,
0
,
typ
,
0
,
prefix
);
ECPGdump_a_record
(
o
,
name
,
ind_name
,
0
,
typ
,
ind_typ
,
0
,
prefix
,
ind_
prefix
);
}
else
{
...
...
@@ -171,7 +176,8 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
long
varcharsize
,
long
arrsiz
,
const
char
*
siz
,
const
char
*
prefix
)
const
char
*
prefix
)
{
switch
(
typ
)
{
...
...
@@ -241,15 +247,19 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
varcharsize
,
arrsiz
,
siz
);
break
;
case
ECPGt_NO_INDICATOR
:
/* no indicator */
fprintf
(
o
,
"
\n\t
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, "
);
break
;
default:
abort
();
}
}
/* Penetrate a record and dump the contents. */
void
ECPGdump_a_record
(
FILE
*
o
,
const
char
*
name
,
long
arrsiz
,
struct
ECPGtype
*
typ
,
const
char
*
offsetarg
,
const
char
*
prefix
)
ECPGdump_a_record
(
FILE
*
o
,
const
char
*
name
,
const
char
*
ind_name
,
long
arrsiz
,
struct
ECPGtype
*
typ
,
struct
ECPGtype
*
ind_typ
,
const
char
*
offsetarg
,
const
char
*
prefix
,
const
char
*
ind_
prefix
)
{
/*
...
...
@@ -257,9 +267,9 @@ ECPGdump_a_record(FILE *o, const char *name, long arrsiz, struct ECPGtype * typ,
* then we are in a record in a record and the offset is used as
* offset.
*/
struct
ECPGrecord_member
*
p
;
struct
ECPGrecord_member
*
p
,
*
ind_p
;
char
obuf
[
BUFSIZ
];
char
pbuf
[
BUFSIZ
];
char
pbuf
[
BUFSIZ
]
,
ind_pbuf
[
BUFSIZ
]
;
const
char
*
offset
;
if
(
offsetarg
==
NULL
)
...
...
@@ -274,63 +284,13 @@ ECPGdump_a_record(FILE *o, const char *name, long arrsiz, struct ECPGtype * typ,
sprintf
(
pbuf
,
"%s%s."
,
prefix
?
prefix
:
""
,
name
);
prefix
=
pbuf
;
sprintf
(
ind_pbuf
,
"%s%s."
,
ind_prefix
?
ind_prefix
:
""
,
ind_name
);
ind_prefix
=
ind_pbuf
;
for
(
p
=
typ
->
u
.
members
;
p
;
p
=
p
->
next
)
for
(
p
=
typ
->
u
.
members
,
ind_p
=
ind_typ
->
u
.
members
;
p
;
p
=
p
->
next
,
ind_p
=
ind_
p
->
next
)
{
#if 0
if (IS_SIMPLE_TYPE(p->typ->typ))
{
sprintf(buf, "%s.%s", name, p->name);
ECPGdump_a_simple(o, buf, p->typ->typ, p->typ->size,
arrsiz, offset);
}
else if (p->typ->typ == ECPGt_array)
{
int i;
for (i = 0; i < p->typ->size; i++)
{
if (IS_SIMPLE_TYPE(p->typ->u.element->typ))
{
/* sprintf(buf, "%s.%s[%d]", name, p->name, i); */
sprintf(buf, "%s.%s", name, p->name);
ECPGdump_a_simple(o, buf, p->typ->u.element->typ, p->typ->u.element->size,
p->typ->u.element->size, offset);
}
else if (p->typ->u.element->typ == ECPGt_array)
{
/* Array within an array. NOT implemented. */
abort();
}
else if (p->typ->u.element->typ == ECPGt_record)
{
/*
* Record within array within record. NOT implemented
* yet.
*/
abort();
}
else
{
/* Unknown type */
abort();
}
}
}
else if (p->typ->typ == ECPGt_record)
{
/* Record within a record */
sprintf(buf, "%s.%s", name, p->name);
ECPGdump_a_record(o, buf, arrsiz, p->typ, offset);
}
else
{
/* Unknown type */
abort();
}
#endif
ECPGdump_a_type
(
o
,
p
->
name
,
p
->
typ
,
prefix
);
ECPGdump_a_type
(
o
,
p
->
name
,
p
->
typ
,
ind_p
->
name
,
ind_p
->
typ
,
prefix
,
ind_prefix
);
}
}
...
...
src/interfaces/ecpg/preproc/type.h
View file @
64e35e14
...
...
@@ -45,7 +45,7 @@ void ECPGfree_type(struct ECPGtype *);
size is the maxsize in case it is a varchar. Otherwise it is the size of
the variable (required to do array fetches of records).
*/
void
ECPGdump_a_type
(
FILE
*
,
const
char
*
name
,
struct
ECPGtype
*
,
const
char
*
);
void
ECPGdump_a_type
(
FILE
*
,
const
char
*
,
struct
ECPGtype
*
,
const
char
*
,
struct
ECPGtype
*
,
const
char
*
,
const
char
*
);
/* A simple struct to keep a variable and its type. */
struct
ECPGtemp_type
...
...
@@ -71,5 +71,6 @@ enum WHEN
struct
when
{
enum
WHEN
code
;
char
*
str
;
char
*
command
;
char
*
str
;
};
src/interfaces/ecpg/test/Makefile
View file @
64e35e14
all
:
test2 perftest
test2
:
test2.c
gcc
-g
-I
../include
-I
../../libpq
-o
test2 test2.c
-L
../lib
-lecpg
-L
../../libpq
-lpq
-lcrypt
gcc
-g
-I
../include
-I
../../libpq
-o
test2 test2.c
-L
../lib
-lecpg
-L
../../libpq
-lpq
-lcrypt
--static
test2.c
:
test2.pgc
ecpg test2.pgc
../preproc/
ecpg test2.pgc
perftest
:
perftest.c
gcc
-g
-I
../include
-I
../../libpq
-o
perftest perftest.c
-L
../lib
-lecpg
-L
../../libpq
-lpq
-lcrypt
gcc
-g
-I
../include
-I
../../libpq
-o
perftest perftest.c
-L
../lib
-lecpg
-L
../../libpq
-lpq
-lcrypt
--static
perftest.c
:
perftest.pgc
ecpg perftest.pgc
../preproc/
ecpg perftest.pgc
clean
:
/bin/rm test2 test2.c perftest perftest.c log
dep depend
:
src/interfaces/ecpg/test/perftest.pgc
View file @
64e35e14
...
...
@@ -16,7 +16,8 @@ print_result(long sec, long usec, char *text)
usec+=1000000;
}
printf("I needed %ld seconds and %ld microseconds for the %s test.\n", sec, usec, text);
exec sql vacuum analyze;
exec sql vacuum;
sleep(1);
}
int
...
...
@@ -27,9 +28,9 @@ exec sql begin declare section;
exec sql end declare section;
struct timeval tvs, tve;
exec sql connect
'mm'
;
exec sql connect
mm
;
exec sql create table perftest1(number int4, ascii char
16
);
exec sql create table perftest1(number int4, ascii char
(16)
);
exec sql create unique index number1 on perftest1(number);
...
...
@@ -100,6 +101,16 @@ exec sql end declare section;
print_result(tve.tv_sec - tvs.tv_sec, tve.tv_usec - tvs.tv_usec, "update");
gettimeofday(&tvs, NULL);
exec sql delete from perftest2;
exec sql commit;
gettimeofday(&tve, NULL);
print_result(tve.tv_sec - tvs.tv_sec, tve.tv_usec - tvs.tv_usec, "delete");
exec sql drop index number2;
exec sql drop table perftest2;
...
...
src/interfaces/ecpg/test/test2.pgc
View file @
64e35e14
...
...
@@ -2,8 +2,6 @@
exec sql include header_test;
extern void ECPGdebug(int n, FILE *dbgs);
static int not_found = 0;
static void
set_not_found(void)
...
...
@@ -18,39 +16,53 @@ exec sql begin declare section;
struct personal_struct { varchar name[8];
struct birth_struct { long born;
short age;
} birth;
} birth;
} personal;
struct personal_indicator { short name;
struct birth_indicator { short born;
int age;
} ind_birth;
} ind_personal;
long ind_married;
char married[9]="a";
exec sql end declare section;
char msg[128];
char msg[128]
, command[128]
;
FILE *dbgs;
if ((dbgs = fopen("log", "w")) != NULL)
ECPGdebug(1, dbgs);
ECPGdebug(1, dbgs);
strcpy(msg, "connect");
exec sql connect
'mm'
;
exec sql connect
mm
;
strcpy(msg, "create");
exec sql create table meskes(name char
8, born int4, age int2
);
exec sql create table meskes(name char
(8), born integer, age smallint, married char(8)
);
strcpy(msg, "insert");
exec sql insert into meskes(name, born, age
) values ('Petra', 19661202, 31
);
exec sql insert into meskes(name, born, age
) values ('Michael', 19660117, 32
);
exec sql insert into meskes(name, born, age
, married) values ('Petra', 19661202, 31, '19900404'
);
exec sql insert into meskes(name, born, age
, married) values ('Michael', 19660117, 32, '19900404'
);
exec sql insert into meskes(name, born, age) values ('Carsten', 19910103, 7);
exec sql insert into meskes(name, born, age) values ('Marc', 19930907, 4);
exec sql insert into meskes(name, born, age) values ('Chris', 19970923, 0);
sprintf(command, "insert into meskes(name, born, age) values ('Chris', 19970923, 0)");
strcpy(msg, "execute");
exec sql execute immediate :command;
strcpy(msg, "commit");
exec sql commit;
strcpy(msg, "declare");
exec sql declare cur cursor for
select name, born, age from meskes;
select name, born, age
, married
from meskes;
strcpy(msg, "open");
exec sql open cur;
while (not_found == 0) {
strcpy(msg, "fetch");
exec sql fetch cur into :personal;
exec sql fetch cur into :personal
:ind_personal, :married:ind_married
;
if (not_found == 0)
printf ("%8.8s was born %d (age = %d)
\n", personal.name.arr, personal.birth.born, personal.birth.age
);
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
);
}
strcpy(msg, "close");
...
...
@@ -63,7 +75,7 @@ exec sql end declare section;
exec sql commit;
if (dbgs != NULL)
fclose(dbgs);
fclose(dbgs);
return (0);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment