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
bf6636ba
Commit
bf6636ba
authored
Feb 20, 1999
by
Marc G. Fournier
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
From: Michael Meskes <Michael_Meskes@topmail.de> See Changes file...
parent
3eb22085
Changes
20
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1514 additions
and
457 deletions
+1514
-457
src/interfaces/ecpg/ChangeLog
src/interfaces/ecpg/ChangeLog
+57
-0
src/interfaces/ecpg/TODO
src/interfaces/ecpg/TODO
+4
-4
src/interfaces/ecpg/include/ecpgerrno.h
src/interfaces/ecpg/include/ecpgerrno.h
+2
-0
src/interfaces/ecpg/include/ecpglib.h
src/interfaces/ecpg/include/ecpglib.h
+4
-1
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
+2
-2
src/interfaces/ecpg/lib/ecpglib.c
src/interfaces/ecpg/lib/ecpglib.c
+210
-4
src/interfaces/ecpg/lib/typename.c
src/interfaces/ecpg/lib/typename.c
+3
-1
src/interfaces/ecpg/preproc/Makefile
src/interfaces/ecpg/preproc/Makefile
+15
-13
src/interfaces/ecpg/preproc/c_keywords.c
src/interfaces/ecpg/preproc/c_keywords.c
+1
-2
src/interfaces/ecpg/preproc/ecpg.c
src/interfaces/ecpg/preproc/ecpg.c
+18
-5
src/interfaces/ecpg/preproc/ecpg_keywords.c
src/interfaces/ecpg/preproc/ecpg_keywords.c
+14
-2
src/interfaces/ecpg/preproc/extern.h
src/interfaces/ecpg/preproc/extern.h
+7
-46
src/interfaces/ecpg/preproc/keywords.c
src/interfaces/ecpg/preproc/keywords.c
+6
-5
src/interfaces/ecpg/preproc/pgc.l
src/interfaces/ecpg/preproc/pgc.l
+27
-23
src/interfaces/ecpg/preproc/preproc.y
src/interfaces/ecpg/preproc/preproc.y
+988
-310
src/interfaces/ecpg/preproc/type.c
src/interfaces/ecpg/preproc/type.c
+20
-9
src/interfaces/ecpg/preproc/type.h
src/interfaces/ecpg/preproc/type.h
+51
-2
src/interfaces/ecpg/test/test1.pgc
src/interfaces/ecpg/test/test1.pgc
+31
-12
src/interfaces/ecpg/test/test2.pgc
src/interfaces/ecpg/test/test2.pgc
+52
-15
No files found.
src/interfaces/ecpg/ChangeLog
View file @
bf6636ba
...
...
@@ -400,3 +400,60 @@ Tue Feb 2 07:40:52 CET 1999
- Brought preproc.y in sync again with gram.y.
- Set ecpg version to 2.4.9
Wed Feb 3 18:28:46 CET 1999
- Started working on PREPARE statement.
- Fixed typo in preproc that cause CREATE statement to not work
anymore.
Thu Feb 4 19:43:39 CET 1999
- Some parts of the PREPARE statement work now.
- Added EXECUTE command
- Added DEALLOCATE PREPARE command
Fri Feb 5 18:25:07 CET 1999
- PREPARE seems to be working okay now.
- Fixed some minor bugs.
- Renamed y.tab.* to preproc.*
Mon Feb 8 07:57:29 CET 1999
- Synced preproc.y with gram.y again.
- Allow ':<name>' as positional variable in prepare statement also.
You can still specify ';;' instead of course.
- Added TYPE statement.
- Set library version to 2.7.0
Tue Feb 9 07:07:11 CET 1999
- Synced preproc.y with gram.y.
Tue Feb 9 20:21:44 CET 1999
- Added FREE statement.
Wed Feb 10 07:51:09 CET 1999
- Synced keyword.c.
Sat Feb 13 10:44:43 CET 1999
- Added DECLARE STATEMENT for compatibility with Oracle. De facto
this statement does nothing.
- Added VAR statement.
Son Feb 14 11:36:04 CET 1999
- Added type 'enum' to TYPE and VAR statement.
- Allow ecpg keywords as datatypes.
Thu Feb 18 08:35:35 CET 1999
- Make sure indicator for array is array too.
Fri Feb 19 18:38:45 CET 1999
- Finished type aliasing for structures.
- Set ecpg version to 2.5.0
src/interfaces/ecpg/TODO
View file @
bf6636ba
...
...
@@ -11,10 +11,10 @@ DESCRIPTOR statement will be ignored.
it would be nice to be able to use :var[:index] as cvariable
'at DB connection' is missing for several commands (is this standard?)
support for unions
Missing statements:
- exec sql type
- exec sql prepare
- exec sql allocate
- exqc sql free
- SQLSTATE
- exec sql whenever sqlwarning
src/interfaces/ecpg/include/ecpgerrno.h
View file @
bf6636ba
...
...
@@ -28,6 +28,8 @@
#define ECPG_NO_CONN -220
#define ECPG_NOT_CONN -221
#define ECPG_INVALID_STMT -230
/* finally the backend error messages, they start at 400 */
#define ECPG_PGSQL -400
#define ECPG_TRANS -401
...
...
src/interfaces/ecpg/include/ecpglib.h
View file @
bf6636ba
...
...
@@ -11,6 +11,9 @@ extern "C"
bool
ECPGdo
(
int
,
char
*
,...);
bool
ECPGtrans
(
int
,
const
char
*
);
bool
ECPGdisconnect
(
int
,
const
char
*
);
bool
ECPGprepare
(
int
,
char
*
,
char
*
);
bool
ECPGdeallocate
(
int
,
char
*
);
char
*
ECPGprepared_statement
(
char
*
);
void
ECPGlog
(
const
char
*
format
,...);
...
...
src/interfaces/ecpg/include/ecpgtype.h
View file @
bf6636ba
...
...
@@ -45,7 +45,8 @@ extern "C"
ECPGt_struct
,
ECPGt_EOIT
,
/* End of insert types. */
ECPGt_EORT
,
/* End of result types. */
ECPGt_NO_INDICATOR
/* no indicator */
ECPGt_NO_INDICATOR
,
/* no indicator */
ECPGt_char_variable
};
#define IS_SIMPLE_TYPE(type) ((type) >= ECPGt_char && (type) <= ECPGt_varchar2)
...
...
src/interfaces/ecpg/lib/Makefile.in
View file @
bf6636ba
...
...
@@ -6,13 +6,13 @@
# Copyright (c) 1994, Regents of the University of California
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.4
0 1999/01/21 20:01:32
scrappy Exp $
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.4
1 1999/02/20 07:00:53
scrappy Exp $
#
#-------------------------------------------------------------------------
NAME
=
ecpg
SO_MAJOR_VERSION
=
2
SO_MINOR_VERSION
=
6.3
SO_MINOR_VERSION
=
7.0
SRCDIR
=
@top_srcdir@
include
$(SRCDIR)/Makefile.global
...
...
src/interfaces/ecpg/lib/ecpglib.c
View file @
bf6636ba
...
...
@@ -81,6 +81,13 @@ struct statement
struct
variable
*
outlist
;
};
struct
prepared_statement
{
char
*
name
;
struct
statement
*
stmt
;
struct
prepared_statement
*
next
;
}
*
prep_stmts
=
NULL
;
static
int
simple_debug
=
0
;
static
FILE
*
debugstream
=
NULL
;
static
int
committed
=
true
;
...
...
@@ -196,6 +203,41 @@ quote_postgres(char *arg, int lineno)
return
res
;
}
/* This function returns a newly malloced string that has the \
in the strings inside the argument quoted with another \.
*/
static
char
*
quote_strings
(
char
*
arg
,
int
lineno
)
{
char
*
res
=
(
char
*
)
ecpg_alloc
(
2
*
strlen
(
arg
)
+
1
,
lineno
);
int
i
,
ri
;
bool
string
=
false
;
if
(
!
res
)
return
(
res
);
for
(
i
=
0
,
ri
=
0
;
arg
[
i
];
i
++
,
ri
++
)
{
switch
(
arg
[
i
])
{
case
'\''
:
string
=
string
?
false
:
true
;
break
;
case
'\\'
:
res
[
ri
++
]
=
'\\'
;
default:
;
}
res
[
ri
]
=
arg
[
i
];
}
res
[
ri
]
=
'\0'
;
return
res
;
}
/* create a list of variables */
static
bool
create_statement
(
int
lineno
,
struct
statement
**
stmt
,
char
*
query
,
va_list
ap
)
...
...
@@ -237,6 +279,14 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
var
->
ind_offset
=
va_arg
(
ap
,
long
);
var
->
next
=
NULL
;
if
(
var
->
value
==
NULL
)
{
ECPGlog
(
"create_statement: invalid statement name
\n
"
);
register_error
(
ECPG_INVALID_STMT
,
"Invalid statement name in line %d"
,
lineno
);
free
(
var
);
return
false
;
}
for
(
ptr
=
*
list
;
ptr
&&
ptr
->
next
;
ptr
=
ptr
->
next
);
if
(
ptr
==
NULL
)
...
...
@@ -251,6 +301,19 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
return
(
true
);
}
static
char
*
next_insert
(
char
*
text
)
{
char
*
ptr
=
text
;
bool
string
=
false
;
for
(;
ptr
[
1
]
!=
'\0'
&&
(
ptr
[
0
]
!=
';'
||
ptr
[
1
]
!=
';'
||
string
);
ptr
++
)
if
(
ptr
[
0
]
==
'\''
)
string
=
string
?
false
:
true
;
return
(
ptr
[
1
]
==
'\0'
)
?
NULL
:
ptr
;
}
static
bool
ECPGexecute
(
struct
statement
*
stmt
)
{
...
...
@@ -379,7 +442,30 @@ ECPGexecute(struct statement * stmt)
tobeinserted
=
mallocedval
;
}
break
;
case
ECPGt_char_variable
:
{
/* set slen to string length if type is char * */
int
slen
=
(
var
->
varcharsize
==
0
)
?
strlen
((
char
*
)
var
->
value
)
:
var
->
varcharsize
;
char
*
tmp
;
if
(
!
(
newcopy
=
ecpg_alloc
(
slen
+
1
,
stmt
->
lineno
)))
return
false
;
strncpy
(
newcopy
,
(
char
*
)
var
->
value
,
slen
);
newcopy
[
slen
]
=
'\0'
;
if
(
!
(
mallocedval
=
(
char
*
)
ecpg_alloc
(
2
*
strlen
(
newcopy
)
+
1
,
stmt
->
lineno
)))
return
false
;
tmp
=
quote_strings
(
newcopy
,
stmt
->
lineno
);
if
(
!
tmp
)
return
false
;
strcat
(
mallocedval
,
tmp
);
free
(
newcopy
);
tobeinserted
=
mallocedval
;
}
break
;
case
ECPGt_varchar
:
{
struct
ECPGgeneric_varchar
*
variable
=
...
...
@@ -428,7 +514,7 @@ ECPGexecute(struct statement * stmt)
return
false
;
strcpy
(
newcopy
,
copiedquery
);
if
((
p
=
strstr
(
newcopy
,
";;"
))
==
NULL
)
if
((
p
=
next_insert
(
newcopy
))
==
NULL
)
{
/*
...
...
@@ -449,7 +535,7 @@ ECPGexecute(struct statement * stmt)
strcat
(
newcopy
,
copiedquery
+
(
p
-
newcopy
)
+
2
/* Length of ;; */
);
+
sizeof
(
";;"
)
-
1
/* don't count the '\0' */
);
}
/*
...
...
@@ -470,7 +556,7 @@ ECPGexecute(struct statement * stmt)
}
/* Check if there are unmatched things left. */
if
(
strstr
(
copiedquery
,
";;"
)
!=
NULL
)
if
(
next_insert
(
copiedquery
)
!=
NULL
)
{
register_error
(
ECPG_TOO_FEW_ARGUMENTS
,
"Too few arguments line %d."
,
stmt
->
lineno
);
return
false
;
...
...
@@ -898,7 +984,21 @@ ECPGtrans(int lineno, const char *transaction)
PQclear
(
res
);
}
if
(
strcmp
(
transaction
,
"commit"
)
==
0
||
strcmp
(
transaction
,
"rollback"
)
==
0
)
{
struct
prepared_statement
*
this
;
committed
=
1
;
/* deallocate all prepared statements */
for
(
this
=
prep_stmts
;
this
!=
NULL
;
this
=
this
->
next
)
{
bool
b
=
ECPGdeallocate
(
lineno
,
this
->
name
);
if
(
!
b
)
return
false
;
}
}
return
TRUE
;
}
...
...
@@ -1033,3 +1133,109 @@ sqlprint(void)
sqlca
.
sqlerrm
.
sqlerrmc
[
sqlca
.
sqlerrm
.
sqlerrml
]
=
'\0'
;
printf
(
"sql error %s
\n
"
,
sqlca
.
sqlerrm
.
sqlerrmc
);
}
static
void
replace_variables
(
char
*
text
)
{
char
*
ptr
=
text
;
bool
string
=
false
;
for
(;
*
ptr
!=
'\0'
;
ptr
++
)
{
if
(
*
ptr
==
'\''
)
string
=
string
?
false
:
true
;
if
(
!
string
&&
*
ptr
==
':'
)
{
ptr
[
0
]
=
ptr
[
1
]
=
';'
;
for
(
ptr
+=
2
;
*
ptr
&&
*
ptr
!=
' '
;
ptr
++
)
*
ptr
=
' '
;
}
}
}
/* handle the EXEC SQL PREPARE statement */
bool
ECPGprepare
(
int
lineno
,
char
*
name
,
char
*
variable
)
{
struct
statement
*
stmt
;
struct
prepared_statement
*
this
;
/* check if we already have prepared this statement */
for
(
this
=
prep_stmts
;
this
!=
NULL
&&
strcmp
(
this
->
name
,
name
)
!=
0
;
this
=
this
->
next
);
if
(
this
)
{
bool
b
=
ECPGdeallocate
(
lineno
,
name
);
if
(
!
b
)
return
false
;
}
this
=
(
struct
prepared_statement
*
)
ecpg_alloc
(
sizeof
(
struct
prepared_statement
),
lineno
);
if
(
!
this
)
return
false
;
stmt
=
(
struct
statement
*
)
ecpg_alloc
(
sizeof
(
struct
statement
),
lineno
);
if
(
!
stmt
)
{
free
(
this
);
return
false
;
}
/* create statement */
stmt
->
lineno
=
lineno
;
stmt
->
command
=
ecpg_strdup
(
variable
,
lineno
);
stmt
->
inlist
=
stmt
->
outlist
=
NULL
;
/* if we have C variables in our statment replace them with ';;' */
replace_variables
(
stmt
->
command
);
/* add prepared statement to our list */
this
->
name
=
ecpg_strdup
(
name
,
lineno
);
this
->
stmt
=
stmt
;
if
(
prep_stmts
==
NULL
)
this
->
next
=
NULL
;
else
this
->
next
=
prep_stmts
;
prep_stmts
=
this
;
return
true
;
}
/* handle the EXEC SQL DEALLOCATE PREPARE statement */
bool
ECPGdeallocate
(
int
lineno
,
char
*
name
)
{
struct
prepared_statement
*
this
,
*
prev
;
/* check if we really have prepared this statement */
for
(
this
=
prep_stmts
,
prev
=
NULL
;
this
!=
NULL
&&
strcmp
(
this
->
name
,
name
)
!=
0
;
prev
=
this
,
this
=
this
->
next
);
if
(
this
)
{
/* okay, free all the resources */
free
(
this
->
name
);
free
(
this
->
stmt
->
command
);
free
(
this
->
stmt
);
if
(
prev
!=
NULL
)
prev
->
next
=
this
->
next
;
else
prep_stmts
=
this
->
next
;
return
true
;
}
ECPGlog
(
"deallocate_prepare: invalid statement name %s
\n
"
,
name
);
register_error
(
ECPG_INVALID_STMT
,
"Invalid statement name %s in line %d"
,
name
,
lineno
);
return
false
;
}
/* return the prepared statement */
char
*
ECPGprepared_statement
(
char
*
name
)
{
struct
prepared_statement
*
this
;
for
(
this
=
prep_stmts
;
this
!=
NULL
&&
strcmp
(
this
->
name
,
name
)
!=
0
;
this
=
this
->
next
);
return
(
this
)
?
this
->
stmt
->
command
:
NULL
;
}
src/interfaces/ecpg/lib/typename.c
View file @
bf6636ba
...
...
@@ -32,6 +32,8 @@ ECPGtype_name(enum ECPGttype typ)
return
"bool"
;
case
ECPGt_varchar
:
return
"varchar"
;
case
ECPGt_char_variable
:
return
"char"
;
default:
abort
();
}
...
...
src/interfaces/ecpg/preproc/Makefile
View file @
bf6636ba
...
...
@@ -2,20 +2,25 @@ SRCDIR= ../../..
include
$(SRCDIR)/Makefile.global
MAJOR_VERSION
=
2
MINOR_VERSION
=
4
PATCHLEVEL
=
9
MINOR_VERSION
=
5
PATCHLEVEL
=
0
CFLAGS
+=
-I
../include
-DMAJOR_VERSION
=
$(MAJOR_VERSION)
\
-DMINOR_VERSION
=
$(MINOR_VERSION)
-DPATCHLEVEL
=
$(PATCHLEVEL)
\
-DINCLUDE_PATH
=
\"
$(DESTDIR)$(HEADERDIR)
\"
OBJ
=
y.tab
.o pgc.o type.o ecpg.o ecpg_keywords.o ../../../backend/parser/scansup.o
\
OBJ
=
preproc
.o pgc.o type.o ecpg.o ecpg_keywords.o ../../../backend/parser/scansup.o
\
keywords.o c_keywords.o ../lib/typename.o
all
::
ecpg
preproc.c preproc.h
:
preproc.y
$(YACC)
$(YFLAGS)
$<
mv
y.tab.c preproc.c
mv
y.tab.h preproc.h
clean
:
rm
-f
*
.o core a.out ecpg
$(X)
y.tab.h y.tab.c pgc.c
*
~
rm
-f
*
.o core a.out ecpg
$(X)
*
~
install
:
all
$(INSTALL)
$(INSTL_EXE_OPTS)
ecpg
$(X)
$(DESTDIR)$(BINDIR)
...
...
@@ -31,13 +36,10 @@ pgc.c: pgc.l
$(LEX)
$<
mv
lex.yy.c pgc.c
y.tab.h y.tab.c
:
preproc.y
$(YACC)
$(YFLAGS)
$<
y.tab.o
:
y.tab.h ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c
preproc.o
:
preproc.h ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c
type.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
pgc.o
:
../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c
preproc
.h
keywords.o
:
../include/ecpgtype.h
preproc
.h
c_keywords.o
:
../include/ecpgtype.h
preproc.h
ecpg_keywords.o
:
../include/ecpgtype.h
preproc.h
src/interfaces/ecpg/preproc/c_keywords.c
View file @
bf6636ba
...
...
@@ -9,9 +9,8 @@
#include <string.h>
#include "postgres.h"
#include "type.h"
#include "y.tab.h"
#include "extern.h"
#include "preproc.h"
/*
* List of (keyword-name, keyword-token-value) pairs.
...
...
src/interfaces/ecpg/preproc/ecpg.c
View file @
bf6636ba
...
...
@@ -25,6 +25,7 @@ extern char *optarg;
struct
_include_path
*
include_paths
;
int
no_auto_trans
=
0
;
struct
cursor
*
cur
=
NULL
;
struct
typedefs
*
types
=
NULL
;
static
void
usage
(
char
*
progname
)
...
...
@@ -155,22 +156,22 @@ main(int argc, char *const argv[])
{
struct
cursor
*
ptr
;
struct
_defines
*
defptr
;
struct
typedefs
*
typeptr
;
/* remove old cursor definitions if any are still there */
for
(
ptr
=
cur
;
ptr
!=
NULL
;)
{
struct
cursor
*
this
=
ptr
;
struct
arguments
*
l1
,
*
l2
;
struct
arguments
*
l1
,
*
l2
;
free
(
ptr
->
command
);
free
(
ptr
->
name
);
for
(
l1
=
argsinsert
;
l1
;
l1
=
l2
)
for
(
l1
=
ptr
->
argsinsert
;
l1
;
l1
=
l2
)
{
l2
=
l1
->
next
;
free
(
l1
);
}
for
(
l1
=
argsresult
;
l1
;
l1
=
l2
)
for
(
l1
=
ptr
->
argsresult
;
l1
;
l1
=
l2
)
{
l2
=
l1
->
next
;
free
(
l1
);
...
...
@@ -190,6 +191,18 @@ main(int argc, char *const argv[])
free
(
this
);
}
/* and old typedefs */
for
(
typeptr
=
types
;
typeptr
!=
NULL
;)
{
struct
typedefs
*
this
=
typeptr
;
free
(
typeptr
->
name
);
free
(
typeptr
->
type
);
ECPGfree_struct_member
(
typeptr
->
struct_member_list
);
typeptr
=
typeptr
->
next
;
free
(
this
);
}
/* initialize lex */
lex_init
();
...
...
src/interfaces/ecpg/preproc/ecpg_keywords.c
View file @
bf6636ba
...
...
@@ -9,9 +9,8 @@
#include <string.h>
#include "postgres.h"
#include "type.h"
#include "extern.h"
#include "
y.tab
.h"
#include "
preproc
.h"
/*
* List of (keyword-name, keyword-token-value) pairs.
...
...
@@ -21,25 +20,38 @@
*/
static
ScanKeyword
ScanKeywords
[]
=
{
/* name value */
{
"bool"
,
SQL_BOOL
},
{
"break"
,
SQL_BREAK
},
{
"call"
,
SQL_CALL
},
{
"connect"
,
SQL_CONNECT
},
{
"connection"
,
SQL_CONNECTION
},
{
"continue"
,
SQL_CONTINUE
},
{
"deallocate"
,
SQL_DEALLOCATE
},
{
"disconnect"
,
SQL_DISCONNECT
},
{
"enum"
,
SQL_ENUM
},
{
"found"
,
SQL_FOUND
},
{
"free"
,
SQL_FREE
},
{
"go"
,
SQL_GO
},
{
"goto"
,
SQL_GOTO
},
{
"identified"
,
SQL_IDENTIFIED
},
{
"immediate"
,
SQL_IMMEDIATE
},
{
"indicator"
,
SQL_INDICATOR
},
{
"int"
,
SQL_INT
},
{
"long"
,
SQL_LONG
},
{
"open"
,
SQL_OPEN
},
{
"prepare"
,
SQL_PREPARE
},
{
"reference"
,
SQL_REFERENCE
},
{
"release"
,
SQL_RELEASE
},
{
"section"
,
SQL_SECTION
},
{
"short"
,
SQL_SHORT
},
{
"signed"
,
SQL_SIGNED
},
{
"sqlerror"
,
SQL_SQLERROR
},
{
"sqlprint"
,
SQL_SQLPRINT
},
{
"sqlwarning"
,
SQL_SQLWARNING
},
{
"stop"
,
SQL_STOP
},
{
"struct"
,
SQL_STRUCT
},
{
"unsigned"
,
SQL_UNSIGNED
},
{
"var"
,
SQL_VAR
},
{
"whenever"
,
SQL_WHENEVER
},
};
...
...
src/interfaces/ecpg/preproc/extern.h
View file @
bf6636ba
#include "parser/keywords.h"
#include "type.h"
#include <errno.h>
/* variables */
extern
int
braces_open
,
no_auto_trans
;
no_auto_trans
,
struct_level
;
extern
char
*
yytext
;
extern
int
yylineno
,
yyleng
;
extern
FILE
*
yyin
,
*
yyout
;
struct
_include_path
{
char
*
path
;
struct
_include_path
*
next
;
};
extern
struct
_include_path
*
include_paths
;
struct
cursor
{
char
*
name
;
char
*
command
;
struct
arguments
*
argsinsert
;
struct
arguments
*
argsresult
;
struct
cursor
*
next
;
};
extern
struct
cursor
*
cur
;
struct
_defines
{
char
*
old
;
char
*
new
;
struct
_defines
*
next
;
};
extern
struct
typedefs
*
types
;
extern
struct
_defines
*
defines
;
/* 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
;
struct
arguments
{
struct
variable
*
variable
;
struct
variable
*
indicator
;
struct
arguments
*
next
;
};
extern
struct
arguments
*
argsinsert
;
extern
struct
arguments
*
argsresult
;
...
...
@@ -77,6 +37,7 @@ extern void yyerror(char *);
#define OK 0
#define PARSE_ERROR -1
#define ILLEGAL_OPTION -2
#define INDICATOR_NOT_ARRAY -3
#define NO_INCLUDE_FILE ENOENT
#define OUT_OF_MEMORY ENOMEM
src/interfaces/ecpg/preproc/keywords.c
View file @
bf6636ba
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.1
0 1999/02/13 23:22:35 momjian
Exp $
* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.1
1 1999/02/20 07:01:00 scrappy
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -18,7 +18,7 @@
#include "nodes/parsenodes.h"
#include "nodes/pg_list.h"
#include "type.h"
#include "
y.tab
.h"
#include "
preproc
.h"
#include "parser/keywords.h"
#include "utils/elog.h"
...
...
@@ -69,9 +69,6 @@ static ScanKeyword ScanKeywords[] = {
{
"createdb"
,
CREATEDB
},
{
"createuser"
,
CREATEUSER
},
{
"cross"
,
CROSS
},
{
"current"
,
CURRENT
},
/* 6.4 to 6.5 is migration time! CURRENT
* will be removed in 6.5! Use OLD keyword
* in rules. Jan */
{
"current_date"
,
CURRENT_DATE
},
{
"current_time"
,
CURRENT_TIME
},
{
"current_timestamp"
,
CURRENT_TIMESTAMP
},
...
...
@@ -96,6 +93,7 @@ static ScanKeyword ScanKeywords[] = {
{
"end"
,
END_TRANS
},
/***S*I***/
{
"except"
,
EXCEPT
},
{
"execute"
,
EXECUTE
},
{
"exists"
,
EXISTS
},
{
"explain"
,
EXPLAIN
},
...
...
@@ -125,6 +123,7 @@ static ScanKeyword ScanKeywords[] = {
{
"instead"
,
INSTEAD
},
/***S*I***/
{
"intersect"
,
INTERSECT
},
{
"interval"
,
INTERVAL
},
{
"into"
,
INTO
},
{
"is"
,
IS
},
...
...
@@ -138,6 +137,7 @@ static ScanKeyword ScanKeywords[] = {
{
"left"
,
LEFT
},
{
"level"
,
LEVEL
},
{
"like"
,
LIKE
},
{
"limit"
,
LIMIT
},
{
"listen"
,
LISTEN
},
{
"load"
,
LOAD
},
{
"local"
,
LOCAL
},
...
...
@@ -167,6 +167,7 @@ static ScanKeyword ScanKeywords[] = {
{
"nullif"
,
NULLIF
},
{
"numeric"
,
NUMERIC
},
{
"of"
,
OF
},
{
"offset"
,
OFFSET
},
{
"oids"
,
OIDS
},
{
"old"
,
CURRENT
},
{
"on"
,
ON
},
...
...
src/interfaces/ecpg/preproc/pgc.l
View file @
bf6636ba
...
...
@@ -24,9 +24,8 @@
#include "nodes/parsenodes.h"
#include "parser/gramparse.h"
#include "parser/scansup.h"
#include "type.h"
#include "extern.h"
#include "
y.tab
.h"
#include "
preproc
.h"
#include "utils/builtins.h"
/* some versions of lex define this as a macro */
...
...
@@ -241,7 +240,7 @@ cppline {space}*#.*(\\{space}*\n)*\n*
}
<xq>{xqstop} {
BEGIN(SQL);
yylval.str = strdup(scanstr(literal));
yylval.str =
mm_
strdup(scanstr(literal));
return SCONST;
}
<xq>{xqdouble} |
...
...
@@ -276,7 +275,7 @@ cppline {space}*#.*(\\{space}*\n)*\n*
}
<xd>{xdstop} {
BEGIN(SQL);
yylval.str = strdup(literal);
yylval.str =
mm_
strdup(literal);
return CSTRING;
}
<xd>{xdinside} {
...
...
@@ -292,7 +291,7 @@ cppline {space}*#.*(\\{space}*\n)*\n*
}
<xdc>{xdstop} {
BEGIN(C);
yylval.str = strdup(literal);
yylval.str =
mm_
strdup(literal);
return CSTRING;
}
<xdc>{xdinside} {
...
...
@@ -316,14 +315,14 @@ cppline {space}*#.*(\\{space}*\n)*\n*
}
<SQL>{self} { return yytext[0]; }
<SQL>{operator}/-[\.0-9] {
yylval.str = strdup((char*)yytext);
yylval.str =
mm_
strdup((char*)yytext);
return Op;
}
<SQL>{operator} {
if (strcmp((char*)yytext,"!=") == 0)
yylval.str = strdup("<>"); /* compatability */
yylval.str =
mm_
strdup("<>"); /* compatability */
else
yylval.str = strdup((char*)yytext);
yylval.str =
mm_
strdup((char*)yytext);
return Op;
}
<SQL>{param} {
...
...
@@ -342,7 +341,6 @@ cppline {space}*#.*(\\{space}*\n)*\n*
if (isascii((unsigned char)lower_text[i]) && isupper(lower_text[i]))
lower_text[i] = tolower(lower_text[i]);
printf("yyt= %s, lt = %s\n", yytext, lower_text);
keyword = ScanKeywordLookup((char*)lower_text);
if (keyword != NULL) {
return keyword->value;
...
...
@@ -367,7 +365,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
yb->buffer = YY_CURRENT_BUFFER;
yb->lineno = yylineno;
yb->filename = strdup(input_filename);
yb->filename =
mm_
strdup(input_filename);
yb->next = yy_buffer;
yy_buffer = yb;
...
...
@@ -378,7 +376,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
}
if (ptr == NULL)
{
yylval.str = strdup((char*)yytext);
yylval.str =
mm_
strdup((char*)yytext);
return IDENT;
}
}
...
...
@@ -470,7 +468,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
return ICONST;
}
<SQL>:{identifier}(("->"|\.){identifier})* {
yylval.str = strdup((char*)yytext+1);
yylval.str =
mm_
strdup((char*)yytext+1);
return(CVARIABLE);
}
<SQL>{identifier} {
...
...
@@ -484,7 +482,6 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
if (isascii((unsigned char)lower_text[i]) && isupper(lower_text[i]))
lower_text[i] = tolower(lower_text[i]);
printf("yyt= %s, lt = %s\n", yytext, lower_text);
keyword = ScanKeywordLookup((char*)lower_text);
if (keyword != NULL) {
return keyword->value;
...
...
@@ -509,7 +506,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
yb->buffer = YY_CURRENT_BUFFER;
yb->lineno = yylineno;
yb->filename = strdup(input_filename);
yb->filename =
mm_
strdup(input_filename);
yb->next = yy_buffer;
yy_buffer = yb;
...
...
@@ -520,19 +517,26 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
}
if (ptr == NULL)
{
yylval.str = strdup((char*)yytext);
yylval.str =
mm_
strdup((char*)yytext);
return IDENT;
}
}
}
}
<SQL>{space} { /* ignore */ }
<SQL>";" { BEGIN C; return SQL_SEMI; }
<SQL>";" { /*
* We may find a ';' inside a structure
* definition in a TYPE or VAR statement.
* This is not a EOL marker.
*/
if (struct_level == 0)
BEGIN C;
return SQL_SEMI; }
<SQL>{other} { return yytext[0]; }
<C>{exec}{space}{sql} { BEGIN SQL; return SQL_START; }
<C>{ccomment} { /* ignore */ }
<C>{cppline} {
yylval.str = strdup((char*)yytext);
yylval.str =
mm_
strdup((char*)yytext);
return(CPP_LINE);
}
<C>{identifier} {
...
...
@@ -556,7 +560,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
yb->buffer = YY_CURRENT_BUFFER;
yb->lineno = yylineno;
yb->filename = strdup(input_filename);
yb->filename =
mm_
strdup(input_filename);
yb->next = yy_buffer;
yy_buffer = yb;
...
...
@@ -567,7 +571,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
}
if (ptr == NULL)
{
yylval.str = strdup((char*)yytext);
yylval.str =
mm_
strdup((char*)yytext);
return IDENT;
}
}
...
...
@@ -585,7 +589,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
<C>{exec}{space}{sql}{space}{define} {BEGIN(def_ident);}
<def_ident>{space} {}
<def_ident>{identifier} {
old = strdup(yytext);
old =
mm_
strdup(yytext);
BEGIN(def);
llen = 0;
*literal = '\0';
...
...
@@ -599,7 +603,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
if (strcmp(old, ptr->old) == 0)
{
free(ptr->new);
ptr->new = strdup(scanstr(literal));
ptr->new =
mm_
strdup(scanstr(literal));
}
}
if (ptr == NULL)
...
...
@@ -608,7 +612,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
/* initial definition */
this->old = old;
this->new = strdup(scanstr(literal));
this->new =
mm_
strdup(scanstr(literal));
this->next = defines;
defines = this;
}
...
...
@@ -666,7 +670,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
exit(NO_INCLUDE_FILE);
}
input_filename = strdup(inc_file);
input_filename =
mm_
strdup(inc_file);
yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
yylineno = 0;
...
...
src/interfaces/ecpg/preproc/preproc.y
View file @
bf6636ba
...
...
@@ -6,7 +6,6 @@
#include "catalog/catname.h"
#include "utils/numeric.h"
#include "type.h"
#include "extern.h"
#ifdef MULTIBYTE
...
...
@@ -18,10 +17,10 @@
/*
* Variables containing simple states.
*/
static
int struct_level = 0;
int struct_level = 0;
static char errortext[128];
static int QueryIsRule = 0, ForUpdateNotAllowed = 0;
static
enum ECPGt
type actual_type[STRUCT_DEPTH];
static
struct this_
type actual_type[STRUCT_DEPTH];
static char *actual_storage[STRUCT_DEPTH];
/* temporarily store struct members while creating the data structure */
...
...
@@ -30,6 +29,8 @@ struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL };
struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, 0L, {NULL}};
struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};
struct ECPGtype ecpg_query = {ECPGt_char_variable, 0L, {NULL}};
/*
* Handle the filename and line numbering.
*/
...
...
@@ -505,6 +506,98 @@ output_statement(char * stmt, int mode)
free(stmt);
}
static struct typedefs *
get_typedef(char *name)
{
struct typedefs *this;
for (this = types; this && strcmp(this->name, name); this = this->next);
if (!this)
{
sprintf(errortext, "invalid datatype '%s'", name);
yyerror(errortext);
}
return(this);
}
static void
adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dimension, int type_index, bool pointer)
{
if (type_index >= 0)
{
if (*length >= 0)
yyerror("No multi-dimensional array support");
*length = type_index;
}
if (type_dimension >= 0)
{
if (*dimension >= 0 && *length >= 0)
yyerror("No multi-dimensional array support");
if (*dimension >= 0)
*length = *dimension;
*dimension = type_dimension;
}
switch (type_enum)
{
case ECPGt_struct:
/* pointer has to get dimension 0 */
if (pointer)
{
*length = *dimension;
*dimension = 0;
}
if (*length >= 0)
yyerror("No multi-dimensional array support for structures");
break;
case ECPGt_varchar:
/* pointer has to get length 0 */
if (pointer)
*length=0;
/* one index is the string length */
if (*length < 0)
{
*length = *dimension;
*dimension = -1;
}
break;
case ECPGt_char:
case ECPGt_unsigned_char:
/* pointer has to get length 0 */
if (pointer)
*length=0;
/* one index is the string length */
if (*length < 0)
{
*length = (*dimension < 0) ? 1 : *dimension;
*dimension = -1;
}
break;
default:
/* a pointer has dimension = 0 */
if (pointer) {
*length = *dimension;
*dimension = 0;
}
if (*length >= 0)
yyerror("No multi-dimensional array support for simple data types");
break;
}
}
%}
%union {
...
...
@@ -519,12 +612,15 @@ output_statement(char * stmt, int mode)
}
/* special embedded SQL token */
%token SQL_BREAK SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE
%token SQL_DISCONNECT SQL_FOUND SQL_GO SQL_GOTO
%token SQL_IDENTIFIED SQL_IMMEDIATE SQL_INDICATOR SQL_OPEN
%token SQL_PREPARE SQL_RELEASE
%token SQL_SECTION SQL_SEMI SQL_SQLERROR SQL_SQLPRINT SQL_START
%token SQL_STOP SQL_WHENEVER SQL_SQLWARNING
%token SQL_BOOL SQL_BREAK
%token SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE
%token SQL_DEALLOCATE SQL_DISCONNECT SQL_ENUM
%token SQL_FOUND SQL_FREE SQL_GO SQL_GOTO
%token SQL_IDENTIFIED SQL_IMMEDIATE SQL_INDICATOR SQL_INT SQL_LONG
%token SQL_OPEN SQL_PREPARE SQL_RELEASE SQL_REFERENCE
%token SQL_SECTION SQL_SEMI SQL_SHORT SQL_SIGNED SQL_SQLERROR SQL_SQLPRINT
%token SQL_SQLWARNING SQL_START SQL_STOP SQL_STRUCT SQL_UNSIGNED
%token SQL_VAR SQL_WHENEVER
/* C token */
%token S_ANYTHING S_AUTO S_BOOL S_CHAR S_CONST S_DOUBLE S_ENUM S_EXTERN
...
...
@@ -577,9 +673,9 @@ output_statement(char * stmt, int mode)
DATABASE, DELIMITERS, DO, EACH, ENCODING, EXPLAIN, EXTEND,
FORWARD, FUNCTION, HANDLER,
INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
LANCOMPILER, LISTEN, UNLISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MOVE,
LANCOMPILER, LI
MIT, LI
STEN, UNLISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MOVE,
NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL,
OIDS, OPERATOR, PASSWORD, PROCEDURAL,
O
FFSET, O
IDS, OPERATOR, PASSWORD, PROCEDURAL,
RECIPE, RENAME, RESET, RETURNS, ROW, RULE,
SERIAL, SEQUENCE, SETOF, SHOW, START, STATEMENT, STDIN, STDOUT, TRUSTED,
UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
...
...
@@ -654,8 +750,9 @@ output_statement(char * stmt, int mode)
%type <str> index_opt_unique IndexStmt set_opt func_return def_rest
%type <str> func_args_list func_args opt_with ProcedureStmt def_arg
%type <str> def_elem def_list definition def_name def_type DefineStmt
%type <str> opt_instead event event_object OptStmtMulti OptStmtBlock
%type <str> OptStmtList RuleStmt opt_column opt_name oper_argtypes
%type <str> opt_instead event event_object RuleActionList,
%type <str> RuleActionBlock RuleActionMulti
%type <str> RuleStmt opt_column opt_name oper_argtypes
%type <str> MathOp RemoveFuncStmt aggr_argtype for_update_clause
%type <str> RemoveAggrStmt remove_type RemoveStmt ExtendStmt RecipeStmt
%type <str> RemoveOperStmt RenameStmt all_Op user_valid_clause
...
...
@@ -665,7 +762,7 @@ output_statement(char * stmt, int mode)
%type <str> user_createuser_clause user_group_list user_group_clause
%type <str> CreateUserStmt AlterUserStmt CreateSeqStmt OptSeqList
%type <str> OptSeqElem TriggerForSpec TriggerForOpt TriggerForType
%type <str> DropTrigStmt TriggerOneEvent TriggerEvents
%type <str> DropTrigStmt TriggerOneEvent TriggerEvents
RuleActionStmt
%type <str> TriggerActionTime CreateTrigStmt DropPLangStmt PLangTrusted
%type <str> CreatePLangStmt IntegerOnly TriggerFuncArgs TriggerFuncArg
%type <str> ViewStmt LoadStmt CreatedbStmt opt_database1 opt_database2 location
...
...
@@ -673,27 +770,32 @@ output_statement(char * stmt, int mode)
%type <str> GrantStmt privileges operation_commalist operation
%type <str> cursor_clause opt_cursor opt_readonly opt_of opt_lmode
%type <str> case_expr when_clause_list case_default case_arg when_clause
%type <str> select_w_o_sort
%type <str> select_w_o_sort opt_select_limit select_limit_value,
%type <str> select_offset_value
%type <str> ECPGWhenever ECPGConnect connection_target ECPGOpen op
en_opts
%type <str> indicator ECPGExecute ecpg_expr dotext
%type <str> ECPGWhenever ECPGConnect connection_target ECPGOpen op
t_using
%type <str> indicator ECPGExecute ecpg_expr dotext
ECPGPrepare
%type <str> storage_clause opt_initializer vartext c_anything blockstart
%type <str> blockend variable_list variable var_anything do_anything
%type <str> opt_pointer cvariable ECPGDisconnect dis_name
%type <str> stmt symbol opt_symbol ECPGRelease execstring server_name
%type <str> connection_object opt_server opt_port c_thing
%type <str> connection_object opt_server opt_port c_thing
opt_reference
%type <str> user_name opt_user char_variable ora_user ident
%type <str> db_prefix server opt_options opt_connection_name
%type <str> ECPGSetConnection c_line cpp_line s_enum
%type <str> enum_type
%type <str> ECPGSetConnection c_line cpp_line s_enum ECPGTypedef
%type <str> enum_type civariableonly ECPGCursorStmt ECPGDeallocate
%type <str> ECPGFree ECPGDeclare ECPGVar sql_variable_declarations
%type <str> sql_declaration sql_variable_list sql_variable
%type <str> struct_type s_struct declaration variable_declarations
%type <type_enum> simple_type
%type <type_enum> simple_type
varchar_type
%type <type> type
%type <type> type
ctype
%type <action> action
%type <index> opt_array_bounds nest_array_bounds
%type <index> opt_array_bounds nest_array_bounds opt_type_array_bounds
%type <index> nest_type_array_bounds
%%
prog: statements;
...
...
@@ -769,13 +871,29 @@ stmt: AddAttrStmt { output_statement($1, 0); }
whenever_action(0);
free($1);
}
| ECPGCursorStmt {
fputs($1, yyout);
free($1);
}
| ECPGDeallocate {
fputs($1, yyout);
whenever_action(0);
free($1);
}
| ECPGDeclare {
fputs($1, yyout);
free($1);
}
| ECPGDisconnect {
fprintf(yyout, "ECPGdisconnect(__LINE__, \"%s\");", $1);
whenever_action(0);
free($1);
}
| ECPGExecute {
fprintf(yyout, "ECPGdo(__LINE__, %s, ECPGt_EOIT, ECPGt_EORT);", $1);
output_statement($1, 0);
}
| ECPGFree {
fprintf(yyout, "ECPGdeallocate(__LINE__, \"%s\");", $1);
whenever_action(0);
free($1);
}
...
...
@@ -797,26 +915,39 @@ stmt: AddAttrStmt { output_statement($1, 0); }
fprintf(yyout, "ECPGdo(__LINE__, \"%s\",", ptr->command);
/* dump variables to C file*/
dump_variables(ptr->argsinsert, 0);
dump_variables(argsinsert, 0);
fputs("ECPGt_EOIT, ", yyout);
dump_variables(ptr->argsresult, 0);
fputs("ECPGt_EORT);", yyout);
whenever_action(0);
free($1);
}
| ECPGPrepare {
fprintf(yyout, "ECPGprepare(__LINE__, %s);", $1);
whenever_action(0);
free($1);
}
| ECPGRelease { /* output already done */ }
| ECPGSetConnection {
fprintf(yyout, "ECPGsetconn(__LINE__, %s);", $1);
whenever_action(0);
free($1);
}
| ECPGTypedef {
fputs($1, yyout);
free($1);
}
| ECPGVar {
fputs($1, yyout);
free($1);
}
| ECPGWhenever {
fputs($1, yyout);
output_line_number();
free($1);
}
| ECPGPrepare {
yyerror("PREPARE is not supported yet.");
}
;
/*
* We start with a lot of stuff that's very similar to the backend's parsing
...
...
@@ -1098,7 +1229,7 @@ copy_delimiter: USING DELIMITERS Sconst { $$ = cat2_str(make1_str("using delim
CreateStmt: CREATE OptTemp TABLE relation_name '(' OptTableElementList ')'
OptInherit
{
$$ = cat
5_str(make1_str("create"), $2, make1_str("table"
), make3_str(make1_str("("), $6, make1_str(")")), $8);
$$ = cat
3_str(cat4_str(make1_str("create"), $2, make1_str("table"), $4
), make3_str(make1_str("("), $6, make1_str(")")), $8);
}
;
...
...
@@ -2127,40 +2258,37 @@ opt_column: COLUMN { $$ = make1_str("colmunn"); }
RuleStmt: CREATE RULE name AS
{ QueryIsRule=1; }
ON event TO event_object where_clause
DO opt_instead
OptStmt
List
DO opt_instead
RuleAction
List
{
$$ = cat2_str(cat5_str(cat5_str(make1_str("create rule"), $3, make1_str("as on"), $7, make1_str("to")), $9, $10, make1_str("do"), $12), $13);
}
;
OptStmtList: NOTHING { $$ = make1_str("nothing"); }
| OptimizableStmt { $$ = $1; }
| '[' OptStmtBlock ']' { $$ = cat3_str(make1_str("["), $2, make1_str("]")); }
/***S*I*D***/
/* We comment this out because it produces a shift / reduce conflict
* with the select_w_o_sort rule */
/* | '(' OptStmtBlock ')' { $$ = cat3_str(make1_str("("), $2, make1_str(")")); }*/
RuleActionList: NOTHING { $$ = make1_str("nothing"); }
| SelectStmt { $$ = $1; }
| RuleActionStmt { $$ = $1; }
| '[' RuleActionBlock ']' { $$ = cat3_str(make1_str("["), $2, make1_str("]")); }
| '(' RuleActionBlock ')' { $$ = cat3_str(make1_str("("), $2, make1_str(")")); }
;
OptStmtBlock: OptStmtMulti
{ $$ = $1; }
| OptimizableStmt
{ $$ = $1; }
RuleActionBlock: RuleActionMulti { $$ = $1; }
| RuleActionStmt { $$ = $1; }
;
OptStmtMulti: OptStmtMulti OptimizableStmt ';'
RuleActionMulti: RuleActionMulti RuleActionStmt
{ $$ = cat2_str($1, $2); }
| RuleActionMulti RuleActionStmt ';'
{ $$ = cat3_str($1, $2, make1_str(";")); }
/***S*I***/
/* We comment the next rule because it seems to be redundant
* and produces 16 shift/reduce conflicts with the new SelectStmt rule
* needed for EXCEPT and INTERSECT. So far I did not notice any
* violations by removing the rule! */
/* | OptStmtMulti OptimizableStmt
{ $$ = cat2_str($1, $2); }*/
| OptimizableStmt ';'
| RuleActionStmt ';'
{ $$ = cat2_str($1, make1_str(";")); }
;
RuleActionStmt: InsertStmt
| UpdateStmt
| DeleteStmt
| NotifyStmt
;
event_object: relation_name '.' attr_name
{
$$ = make3_str($1, make1_str("."), $3);
...
...
@@ -2588,7 +2716,7 @@ CursorStmt: DECLARE name opt_cursor CURSOR FOR SelectStmt cursor_clause
{
if (strcmp($2, ptr->name) == 0)
{
/* re-definition is a bug*/
/* re-definition is a bug
*/
sprintf(errortext, "cursor %s already defined", $2);
yyerror(errortext);
}
...
...
@@ -2642,13 +2770,13 @@ opt_of: OF columnList { $$ = make2_str(make1_str("of"), $2); }
/* The new 'SelectStmt' rule adapted for the optional use of INTERSECT EXCEPT a nd UNION
* accepts the use of '(' and ')' to select an order of set operations.
*/
SelectStmt: select_w_o_sort sort_clause for_update_clause
SelectStmt: select_w_o_sort sort_clause for_update_clause
opt_select_limit
{
if (strlen($3) > 0 && ForUpdateNotAllowed != 0)
yyerror("SELECT FOR UPDATE is not allowed in this context");
ForUpdateNotAllowed = 0;
$$ = cat
3_str($1, $2, $3
);
$$ = cat
4_str($1, $2, $3, $4
);
}
/***S*I***/
...
...
@@ -2736,6 +2864,29 @@ OptUseOp: USING Op { $$ = cat2_str(make1_str("using"), $2); }
| /*EMPTY*/ { $$ = make1_str(""); }
;
opt_select_limit: LIMIT select_limit_value ',' select_offset_value
{ $$ = cat4_str(make1_str("limit"), $2, make1_str(","), $4); }
| LIMIT select_limit_value OFFSET select_offset_value
{ $$ = cat4_str(make1_str("limit"), $2, make1_str("offset"), $4); }
| LIMIT select_limit_value
{ $$ = cat2_str(make1_str("limit"), $2);; }
| OFFSET select_offset_value LIMIT select_limit_value
{ $$ = cat4_str(make1_str("offset"), $2, make1_str("limit"), $4); }
| OFFSET select_offset_value
{ $$ = cat2_str(make1_str("offset"), $2); }
| /* EMPTY */
{ $$ = make1_str(""); }
;
select_limit_value: Iconst { $$ = $1; }
| ALL { $$ = make1_str("all"); }
| PARAM { $$ = make_name(); }
;
select_offset_value: Iconst { $$ = $1; }
| PARAM { $$ = make_name(); }
;
/*
* jimmy bell-style recursive queries aren't supported in the
* current system.
...
...
@@ -2952,6 +3103,36 @@ Generic: generic
generic: ident { $$ = $1; }
| TYPE_P { $$ = make1_str("type"); }
| SQL_BOOL { $$ = make1_str("bool"); }
| SQL_BREAK { $$ = make1_str("break"); }
| SQL_CALL { $$ = make1_str("call"); }
| SQL_CONNECT { $$ = make1_str("connect"); }
| SQL_CONNECTION { $$ = make1_str("connection"); }
| SQL_CONTINUE { $$ = make1_str("continue"); }
| SQL_DEALLOCATE { $$ = make1_str("deallocate"); }
| SQL_DISCONNECT { $$ = make1_str("disconnect"); }
| SQL_FOUND { $$ = make1_str("found"); }
| SQL_GO { $$ = make1_str("go"); }
| SQL_GOTO { $$ = make1_str("goto"); }
| SQL_IDENTIFIED { $$ = make1_str("identified"); }
| SQL_IMMEDIATE { $$ = make1_str("immediate"); }
| SQL_INDICATOR { $$ = make1_str("indicator"); }
| SQL_INT { $$ = make1_str("int"); }
| SQL_LONG { $$ = make1_str("long"); }
| SQL_OPEN { $$ = make1_str("open"); }
| SQL_PREPARE { $$ = make1_str("prepare"); }
| SQL_RELEASE { $$ = make1_str("release"); }
| SQL_SECTION { $$ = make1_str("section"); }
| SQL_SHORT { $$ = make1_str("short"); }
| SQL_SIGNED { $$ = make1_str("signed"); }
| SQL_SQLERROR { $$ = make1_str("sqlerror"); }
| SQL_SQLPRINT { $$ = make1_str("sqlprint"); }
| SQL_SQLWARNING { $$ = make1_str("sqlwarning"); }
| SQL_STOP { $$ = make1_str("stop"); }
| SQL_STRUCT { $$ = make1_str("struct"); }
| SQL_UNSIGNED { $$ = make1_str("unsigned"); }
| SQL_VAR { $$ = make1_str("var"); }
| SQL_WHENEVER { $$ = make1_str("whenever"); }
;
/* SQL92 numeric data types
...
...
@@ -3638,7 +3819,7 @@ b_expr: attr opt_indirection
$$ = make3_str(make1_str("trim("), $3, make1_str(")"));
}
| civariableonly
{
$$ = make1_str(";;")
; }
{
$$ = $1
; }
;
opt_indirection: '[' ecpg_expr ']' opt_indirection
...
...
@@ -4125,6 +4306,36 @@ ColId: ident { $$ = $1; }
| VALID { $$ = make1_str("valid"); }
| VERSION { $$ = make1_str("version"); }
| ZONE { $$ = make1_str("zone"); }
| SQL_BOOL { $$ = make1_str("bool"); }
| SQL_BREAK { $$ = make1_str("break"); }
| SQL_CALL { $$ = make1_str("call"); }
| SQL_CONNECT { $$ = make1_str("connect"); }
| SQL_CONNECTION { $$ = make1_str("connection"); }
| SQL_CONTINUE { $$ = make1_str("continue"); }
| SQL_DEALLOCATE { $$ = make1_str("deallocate"); }
| SQL_DISCONNECT { $$ = make1_str("disconnect"); }
| SQL_FOUND { $$ = make1_str("found"); }
| SQL_GO { $$ = make1_str("go"); }
| SQL_GOTO { $$ = make1_str("goto"); }
| SQL_IDENTIFIED { $$ = make1_str("identified"); }
| SQL_IMMEDIATE { $$ = make1_str("immediate"); }
| SQL_INDICATOR { $$ = make1_str("indicator"); }
| SQL_INT { $$ = make1_str("int"); }
| SQL_LONG { $$ = make1_str("long"); }
| SQL_OPEN { $$ = make1_str("open"); }
| SQL_PREPARE { $$ = make1_str("prepare"); }
| SQL_RELEASE { $$ = make1_str("release"); }
| SQL_SECTION { $$ = make1_str("section"); }
| SQL_SHORT { $$ = make1_str("short"); }
| SQL_SIGNED { $$ = make1_str("signed"); }
| SQL_SQLERROR { $$ = make1_str("sqlerror"); }
| SQL_SQLPRINT { $$ = make1_str("sqlprint"); }
| SQL_SQLWARNING { $$ = make1_str("sqlwarning"); }
| SQL_STOP { $$ = make1_str("stop"); }
| SQL_STRUCT { $$ = make1_str("struct"); }
| SQL_UNSIGNED { $$ = make1_str("unsigned"); }
| SQL_VAR { $$ = make1_str("var"); }
| SQL_WHENEVER { $$ = make1_str("whenever"); }
;
/* Column label
* Allowed labels in "AS" clauses.
...
...
@@ -4198,202 +4409,423 @@ SpecialRuleRelation: CURRENT
*/
/*
*
variable declaration inside the exec sql declare block
*
the exec sql connect statement: connect to the given database
*/
ECPGDeclaration: sql_startdeclare variable_declarations sql_enddeclare {}
sql_startdeclare : ecpgstart BEGIN_TRANS DECLARE SQL_SECTION SQL_SEMI {
fputs("/* exec sql begin declare section */\n", yyout);
output_line_number();
}
sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION SQL_SEMI {
fputs("/* exec sql end declare section */\n", yyout);
output_line_number();
}
variable_declarations: /* empty */
| declaration variable_declarations;
declaration: storage_clause type
ECPGConnect: SQL_CONNECT TO connection_target opt_connection_name opt_user
{
actual_storage[struct_level] = $1;
actual_type[struct_level] = $2.type_enum;
if ($2.type_enum != ECPGt_varchar && $2.type_enum != ECPGt_struct)
fprintf(yyout, "%s %s", $1, $2.type_str);
free($2.type_str);
$$ = make5_str($3, make1_str(","), $5, make1_str(","), $4);
}
variable_list ';' { fputc(';', yyout); }
storage_clause : S_EXTERN { $$ = "extern"; }
| S_STATIC { $$ = "static"; }
| S_SIGNED { $$ = "signed"; }
| S_CONST { $$ = "const"; }
| S_REGISTER { $$ = "register"; }
| S_AUTO { $$ = "auto"; }
| /* empty */ { $$ = ""; }
type: simple_type
| SQL_CONNECT TO DEFAULT
{
$$.type_enum = $1;
$$.type_str = mm_strdup(ECPGtype_name($1));
$$ = make1_str("NULL,NULL,NULL,\"DEFAULT\"");
}
| struct_type
/* also allow ORACLE syntax */
| SQL_CONNECT ora_user
{
$$.type_enum = ECPGt_struct;
$$.type_str = make1_str("");
$$ = make3_str(make1_str("NULL,"), $2, make1_str(",NULL"));
}
| enum_type
connection_target: database_name opt_server opt_port
{
$$.type_str = $1;
$$.type_enum = ECPGt_int;
/* old style: dbname[@server][:port] */
if (strlen($2) > 0 && *($2) != '@')
{
sprintf(errortext, "parse error at or near '%s'", $2);
yyerror(errortext);
}
enum_type: s_enum '{' c_line '}'
$$ = make5_str(make1_str("\""), $1, $2, $3, make1_str("\""));
}
| db_prefix server opt_port '/' database_name opt_options
{
$$ = cat4_str($1, make1_str("{"), $3, make1_str("}"));
/* new style: <tcp|unix>:postgresql://server[:port][/dbname] */
if (strncmp($2, "://", 3) != 0)
{
sprintf(errortext, "parse error at or near '%s'", $2);
yyerror(errortext);
}
s_enum: S_ENUM opt_symbol { $$ = cat2_str(make1_str("enum"), $2); }
struct_type: s_struct '{' variable_declarations '}'
if (strncmp($1, "unix", 4) == 0 && strncmp($2 + 3, "localhost", 9) != 0)
{
ECPGfree_struct_member(struct_member_list[struct_level]);
free(actual_storage[struct_level--]);
fputs("} ", yyout);
sprintf(errortext, "unix domain sockets only work on 'localhost' but not on '%9.9s'", $2);
yyerror(errortext);
}
s_struct : S_STRUCT opt_symbol
if (strncmp($1, "unix", 4) != 0 && strncmp($1, "tcp", 3) != 0)
{
struct_member_list[struct_level++] = NULL;
if (struct_level >= STRUCT_DEPTH)
yyerror("Too many levels in nested structure definition");
fprintf(yyout, "struct %s {", $2);
free($2);
sprintf(errortext, "only protocols 'tcp' and 'unix' are supported");
yyerror(errortext);
}
opt_symbol: /* empty */ { $$ = make1_str(""); }
| symbol { $$ = $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; }
variable_list: variable
| variable_list ','
$$ = make4_str(make5_str(make1_str("\""), $1, $2, $3, make1_str("/")), $5, $6, make1_str("\""));
}
| char_variable
{
if (actual_type[struct_level] != ECPGt_varchar)
fputs(", ", yyout);
else
fputs(";\n ", yyout);
} variable
variable: opt_pointer symbol opt_array_bounds opt_initializer
$$ = $1;
}
| Sconst
{
struct ECPGtype * type;
int dimension = $3.index1; /* dimension of array */
int length = $3.index2; /* lenght of string */
char dim[14L];
$$ = mm_strdup($1);
$$[0] = '\"';
$$[strlen($$) - 1] = '\"';
free($1);
}
switch (actual_type[struct_level])
db_prefix: ident cvariable
{
case ECPGt_struct:
/* pointer has to get dimension 0 */
if (strlen($1) > 0)
if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0)
{
length = dimension
;
dimension = 0;
sprintf(errortext, "parse error at or near '%s'", $2)
;
yyerror(errortext);
}
if (length >= 0)
yyerror("No multi-dimensional array support for structures");
if (dimension == 1 || dimension < 0)
type = ECPGmake_struct_type(struct_member_list[struct_level]);
else
type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level]), dimension);
fprintf(yyout, "%s%s%s%s", $1, $2, $3.str, $4);
break;
case ECPGt_varchar:
/* pointer has to get length 0 */
if (strlen($1) > 0)
length=0;
/* one index is the string length */
if (length < 0)
if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0)
{
length = dimension
;
dimension = 1
;
sprintf(errortext, "Illegal connection type %s", $1)
;
yyerror(errortext)
;
}
if (dimension == 1)
type = ECPGmake_simple_type(actual_type[struct_level], length);
else
type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level], length), dimension);
switch(dimension)
{
case 0:
strcpy(dim, "[]");
break;
case 1:
*dim = '\0';
break;
default:
sprintf(dim, "[%d]", dimension);
break;
$$ = make3_str($1, make1_str(":"), $2);
}
if (length > 0)
fprintf(yyout, "%s struct varchar_%s { int len; char arr[%d]; } %s%s", actual_storage[struct_level], $2, length, $2, dim);
else
fprintf(yyout, "%s struct varchar_%s { int len; char *arr; } %s%s", actual_storage[struct_level], $2, $2, dim);
break;
case ECPGt_char:
case ECPGt_unsigned_char:
/* pointer has to get length 0 */
if (strlen($1) > 0)
length=0;
/* one index is the string length */
if (length < 0)
server: Op server_name
{
if (strcmp($1, "@") != 0 && strcmp($1, "://") != 0)
{
length = (dimension < 0) ? 1 : dimension
;
dimension = 1
;
sprintf(errortext, "parse error at or near '%s'", $1)
;
yyerror(errortext)
;
}
if (dimension == 1)
type = ECPGmake_simple_type(actual_type[struct_level], length);
else
type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level], length), dimension);
fprintf(yyout, "%s%s%s%s", $1, $2, $3.str, $4);
break;
default:
/* a pointer has dimension = 0 */
if (strlen($1) > 0) {
length = dimension;
dimension = 0;
$$ = make2_str($1, $2);
}
if (length >= 0)
yyerror("No multi-dimensional array support for simple data types");
opt_server: server { $$ = $1; }
| /* empty */ { $$ = make1_str(""); }
if (dimension == 1 || dimension < 0)
type = ECPGmake_simple_type(actual_type[struct_level], 1);
else
type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level], 1), dimension);
server_name: ColId { $$ = $1; }
| ColId '.' server_name { $$ = make3_str($1, make1_str("."), $3); }
opt_port: ':' Iconst { $$ = make2_str(make1_str(":"), $2); }
| /* empty */ { $$ = make1_str(""); }
opt_connection_name: AS connection_target { $$ = $2; }
| /* empty */ { $$ = make1_str("NULL"); }
opt_user: USER ora_user { $$ = $2; }
| /* empty */ { $$ = make1_str("NULL,NULL"); }
ora_user: user_name
{
$$ = make2_str($1, make1_str(",NULL"));
}
| user_name '/' ColId
{
$$ = make3_str($1, make1_str(","), $3);
}
| user_name SQL_IDENTIFIED BY user_name
{
$$ = make3_str($1, make1_str(","), $4);
}
| user_name USING user_name
{
$$ = make3_str($1, make1_str(","), $3);
}
user_name: UserId { if ($1[0] == '\"')
$$ = $1;
else
$$ = make3_str(make1_str("\""), $1, make1_str("\""));
}
| char_variable { $$ = $1; }
| SCONST { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); }
char_variable: 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 */
if (typ == ECPGt_array)
typ = p->type->u.element->typ;
switch (typ)
{
case ECPGt_char:
case ECPGt_unsigned_char:
$$ = $1;
break;
case ECPGt_varchar:
$$ = make2_str($1, make1_str(".arr"));
break;
default:
yyerror("invalid datatype");
break;
}
}
opt_options: Op ColId
{
if (strlen($1) == 0)
yyerror("parse error");
if (strcmp($1, "?") != 0)
{
sprintf(errortext, "parse error at or near %s", $1);
yyerror(errortext);
}
$$ = make2_str(make1_str("?"), $2);
}
| /* empty */ { $$ = make1_str(""); }
/*
* Declare a prepared cursor. The syntax is different from the standard
* declare statement, so we create a new rule.
*/
ECPGCursorStmt: DECLARE name opt_cursor CURSOR FOR ident cursor_clause
{
struct cursor *ptr, *this;
struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
for (ptr = cur; ptr != NULL; ptr = ptr->next)
{
if (strcmp($2, ptr->name) == 0)
{
/* re-definition is a bug */
sprintf(errortext, "cursor %s already defined", $2);
yyerror(errortext);
}
}
this = (struct cursor *) mm_alloc(sizeof(struct cursor));
/* initial definition */
this->next = cur;
this->name = $2;
this->command = cat5_str(make1_str("declare"), mm_strdup($2), $3, make1_str("cursor for ;;"), $7);
this->argsresult = NULL;
thisquery->type = &ecpg_query;
thisquery->brace_level = 0;
thisquery->next = NULL;
thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(\"\")") + strlen($6));
sprintf(thisquery->name, "ECPGprepared_statement(\"%s\")", $6);
this->argsinsert = NULL;
add_variable(&(this->argsinsert), thisquery, &no_indicator);
cur = this;
$$ = cat3_str(make1_str("/*"), mm_strdup(this->command), make1_str("*/"));
}
;
/*
* the exec sql deallocate prepare command to deallocate a previously
* prepared statement
*/
ECPGDeallocate: SQL_DEALLOCATE SQL_PREPARE ident { $$ = make3_str(make1_str("ECPGdeallocate(__LINE__, \""), $3, make1_str("\");")); }
/*
* variable declaration inside the exec sql declare block
*/
ECPGDeclaration: sql_startdeclare
{
fputs("/* exec sql begin declare section */", yyout);
output_line_number();
}
variable_declarations sql_enddeclare
{
fprintf(yyout, "%s/* exec sql end declare section */", $3);
free($3);
output_line_number();
}
sql_startdeclare : ecpgstart BEGIN_TRANS DECLARE SQL_SECTION SQL_SEMI {}
sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION SQL_SEMI {}
variable_declarations: /* empty */
{
$$ = make1_str("");
}
| declaration variable_declarations
{
$$ = cat2_str($1, $2);
}
declaration: storage_clause
{
actual_storage[struct_level] = mm_strdup($1);
}
type
{
actual_type[struct_level].type_enum = $3.type_enum;
actual_type[struct_level].type_dimension = $3.type_dimension;
actual_type[struct_level].type_index = $3.type_index;
}
variable_list ';'
{
$$ = cat4_str($1, $3.type_str, $5, make1_str(";\n"));
}
storage_clause : S_EXTERN { $$ = make1_str("extern"); }
| S_STATIC { $$ = make1_str("static"); }
| S_SIGNED { $$ = make1_str("signed"); }
| S_CONST { $$ = make1_str("const"); }
| S_REGISTER { $$ = make1_str("register"); }
| S_AUTO { $$ = make1_str("auto"); }
| /* empty */ { $$ = make1_str(""); }
type: simple_type
{
$$.type_enum = $1;
$$.type_str = mm_strdup(ECPGtype_name($1));
$$.type_dimension = -1;
$$.type_index = -1;
}
| varchar_type
{
$$.type_enum = ECPGt_varchar;
$$.type_str = make1_str("");
$$.type_dimension = -1;
$$.type_index = -1;
}
| struct_type
{
$$.type_enum = ECPGt_struct;
$$.type_str = $1;
$$.type_dimension = -1;
$$.type_index = -1;
}
| enum_type
{
$$.type_str = $1;
$$.type_enum = ECPGt_int;
$$.type_dimension = -1;
$$.type_index = -1;
}
| symbol
{
/* this is for typedef'ed types */
struct typedefs *this = get_typedef($1);
$$.type_str = mm_strdup(this->name);
$$.type_enum = this->type->type_enum;
$$.type_dimension = this->type->type_dimension;
$$.type_index = this->type->type_index;
struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
}
enum_type: s_enum '{' c_line '}'
{
$$ = cat4_str($1, make1_str("{"), $3, make1_str("}"));
}
s_enum: S_ENUM opt_symbol { $$ = cat2_str(make1_str("enum"), $2); }
struct_type: s_struct '{' variable_declarations '}'
{
ECPGfree_struct_member(struct_member_list[struct_level]);
free(actual_storage[struct_level--]);
$$ = cat4_str($1, make1_str("{"), $3, make1_str("}"));
}
s_struct : S_STRUCT opt_symbol
{
struct_member_list[struct_level++] = NULL;
if (struct_level >= STRUCT_DEPTH)
yyerror("Too many levels in nested structure definition");
$$ = cat2_str(make1_str("struct"), $2);
}
opt_symbol: /* empty */ { $$ = make1_str(""); }
| symbol { $$ = $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; }
varchar_type: S_VARCHAR { $$ = ECPGt_varchar; }
variable_list: variable
{
$$ = $1;
}
| variable_list ',' variable
{
$$ = cat3_str($1, make1_str(","), $3);
}
fprintf(yyout, "%s%s%s%s", $1, $2, $3.str, $4);
variable: opt_pointer symbol opt_array_bounds opt_initializer
{
struct ECPGtype * type;
int dimension = $3.index1; /* dimension of array */
int length = $3.index2; /* lenght of string */
char dim[14L], ascii_len[12];
adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension, actual_type[struct_level].type_index, strlen($1));
switch (actual_type[struct_level].type_enum)
{
case ECPGt_struct:
if (dimension < 0)
type = ECPGmake_struct_type(struct_member_list[struct_level]);
else
type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level]), dimension);
$$ = make4_str($1, mm_strdup($2), $3.str, $4);
break;
case ECPGt_varchar:
if (dimension == -1)
type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
else
type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
switch(dimension)
{
case 0:
strcpy(dim, "[]");
break;
case -1:
case 1:
*dim = '\0';
break;
default:
sprintf(dim, "[%d]", dimension);
break;
}
sprintf(ascii_len, "%d", length);
if (length > 0)
$$ = make4_str(make5_str(mm_strdup(actual_storage[struct_level]), make1_str(" struct varchar_"), mm_strdup($2), make1_str(" { int len; char arr["), mm_strdup(ascii_len)), make1_str("]; } "), mm_strdup($2), mm_strdup(dim));
else
$$ = make4_str(make3_str(mm_strdup(actual_storage[struct_level]), make1_str(" struct varchar_"), mm_strdup($2)), make1_str(" { int len; char *arr; } "), mm_strdup($2), mm_strdup(dim));
break;
case ECPGt_char:
case ECPGt_unsigned_char:
if (dimension == -1)
type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
else
type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
$$ = make4_str($1, mm_strdup($2), $3.str, $4);
break;
default:
if (dimension < 0)
type = ECPGmake_simple_type(actual_type[struct_level].type_enum, 1);
else
type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, 1), dimension);
$$ = make4_str($1, mm_strdup($2), $3.str, $4);
break;
}
...
...
@@ -4402,10 +4834,7 @@ variable: opt_pointer symbol opt_array_bounds opt_initializer
else
ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1]));
free($1);
free($2);
free($3.str);
free($4);
}
opt_initializer: /* empty */ { $$ = make1_str(""); }
...
...
@@ -4414,234 +4843,490 @@ opt_initializer: /* empty */ { $$ = make1_str(""); }
opt_pointer: /* empty */ { $$ = make1_str(""); }
| '*' { $$ = make1_str("*"); }
/*
* the exec sql connect statement: connect to the given database
*/
ECPGConnect: SQL_CONNECT TO connection_target opt_connection_name opt_user
/*
* As long as the prepare statement is not supported by the backend, we will
* try to simulate it here so we get dynamic SQL
*/
ECPGDeclare: DECLARE STATEMENT ident
{
/* this is only supported for compatibility */
$$ = cat3_str(make1_str("/* declare statement"), $3, make1_str("*/"));
}
/*
* the exec sql disconnect statement: disconnect from the given database
*/
ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; }
dis_name: connection_object { $$ = $1; }
| CURRENT { $$ = make1_str("CURRENT"); }
| ALL { $$ = make1_str("ALL"); }
| /* empty */ { $$ = make1_str("CURRENT"); }
connection_object: connection_target { $$ = $1; }
| DEFAULT { $$ = make1_str("DEFAULT"); }
/*
* execute a given string as sql command
*/
ECPGExecute : EXECUTE SQL_IMMEDIATE execstring
{
struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
thisquery->type = &ecpg_query;
thisquery->brace_level = 0;
thisquery->next = NULL;
thisquery->name = $3;
add_variable(&argsinsert, thisquery, &no_indicator);
$$ = make1_str(";;");
}
| EXECUTE ident
{
struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
thisquery->type = &ecpg_query;
thisquery->brace_level = 0;
thisquery->next = NULL;
thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(\"\")") + strlen($2));
sprintf(thisquery->name, "ECPGprepared_statement(\"%s\")", $2);
add_variable(&argsinsert, thisquery, &no_indicator);
} opt_using
{
$$ = make1_str(";;");
}
execstring: char_variable |
CSTRING { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); };
/*
* the exec sql free command to deallocate a previously
* prepared statement
*/
ECPGFree: SQL_FREE ident { $$ = $2; }
/*
* open is an open cursor, at the moment this has to be removed
*/
ECPGOpen: SQL_OPEN name opt_using {
$$ = $2;
};
opt_using: /* empty */ { $$ = make1_str(""); }
| USING variablelist {
/* yyerror ("open cursor with variables not implemented yet"); */
$$ = make1_str("");
}
variablelist: cinputvariable | cinputvariable ',' variablelist
/*
* As long as the prepare statement is not supported by the backend, we will
* try to simulate it here so we get dynamic SQL
*/
ECPGPrepare: SQL_PREPARE ident FROM char_variable
{
$$ = make4_str(make1_str("\""), $2, make1_str("\", "), $4);
}
/*
* for compatibility with ORACLE we will also allow the keyword RELEASE
* after a transaction statement to disconnect from the database.
*/
ECPGRelease: TransactionStmt SQL_RELEASE
{
if (strncmp($1, "begin", 5) == 0)
yyerror("RELEASE does not make sense when beginning a transaction");
fprintf(yyout, "ECPGtrans(__LINE__, \"%s\");", $1);
whenever_action(0);
fprintf(yyout, "ECPGdisconnect(\"\");");
whenever_action(0);
free($1);
}
/*
* set the actual connection, this needs a differnet handling as the other
* set commands
*/
ECPGSetConnection: SET SQL_CONNECTION connection_object
{
$$ = $3;
}
/*
* define a new type for embedded SQL
*/
ECPGTypedef: TYPE_P symbol IS ctype opt_type_array_bounds opt_reference
{
/* add entry to list */
struct typedefs *ptr, *this;
int dimension = $5.index1;
int length = $5.index2;
for (ptr = types; ptr != NULL; ptr = ptr->next)
{
if (strcmp($2, ptr->name) == 0)
{
/* re-definition is a bug */
sprintf(errortext, "type %s already defined", $2);
yyerror(errortext);
}
}
adjust_array($4.type_enum, &dimension, &length, $4.type_dimension, $4.type_index, strlen($6));
this = (struct typedefs *) mm_alloc(sizeof(struct typedefs));
/* initial definition */
this->next = types;
this->name = $2;
this->type = (struct this_type *) mm_alloc(sizeof(struct this_type));
this->type->type_enum = $4.type_enum;
this->type->type_str = mm_strdup($2);
this->type->type_dimension = dimension; /* dimension of array */
this->type->type_index = length; /* lenght of string */
this->struct_member_list = struct_member_list[struct_level];
if ($4.type_enum != ECPGt_varchar &&
$4.type_enum != ECPGt_char &&
$4.type_enum != ECPGt_unsigned_char &&
this->type->type_index >= 0)
yyerror("No multi-dimensional array support for simple data types");
types = this;
$$ = cat5_str(cat3_str(make1_str("/* exec sql type"), mm_strdup($2), make1_str("is")), mm_strdup($4.type_str), mm_strdup($5.str), $6, make1_str("*/"));
}
opt_type_array_bounds: '[' ']' nest_type_array_bounds
{
$$.index1 = 0;
$$.index2 = $3.index1;
$$.str = cat2_str(make1_str("[]"), $3.str);
}
| '(' ')' nest_type_array_bounds
{
$$.index1 = 0;
$$.index2 = $3.index1;
$$.str = cat2_str(make1_str("[]"), $3.str);
}
| '[' Iconst ']' nest_type_array_bounds
{
$$.index1 = atol($2);
$$.index2 = $4.index1;
$$.str = cat4_str(make1_str("["), $2, make1_str("]"), $4.str);
}
| '(' Iconst ')' nest_type_array_bounds
{
$$.index1 = atol($2);
$$.index2 = $4.index1;
$$.str = cat4_str(make1_str("["), $2, make1_str("]"), $4.str);
}
| /* EMPTY */
{
$$.index1 = -1;
$$.index2 = -1;
$$.str= make1_str("");
}
;
nest_type_array_bounds: '[' ']' nest_type_array_bounds
{
$$ = make5_str($3, make1_str(","), $5, make1_str(","), $4);
$$.index1 = 0;
$$.index2 = $3.index1;
$$.str = cat2_str(make1_str("[]"), $3.str);
}
| SQL_CONNECT TO DEFAULT
| '(' ')' nest_type_array_bounds
{
$$ = make1_str("NULL,NULL,NULL,\"DEFAULT\"");
$$.index1 = 0;
$$.index2 = $3.index1;
$$.str = cat2_str(make1_str("[]"), $3.str);
}
/* also allow ORACLE syntax */
| SQL_CONNECT ora_user
| '[' Iconst ']' nest_type_array_bounds
{
$$ = make3_str(make1_str("NULL,"), $2, make1_str(",NULL"));
$$.index1 = atol($2);
$$.index2 = $4.index1;
$$.str = cat4_str(make1_str("["), $2, make1_str("]"), $4.str);
}
connection_target: database_name opt_server opt_port
| '(' Iconst ')' nest_type_array_bounds
{
/* old style: dbname[@server][:port] */
if (strlen($2) > 0 && *($2) != '@')
$$.index1 = atol($2);
$$.index2 = $4.index1;
$$.str = cat4_str(make1_str("["), $2, make1_str("]"), $4.str);
}
| /* EMPTY */
{
sprintf(errortext, "parse error at or near '%s'", $2);
yyerror(errortext);
$$.index1 = -1;
$$.index2 = -1;
$$.str= make1_str("");
}
;
opt_reference: SQL_REFERENCE { $$ = make1_str("reference"); }
| /* empty */ { $$ = make1_str(""); }
$$ = make5_str(make1_str("\""), $1, $2, $3, make1_str("\""));
ctype: CHAR
{
$$.type_str = make1_str("char");
$$.type_enum = ECPGt_char;
$$.type_index = -1;
$$.type_dimension = -1;
}
| db_prefix server opt_port '/' database_name opt_options
| VARCHAR
{
/* new style: <tcp|unix>:postgresql://server[:port][/dbname] */
if (strncmp($2, "://", 3) != 0)
$$.type_str = make1_str("varchar");
$$.type_enum = ECPGt_varchar;
$$.type_index = -1;
$$.type_dimension = -1;
}
| FLOAT
{
sprintf(errortext, "parse error at or near '%s'", $2);
yyerror(errortext);
$$.type_str = make1_str("float");
$$.type_enum = ECPGt_float;
$$.type_index = -1;
$$.type_dimension = -1;
}
if (strncmp($1, "unix", 4) == 0 && strncmp($2 + 3, "localhost", 9) != 0)
| DOUBLE
{
sprintf(errortext, "unix domain sockets only work on 'localhost' but not on '%9.9s'", $2);
yyerror(errortext);
$$.type_str = make1_str("double");
$$.type_enum = ECPGt_double;
$$.type_index = -1;
$$.type_dimension = -1;
}
if (strncmp($1, "unix", 4) != 0 && strncmp($1, "tcp", 3) != 0)
| opt_signed SQL_INT
{
sprintf(errortext, "only protocols 'tcp' and 'unix' are supported");
yyerror(errortext);
$$.type_str = make1_str("int");
$$.type_enum = ECPGt_int;
$$.type_index = -1;
$$.type_dimension = -1;
}
$$ = make4_str(make5_str(make1_str("\""), $1, $2, $3, make1_str("/")), $5, $6, make1_str("\""));
| SQL_ENUM
{
$$.type_str = make1_str("int");
$$.type_enum = ECPGt_int;
$$.type_index = -1;
$$.type_dimension = -1;
}
|
char_variable
|
opt_signed SQL_SHORT
{
$$ = $1;
$$.type_str = make1_str("short");
$$.type_enum = ECPGt_short;
$$.type_index = -1;
$$.type_dimension = -1;
}
|
Sconst
|
opt_signed SQL_LONG
{
$$ = mm_strdup($1
);
$$[0] = '\"'
;
$$[strlen($$) - 1] = '\"'
;
free($1)
;
$$.type_str = make1_str("long"
);
$$.type_enum = ECPGt_long
;
$$.type_index = -1
;
$$.type_dimension = -1
;
}
db_prefix: ident cvariable
| SQL_BOOL
{
if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0)
$$.type_str = make1_str("bool");
$$.type_enum = ECPGt_bool;
$$.type_index = -1;
$$.type_dimension = -1;
}
| SQL_UNSIGNED SQL_INT
{
sprintf(errortext, "parse error at or near '%s'", $2);
yyerror(errortext);
$$.type_str = make1_str("unsigned int");
$$.type_enum = ECPGt_unsigned_int;
$$.type_index = -1;
$$.type_dimension = -1;
}
if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0)
| SQL_UNSIGNED SQL_SHORT
{
sprintf(errortext, "Illegal connection type %s", $1);
yyerror(errortext);
$$.type_str = make1_str("unsigned short");
$$.type_enum = ECPGt_unsigned_short;
$$.type_index = -1;
$$.type_dimension = -1;
}
$$ = make3_str($1, make1_str(":"), $2);
| SQL_UNSIGNED SQL_LONG
{
$$.type_str = make1_str("unsigned long");
$$.type_enum = ECPGt_unsigned_long;
$$.type_index = -1;
$$.type_dimension = -1;
}
server: Op server_name
| SQL_STRUCT
{
if (strcmp($1, "@") != 0 && strcmp($1, "://") != 0)
struct_member_list[struct_level++] = NULL;
if (struct_level >= STRUCT_DEPTH)
yyerror("Too many levels in nested structure definition");
} '{' sql_variable_declarations '}'
{
sprintf(errortext, "parse error at or near '%s'", $1);
yyerror(errortext);
ECPGfree_struct_member(struct_member_list[struct_level--]);
$$.type_str = cat3_str(make1_str("struct {"), $4, make1_str("}"));
$$.type_enum = ECPGt_struct;
$$.type_index = -1;
$$.type_dimension = -1;
}
| symbol
{
struct typedefs *this = get_typedef($1);
$$ = make2_str($1, $2);
$$.type_str = mm_strdup($1);
$$.type_enum = this->type->type_enum;
$$.type_dimension = this->type->type_dimension;
$$.type_index = this->type->type_index;
struct_member_list[struct_level] = this->struct_member_list;
}
opt_server: server { $$ = $1; }
| /* empty */ { $$ = make1_str(""); }
server_name: ColId { $$ = $1; }
| ColId '.' server_name { $$ = make3_str($1, make1_str("."), $3); }
opt_port: ':' Iconst { $$ = make2_str(make1_str(":"), $2); }
| /* empty */ { $$ = make1_str(""); }
opt_connection_name: AS connection_target { $$ = $2; }
| /* empty */ { $$ = make1_str("NULL"); }
opt_signed: SQL_SIGNED | /* empty */
opt_user: USER ora_user { $$ = $2; }
| /* empty */ { $$ = make1_str("NULL,NULL"); }
ora_user: user_name
sql_variable_declarations: /* empty */
{
$$ = make2_str($1, make1_str(",NULL")
);
$$ = make1_str(""
);
}
|
user_name '/' ColId
|
sql_declaration sql_variable_declarations
{
$$ = make3_str($1, make1_str(","), $3
);
$$ = cat2_str($1, $2
);
}
| user_name SQL_IDENTIFIED BY user_name
;
sql_declaration: ctype
{
$$ = make3_str($1, make1_str(","), $4);
actual_type[struct_level].type_enum = $1.type_enum;
actual_type[struct_level].type_dimension = $1.type_dimension;
actual_type[struct_level].type_index = $1.type_index;
}
| user_name USING user_name
sql_variable_list SQL_SEMI
{
$$ = make3_str($1, make1_str(","), $3
);
$$ = cat3_str($1.type_str, $3, make1_str(";")
);
}
user_name: UserId { if ($1[0] == '\"')
sql_variable_list: sql_variable
{
$$ = $1;
else
$$ = make3_str(make1_str("\""), $1, make1_str("\""));
}
| char_variable { $$ = $1; }
| SCONST { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); }
| sql_variable_list ',' sql_variable
{
$$ = make3_str($1, make1_str(","), $3);
}
char_variable: cvariable
{ /* check if we have a char variable */
struct variable *p = find_variable($1);
enum ECPGttype typ = p->type->typ;
sql_variable: opt_pointer symbol opt_array_bounds
{
int dimension = $3.index1;
int length = $3.index2;
struct ECPGtype * type;
char dim[14L];
/* if array see what's inside */
if (typ == ECPGt_array)
typ = p->type->u.element->typ;
adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension, actual_type[struct_level].type_index, strlen($1));
switch (typ
)
switch (actual_type[struct_level].type_enum
)
{
case ECPGt_char:
case ECPGt_unsigned_char:
$$ = $1;
case ECPGt_struct:
if (dimension < 0)
type = ECPGmake_struct_type(struct_member_list[struct_level]);
else
type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level]), dimension);
break;
case ECPGt_varchar:
$$ = make2_str($1, make1_str(".arr"));
if (dimension == -1)
type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
else
type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
switch(dimension)
{
case 0:
strcpy(dim, "[]");
break;
case -1:
case 1:
*dim = '\0';
break;
default:
yyerror("invalid datatype"
);
sprintf(dim, "[%d]", dimension
);
break;
}
}
opt_options: Op ColId
{
if (strlen($1) == 0)
yyerror("parse error");
break;
case ECPGt_char:
case ECPGt_unsigned_char:
if (dimension == -1)
type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
else
type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
if (strcmp($1, "?") != 0)
{
sprintf(errortext, "parse error at or near %s", $1);
yyerror(errortext);
break;
default:
if (length >= 0)
yyerror("No multi-dimensional array support for simple data types");
if (dimension < 0)
type = ECPGmake_simple_type(actual_type[struct_level].type_enum, 1);
else
type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, 1), dimension);
break;
}
$$ = make2_str(make1_str("?"), $2);
if (struct_level == 0)
new_variable($2, type);
else
ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1]));
$$ = cat3_str($1, $2, $3.str);
}
| /* empty */ { $$ = make1_str(""); }
/*
*
the exec sql disconnect statement: disconnect from the given database
*
define the type of one variable for embedded SQL
*/
ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; }
ECPGVar: SQL_VAR symbol IS ctype opt_type_array_bounds opt_reference
{
struct variable *p = find_variable($2);
int dimension = $5.index1;
int length = $5.index2;
struct ECPGtype * type;
dis_name: connection_object { $$ = $1; }
| CURRENT { $$ = make1_str("CURRENT"); }
| ALL { $$ = make1_str("ALL"); }
| /* empty */ { $$ = make1_str("CURRENT"); }
adjust_array($4.type_enum, &dimension, &length, $4.type_dimension, $4.type_index, strlen($6));
connection_object: connection_target { $$ = $1; }
| DEFAULT { $$ = make1_str("DEFAULT"); }
switch ($4.type_enum)
{
case ECPGt_struct:
if (dimension < 0)
type = ECPGmake_struct_type(struct_member_list[struct_level]);
else
type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level]), dimension);
break;
case ECPGt_varchar:
if (dimension == -1)
type = ECPGmake_simple_type($4.type_enum, length);
else
type = ECPGmake_array_type(ECPGmake_simple_type($4.type_enum, length), dimension);
/*
* execute a given string as sql command
*/
ECPGExecute : EXECUTE SQL_IMMEDIATE execstring { $$ = $3; };
break;
case ECPGt_char:
case ECPGt_unsigned_char:
if (dimension == -1)
type = ECPGmake_simple_type($4.type_enum, length);
else
type = ECPGmake_array_type(ECPGmake_simple_type($4.type_enum, length), dimension);
execstring: cvariable |
CSTRING { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); };
break;
default:
if (length >= 0)
yyerror("No multi-dimensional array support for simple data types");
/*
* open is an open cursor, at the moment this has to be removed
*/
ECPGOpen: SQL_OPEN name open_opts {
$$ = $2;
};
if (dimension < 0)
type = ECPGmake_simple_type($4.type_enum, 1);
else
type = ECPGmake_array_type(ECPGmake_simple_type($4.type_enum, 1), dimension);
open_opts: /* empty */ { $$ = make1_str(""); }
| USING cvariable {
yyerror ("open cursor with variables not implemented yet");
break;
}
/*
* for compatibility with ORACLE we will also allow the keyword RELEASE
* after a transaction statement to disconnect from the database.
*/
ECPGRelease: TransactionStmt SQL_RELEASE
{
if (strncmp($1, "begin", 5) == 0)
yyerror("RELEASE does not make sense when beginning a transaction");
ECPGfree_type(p->type);
p->type = type;
fprintf(yyout, "ECPGtrans(__LINE__, \"%s\");", $1);
whenever_action(0);
fprintf(yyout, "ECPGdisconnect(\"\");");
whenever_action(0);
free($1);
$$ = cat5_str(cat3_str(make1_str("/* exec sql var"), mm_strdup($2), make1_str("is")), mm_strdup($4.type_str), mm_strdup($5.str), $6, make1_str("*/"));
}
/*
* set the actual connection, this needs a differnet handling as the other
* set commands
*/
ECPGSetConnection: SET SQL_CONNECTION connection_object
{
$$ = $3;
}
/*
* whenever statement: decide what to do in case of error/no data found
* according to SQL standards we lack: SQLSTATE, CONSTRAINT and SQLEXCEPTION
...
...
@@ -4703,14 +5388,6 @@ action : SQL_CONTINUE {
$<action>$.str = cat2_str(make1_str("call"), mm_strdup($<action>$.command));
}
/*
* As long as the prepare statement in not supported by the backend, we will
* try to simulate it here so we get dynamic SQL
*/
ECPGPrepare: SQL_PREPARE name FROM name
{
}
/* some other stuff for ecpg */
ecpg_expr: attr opt_indirection
{
...
...
@@ -4987,7 +5664,7 @@ ecpg_expr: attr opt_indirection
| NOT ecpg_expr
{ $$ = cat2_str(make1_str("not"), $2); }
| civariableonly
{
$$ = make1_str(";;")
; }
{
$$ = $1
; }
;
into_list : coutputvariable | into_list ',' coutputvariable;
...
...
@@ -5010,6 +5687,7 @@ cinputvariable : cvariable indicator {
civariableonly : cvariable {
add_variable(&argsinsert, find_variable($1), &no_indicator);
$$ = make1_str(";;");
}
cvariable: CVARIABLE { $$ = $1; }
...
...
src/interfaces/ecpg/preproc/type.c
View file @
bf6636ba
...
...
@@ -2,7 +2,6 @@
#include <string.h>
#include <stdlib.h>
#include "type.h"
#include "extern.h"
/* malloc + error check */
...
...
@@ -36,8 +35,8 @@ mm_strdup(const char *string)
}
/* duplicate memberlist */
st
atic
st
ruct
ECPGstruct_member
*
struct_member_dup
(
struct
ECPGstruct_member
*
rm
)
struct
ECPGstruct_member
*
ECPG
struct_member_dup
(
struct
ECPGstruct_member
*
rm
)
{
struct
ECPGstruct_member
*
new
=
NULL
;
...
...
@@ -71,7 +70,8 @@ void
ECPGmake_struct_member
(
char
*
name
,
struct
ECPGtype
*
type
,
struct
ECPGstruct_member
**
start
)
{
struct
ECPGstruct_member
*
ptr
,
*
ne
=
(
struct
ECPGstruct_member
*
)
mm_alloc
(
sizeof
(
struct
ECPGstruct_member
));
*
ne
=
(
struct
ECPGstruct_member
*
)
mm_alloc
(
sizeof
(
struct
ECPGstruct_member
));
ne
->
name
=
strdup
(
name
);
ne
->
typ
=
type
;
...
...
@@ -112,7 +112,7 @@ ECPGmake_struct_type(struct ECPGstruct_member * rm)
{
struct
ECPGtype
*
ne
=
ECPGmake_simple_type
(
ECPGt_struct
,
1
);
ne
->
u
.
members
=
struct_member_dup
(
rm
);
ne
->
u
.
members
=
ECPG
struct_member_dup
(
rm
);
return
ne
;
}
...
...
@@ -160,6 +160,9 @@ get_type(enum ECPGttype typ)
case
ECPGt_NO_INDICATOR
:
/* no indicator */
return
(
"ECPGt_NO_INDICATOR"
);
break
;
case
ECPGt_char_variable
:
/* string that should not be quoted */
return
(
"ECPGt_char_variable"
);
break
;
default:
abort
();
}
...
...
@@ -202,23 +205,30 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *in
{
ECPGdump_a_simple
(
o
,
name
,
typ
->
u
.
element
->
typ
,
typ
->
u
.
element
->
size
,
typ
->
size
,
NULL
,
prefix
);
if
(
ind_typ
==
&
ecpg_no_indicator
)
if
(
ind_typ
->
typ
==
ECPGt_NO_INDICATOR
)
ECPGdump_a_simple
(
o
,
ind_name
,
ind_typ
->
typ
,
ind_typ
->
size
,
-
1
,
NULL
,
ind_prefix
);
else
{
if
(
ind_typ
->
typ
!=
ECPGt_array
)
{
fprintf
(
stderr
,
"Indicator for an array has to be array too.
\n
"
);
exit
(
INDICATOR_NOT_ARRAY
);
}
ECPGdump_a_simple
(
o
,
ind_name
,
ind_typ
->
u
.
element
->
typ
,
ind_typ
->
u
.
element
->
size
,
ind_typ
->
size
,
NULL
,
prefix
);
}
}
else
if
(
typ
->
u
.
element
->
typ
==
ECPGt_array
)
{
yyerror
(
"No nested arrays allowed (except strings)"
);
/*
Array of array,
*/
yyerror
(
"No nested arrays allowed (except strings)"
);
/*
array of array
*/
}
else
if
(
typ
->
u
.
element
->
typ
==
ECPGt_struct
)
{
/* Array of structs
.
*/
/* Array of structs */
ECPGdump_a_struct
(
o
,
name
,
ind_name
,
typ
->
size
,
typ
->
u
.
element
,
ind_typ
->
u
.
element
,
NULL
,
prefix
,
ind_prefix
);
}
else
yyerror
(
"Internal error: unknown datatype, ple
q
ase inform pgsql-bugs@postgresql.org"
);
yyerror
(
"Internal error: unknown datatype, please inform pgsql-bugs@postgresql.org"
);
break
;
case
ECPGt_struct
:
ECPGdump_a_struct
(
o
,
name
,
ind_name
,
1
,
typ
,
ind_typ
,
NULL
,
prefix
,
ind_prefix
);
...
...
@@ -260,6 +270,7 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
break
;
case
ECPGt_char
:
case
ECPGt_unsigned_char
:
case
ECPGt_char_variable
:
sprintf
(
offset
,
"%ld*sizeof(char)"
,
varcharsize
);
break
;
default:
...
...
src/interfaces/ecpg/preproc/type.h
View file @
bf6636ba
...
...
@@ -30,6 +30,7 @@ struct ECPGtype *ECPGmake_simple_type(enum ECPGttype, long);
struct
ECPGtype
*
ECPGmake_varchar_type
(
enum
ECPGttype
,
long
);
struct
ECPGtype
*
ECPGmake_array_type
(
struct
ECPGtype
*
,
long
);
struct
ECPGtype
*
ECPGmake_struct_type
(
struct
ECPGstruct_member
*
);
struct
ECPGstruct_member
*
ECPGstruct_member_dup
(
struct
ECPGstruct_member
*
);
/* Frees a type. */
void
ECPGfree_struct_member
(
struct
ECPGstruct_member
*
);
...
...
@@ -86,4 +87,52 @@ struct this_type
{
enum
ECPGttype
type_enum
;
char
*
type_str
;
int
type_dimension
;
int
type_index
;
};
struct
_include_path
{
char
*
path
;
struct
_include_path
*
next
;
};
struct
cursor
{
char
*
name
;
char
*
command
;
struct
arguments
*
argsinsert
;
struct
arguments
*
argsresult
;
struct
cursor
*
next
;
};
struct
typedefs
{
char
*
name
;
struct
this_type
*
type
;
struct
ECPGstruct_member
*
struct_member_list
;
struct
typedefs
*
next
;
};
struct
_defines
{
char
*
old
;
char
*
new
;
struct
_defines
*
next
;
};
/* This is a linked list of the variable names and types. */
struct
variable
{
char
*
name
;
struct
ECPGtype
*
type
;
int
brace_level
;
struct
variable
*
next
;
};
struct
arguments
{
struct
variable
*
variable
;
struct
variable
*
indicator
;
struct
arguments
*
next
;
};
src/interfaces/ecpg/test/test1.pgc
View file @
bf6636ba
...
...
@@ -4,16 +4,25 @@ exec sql whenever sqlerror sqlprint;
exec sql include sqlca;
exec sql define AMOUNT 5;
exec sql define AMOUNT 8;
exec sql type intarray is int[AMOUNT];
exec sql type string is char(6);
typedef int intarray[AMOUNT];
int
main ()
{
exec sql begin declare section;
int amount[AMOUNT];
char name[AMOUNT][8];
intarray amount;
int increment=100;
char name[AMOUNT][6];
char letter[AMOUNT][1];
char command[128];
exec sql end declare section;
char msg[128], command[128];
exec sql var name is string(AMOUNT);
char msg[128];
FILE *dbgs;
int i,j;
...
...
@@ -24,30 +33,40 @@ exec sql end declare section;
exec sql connect to mm;
strcpy(msg, "create");
exec sql create table test(name char(8), amount int);
exec sql create table test(name char(6), amount int, letter char(1));
strcpy(msg, "commit");
exec sql commit;
strcpy(msg, "execute insert 1");
sprintf(command, "insert into test(name, amount
) values ('foobar', 1
)");
sprintf(command, "insert into test(name, amount
, letter) values ('foobar', 1, 'f'
)");
exec sql execute immediate :command;
strcpy(msg, "excute insert 2");
sprintf(command, "insert into test(name, amount
) select name, amount+1
from test");
strcpy(msg, "ex
e
cute insert 2");
sprintf(command, "insert into test(name, amount
, letter) select name, amount+1, letter
from test");
exec sql execute immediate :command;
strcpy(msg, "excute insert 3");
sprintf(command, "insert into test(name, amount
) select name, amount+10
from test");
strcpy(msg, "ex
e
cute insert 3");
sprintf(command, "insert into test(name, amount
, letter) select name, amount+10, letter
from test");
exec sql execute immediate :command;
printf("Inserted %d tuples via execute immediate\n", sqlca.sqlerrd[2]);
strcpy(msg, "execute insert 4");
sprintf(command, "insert into test(name, amount, letter) select name, amount+;;, letter from test");
exec sql prepare I from :command;
exec sql execute I using :increment;
printf("Inserted %d tuples via prepared execute\n", sqlca.sqlerrd[2]);
strcpy(msg, "commit");
exec sql commit;
strcpy(msg, "select");
exec sql select name, amount
into :name, :amount
from test;
exec sql select name, amount
, letter into :name, :amount, :letter
from test;
for (i=0, j=sqlca.sqlerrd[2]; i<j; i++)
printf("name[%d]=%
8.8s, amount[%d]=%d\n", i, name[i], i, amount[i
]);
printf("name[%d]=%
6.6s\tamount[%d]=%d\tletter[%d]=%c\n", i, name[i], i, amount[i],i, letter[i][0
]);
strcpy(msg, "drop");
exec sql drop table test;
...
...
src/interfaces/ecpg/test/test2.pgc
View file @
bf6636ba
...
...
@@ -2,25 +2,30 @@
exec sql include header_test;
exec sql type c is char reference;
typedef char* c;
int
main ()
{
typedef struct { long born; short age; } birthinfo;
exec sql type birthinfo is struct { long born; short age; };
exec sql begin declare section;
struct personal_struct { varchar name[8];
struct birth_struct { long born;
short age;
} birth;
birthinfo birth;
} personal;
struct personal_indicator { short ind_name;
struct birth_indicator { short ind_born;
int ind_age;
} ind_birth;
struct personal_indicator { int ind_name;
birthinfo ind_birth;
} ind_personal;
long
ind_married;
int
ind_married;
char married[9];
c testname="Petra";
char *query="select name, born, age, married from meskes where name = :var1";
exec sql end declare section;
exec sql declare cur cursor for
exec sql var ind_married is long;
exec sql declare cur cursor for
select name, born, age, married from meskes;
char msg[128], command[128];
...
...
@@ -36,11 +41,11 @@ exec sql declare cur cursor for
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, married) values ('Petra', 19661202, 32
, '19900404');
exec sql insert into meskes(name,
married) values ('Petra'
, '19900404');
exec sql insert into meskes(name, born, age, married) values ('Michael', 19660117, 33, '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
);
exec sql insert into meskes(name, born, age) values ('Carsten', 19910103,
8
);
exec sql insert into meskes(name, born, age) values ('Marc', 19930907,
5
);
exec sql insert into meskes(name, born, age) values ('Chris', 19970923,
1
);
strcpy(msg, "commit");
exec sql commit;
...
...
@@ -53,12 +58,44 @@ exec sql declare cur cursor for
while (1) {
strcpy(msg, "fetch");
exec sql fetch in cur into :personal:ind_personal, :married:ind_married;
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);
printf("%8.8s", personal.name.arr);
if (!ind_personal.ind_birth.born)
printf(", born %d", personal.birth.born);
if (!ind_personal.ind_birth.age)
printf(", age = %d", personal.birth.age);
if (!ind_married)
printf(", married %s", married);
putchar('\n');
}
strcpy(msg, "close");
exec sql close cur;
/* and now the same query with prepare */
exec sql prepare MM from :query;
exec sql declare prep cursor for MM;
strcpy(msg, "open");
exec sql open prep using :testname;
exec sql whenever not found do break;
while (1) {
strcpy(msg, "fetch");
exec sql fetch in prep into :personal:ind_personal, :married:ind_married;
printf("%8.8s", personal.name.arr);
if (!ind_personal.ind_birth.born)
printf(", born %d", personal.birth.born);
if (!ind_personal.ind_birth.age)
printf(", age = %d", personal.birth.age);
if (!ind_married)
printf(", married %s", married);
putchar('\n');
}
strcpy(msg, "close");
exec sql close prep;
strcpy(msg, "drop");
exec sql drop table meskes;
...
...
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