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
35ba9de2
Commit
35ba9de2
authored
Feb 16, 2000
by
Michael Meskes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
*** empty log message ***
parent
988d53e5
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
1002 additions
and
22 deletions
+1002
-22
src/interfaces/ecpg/ChangeLog
src/interfaces/ecpg/ChangeLog
+5
-0
src/interfaces/ecpg/README.dynSQL
src/interfaces/ecpg/README.dynSQL
+20
-0
src/interfaces/ecpg/TODO
src/interfaces/ecpg/TODO
+0
-2
src/interfaces/ecpg/include/Makefile
src/interfaces/ecpg/include/Makefile
+2
-0
src/interfaces/ecpg/include/ecpgerrno.h
src/interfaces/ecpg/include/ecpgerrno.h
+4
-0
src/interfaces/ecpg/include/ecpglib.h
src/interfaces/ecpg/include/ecpglib.h
+12
-0
src/interfaces/ecpg/include/sql3types.h
src/interfaces/ecpg/include/sql3types.h
+38
-0
src/interfaces/ecpg/lib/Makefile.in
src/interfaces/ecpg/lib/Makefile.in
+2
-2
src/interfaces/ecpg/lib/dynamic.c
src/interfaces/ecpg/lib/dynamic.c
+290
-0
src/interfaces/ecpg/lib/ecpglib.c
src/interfaces/ecpg/lib/ecpglib.c
+17
-8
src/interfaces/ecpg/preproc/ecpg_keywords.c
src/interfaces/ecpg/preproc/ecpg_keywords.c
+5
-0
src/interfaces/ecpg/preproc/extern.h
src/interfaces/ecpg/preproc/extern.h
+1
-0
src/interfaces/ecpg/preproc/preproc.y
src/interfaces/ecpg/preproc/preproc.y
+461
-7
src/interfaces/ecpg/preproc/type.h
src/interfaces/ecpg/preproc/type.h
+14
-0
src/interfaces/ecpg/test/Makefile
src/interfaces/ecpg/test/Makefile
+4
-3
src/interfaces/ecpg/test/dyntest.pgc
src/interfaces/ecpg/test/dyntest.pgc
+127
-0
No files found.
src/interfaces/ecpg/ChangeLog
View file @
35ba9de2
...
...
@@ -809,5 +809,10 @@ Tue Feb 15 17:39:19 CET 2000
Wed Feb 16 11:57:02 CET 2000
- Fixed library to be able to input complete arrays.
Wed Feb 16 17:04:41 CET 2000
- Apply patch by Christof Petig <christof.petig@wtal.de> that adds
descriptors.
- Set library version to 3.1.0.
- Set ecpg version to 2.7.0.
src/interfaces/ecpg/README.dynSQL
0 → 100644
View file @
35ba9de2
descriptor statements have the following shortcomings
- up to now the only reasonable statement is
FETCH ... INTO SQL DESCRIPTOR <name>
no input variables allowed!
Reason: to fully support dynamic SQL the frontend/backend communication
should change to recognize input parameters.
Since this is not likely to happen in the near future and you
can cover the same functionality with the existing infrastructure
I'll leave the work to someone else.
- string buffer overflow does not always generate warnings
(beware: terminating 0 may be missing because strncpy is used)
:var=data sets sqlwarn accordingly (but not indicator)
- char variables pointing to NULL are not allocated on demand
- string truncation does not show up in indicator
src/interfaces/ecpg/TODO
View file @
35ba9de2
...
...
@@ -18,8 +18,6 @@ cvariable for an array var
How can one insert arrays from c variables?
support for dynamic SQL with unknown number of variables with DESCRIPTORS
What happens to the output variable during read if there was an
indicator-error?
...
...
src/interfaces/ecpg/include/Makefile
View file @
35ba9de2
...
...
@@ -10,11 +10,13 @@ install::
$(INSTALL)
$(INSTLOPTS)
ecpglib.h
$(HEADERDIR)
$(INSTALL)
$(INSTLOPTS)
ecpgtype.h
$(HEADERDIR)
$(INSTALL)
$(INSTLOPTS)
sqlca.h
$(HEADERDIR)
$(INSTALL)
$(INSTLOPTS)
sql3types.h
$(HEADERDIR)
uninstall
::
rm
-f
$(HEADERDIR)
/ecpgerrno.h
rm
-f
$(HEADERDIR)
/ecpglib.h
rm
-f
$(HEADERDIR)
/ecpgtype.h
rm
-f
$(HEADERDIR)
/sqlca.h
rm
-f
$(HEADERDIR)
/sql3types.h
dep depend
:
src/interfaces/ecpg/include/ecpgerrno.h
View file @
35ba9de2
...
...
@@ -29,6 +29,10 @@
#define ECPG_INVALID_STMT -230
/* dynamic SQL related */
#define ECPG_UNKNOWN_DESCRIPTOR -240
#define ECPG_INVALID_DESCRIPTOR_INDEX -241
/* 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 @
35ba9de2
#include <postgres.h>
#include <libpq-fe.h>
#ifdef __cplusplus
extern
"C"
...
...
@@ -49,6 +50,17 @@ extern "C"
#define SQLCODE sqlca.sqlcode
/* dynamic SQL */
unsigned
int
ECPGDynamicType
(
Oid
type
);
unsigned
int
ECPGDynamicType_DDT
(
Oid
type
);
PGresult
*
ECPGresultByDescriptor
(
int
line
,
const
char
*
name
);
bool
ECPGdo_descriptor
(
int
line
,
const
char
*
connection
,
const
char
*
descriptor
,
const
char
*
query
);
bool
ECPGdeallocate_desc
(
int
line
,
const
char
*
name
);
bool
ECPGallocate_desc
(
int
line
,
const
char
*
name
);
void
ECPGraise
(
int
line
,
int
code
);
#ifdef __cplusplus
}
...
...
src/interfaces/ecpg/include/sql3types.h
0 → 100644
View file @
35ba9de2
/* SQL3 dynamic type codes
*
* Copyright (c) 2000, Christof Petig <christof.petig@wtal.de>
*
* $Header: /cvsroot/pgsql/src/interfaces/ecpg/include/sql3types.h,v 1.1 2000/02/16 16:18:03 meskes Exp $
*/
/* chapter 13.1 table 2: Codes used for SQL data types in Dynamic SQL */
enum
{
SQL3_CHARACTER
=
1
,
SQL3_NUMERIC
,
SQL3_DECIMAL
,
SQL3_INTEGER
,
SQL3_SMALLINT
,
SQL3_FLOAT
,
SQL3_REAL
,
SQL3_DOUBLE_PRECISION
,
SQL3_DATE_TIME_TIMESTAMP
,
SQL3_INTERVAL
,
//10
SQL3_CHARACTER_VARYING
=
12
,
SQL3_ENUMERATED
,
SQL3_BIT
,
SQL3_BIT_VARYING
,
SQL3_BOOLEAN
,
SQL3_abstract
// the rest is xLOB stuff
};
/* chapter 13.1 table 3: Codes associated with datetime data types in Dynamic SQL */
enum
{
SQL3_DDT_DATE
=
1
,
SQL3_DDT_TIME
,
SQL3_DDT_TIMESTAMP
,
SQL3_DDT_TIME_WITH_TIME_ZONE
,
SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE
,
SQL3_DDT_ILLEGAL
/* not a datetime data type (not part of standard) */
};
src/interfaces/ecpg/lib/Makefile.in
View file @
35ba9de2
...
...
@@ -6,7 +6,7 @@
# Copyright (c) 1994, Regents of the University of California
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.5
7 2000/02/16 11:52:24
meskes Exp $
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.5
8 2000/02/16 16:18:05
meskes Exp $
#
#-------------------------------------------------------------------------
...
...
@@ -36,7 +36,7 @@ include $(SRCDIR)/Makefile.shlib
install
:
install-lib $(install-shlib-dep)
# Handmade dependencies in case make depend not done
ecpglib.o
:
ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h
ecpglib.o
:
ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h
dynamic.c
typename.o
:
typename.c ../include/ecpgtype.h
...
...
src/interfaces/ecpg/lib/dynamic.c
0 → 100644
View file @
35ba9de2
/* dynamic SQL support routines
*
* Copyright (c) 2000, Christof Petig <christof.petig@wtal.de>
*
* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/dynamic.c,v 1.1 2000/02/16 16:18:12 meskes Exp $
*/
/* I borrowed the include files from ecpglib.c, maybe we don't need all of them */
#if 0
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <locale.h>
#include <libpq-fe.h>
#include <libpq/pqcomm.h>
#include <ecpgtype.h>
#include <ecpglib.h>
#include <sqlca.h>
#endif
#include <sql3types.h>
static
struct
descriptor
{
char
*
name
;
PGresult
*
result
;
struct
descriptor
*
next
;
}
*
all_descriptors
=
NULL
;
PGconn
*
ECPG_internal_get_connection
(
char
*
name
);
unsigned
int
ECPGDynamicType
(
Oid
type
)
{
switch
(
type
)
{
case
16
:
return
SQL3_BOOLEAN
;
/* bool */
case
21
:
return
SQL3_SMALLINT
;
/* int2 */
case
23
:
return
SQL3_INTEGER
;
/* int4 */
case
25
:
return
SQL3_CHARACTER
;
/* text */
case
700
:
return
SQL3_REAL
;
/* float4 */
case
701
:
return
SQL3_DOUBLE_PRECISION
;
/* float8 */
case
1042
:
return
SQL3_CHARACTER
;
/* bpchar */
case
1043
:
return
SQL3_CHARACTER_VARYING
;
/* varchar */
case
1082
:
return
SQL3_DATE_TIME_TIMESTAMP
;
/* date */
case
1083
:
return
SQL3_DATE_TIME_TIMESTAMP
;
/* time */
case
1184
:
return
SQL3_DATE_TIME_TIMESTAMP
;
/* datetime */
case
1296
:
return
SQL3_DATE_TIME_TIMESTAMP
;
/* timestamp */
case
1700
:
return
SQL3_NUMERIC
;
/* numeric */
default:
return
-
type
;
}
}
unsigned
int
ECPGDynamicType_DDT
(
Oid
type
)
{
switch
(
type
)
{
case
1082
:
return
SQL3_DDT_DATE
;
/* date */
case
1083
:
return
SQL3_DDT_TIME
;
/* time */
case
1184
:
return
SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE
;
/* datetime */
case
1296
:
return
SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE
;
/* timestamp */
default:
return
SQL3_DDT_ILLEGAL
;
}
}
// like ECPGexecute
static
bool
execute_descriptor
(
int
lineno
,
const
char
*
query
,
struct
connection
*
con
,
PGresult
**
resultptr
)
{
bool
status
=
false
;
PGresult
*
results
;
PGnotify
*
notify
;
/* Now the request is built. */
if
(
con
->
committed
&&
!
con
->
autocommit
)
{
if
((
results
=
PQexec
(
con
->
connection
,
"begin transaction"
))
==
NULL
)
{
register_error
(
ECPG_TRANS
,
"Error in transaction processing line %d."
,
lineno
);
return
false
;
}
PQclear
(
results
);
con
->
committed
=
false
;
}
ECPGlog
(
"execute_descriptor line %d: QUERY: %s on connection %s
\n
"
,
lineno
,
query
,
con
->
name
);
results
=
PQexec
(
con
->
connection
,
query
);
if
(
results
==
NULL
)
{
ECPGlog
(
"ECPGexecute line %d: error: %s"
,
lineno
,
PQerrorMessage
(
con
->
connection
));
register_error
(
ECPG_PGSQL
,
"Postgres error: %s line %d."
,
PQerrorMessage
(
con
->
connection
),
lineno
);
}
else
{
*
resultptr
=
results
;
switch
(
PQresultStatus
(
results
))
{
int
ntuples
;
case
PGRES_TUPLES_OK
:
status
=
true
;
sqlca
.
sqlerrd
[
2
]
=
ntuples
=
PQntuples
(
results
);
if
(
ntuples
<
1
)
{
ECPGlog
(
"execute_descriptor line %d: Incorrect number of matches: %d
\n
"
,
lineno
,
ntuples
);
register_error
(
ECPG_NOT_FOUND
,
"No data found line %d."
,
lineno
);
status
=
false
;
break
;
}
break
;
#if 1
/* strictly these are not needed (yet) */
case
PGRES_EMPTY_QUERY
:
/* do nothing */
register_error
(
ECPG_EMPTY
,
"Empty query line %d."
,
lineno
);
break
;
case
PGRES_COMMAND_OK
:
status
=
true
;
sqlca
.
sqlerrd
[
1
]
=
atol
(
PQoidStatus
(
results
));
sqlca
.
sqlerrd
[
2
]
=
atol
(
PQcmdTuples
(
results
));
ECPGlog
(
"ECPGexecute line %d Ok: %s
\n
"
,
lineno
,
PQcmdStatus
(
results
));
break
;
case
PGRES_COPY_OUT
:
ECPGlog
(
"ECPGexecute line %d: Got PGRES_COPY_OUT ... tossing.
\n
"
,
lineno
);
PQendcopy
(
con
->
connection
);
break
;
case
PGRES_COPY_IN
:
ECPGlog
(
"ECPGexecute line %d: Got PGRES_COPY_IN ... tossing.
\n
"
,
lineno
);
PQendcopy
(
con
->
connection
);
break
;
#else
case
PGRES_EMPTY_QUERY
:
case
PGRES_COMMAND_OK
:
case
PGRES_COPY_OUT
:
case
PGRES_COPY_IN
:
break
;
#endif
case
PGRES_NONFATAL_ERROR
:
case
PGRES_FATAL_ERROR
:
case
PGRES_BAD_RESPONSE
:
ECPGlog
(
"ECPGexecute line %d: Error: %s"
,
lineno
,
PQerrorMessage
(
con
->
connection
));
register_error
(
ECPG_PGSQL
,
"Postgres error: %s line %d."
,
PQerrorMessage
(
con
->
connection
),
lineno
);
status
=
false
;
break
;
default:
ECPGlog
(
"ECPGexecute line %d: Got something else, postgres error.
\n
"
,
lineno
);
register_error
(
ECPG_PGSQL
,
"Postgres error: %s line %d."
,
PQerrorMessage
(
con
->
connection
),
lineno
);
status
=
false
;
break
;
}
}
/* check for asynchronous returns */
notify
=
PQnotifies
(
con
->
connection
);
if
(
notify
)
{
ECPGlog
(
"ECPGexecute line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received
\n
"
,
lineno
,
notify
->
relname
,
notify
->
be_pid
);
free
(
notify
);
}
return
status
;
}
/* like ECPGdo */
static
bool
do_descriptor2
(
int
lineno
,
const
char
*
connection_name
,
PGresult
**
resultptr
,
const
char
*
query
)
{
struct
connection
*
con
=
get_connection
(
connection_name
);
bool
status
=
true
;
char
*
locale
=
setlocale
(
LC_NUMERIC
,
NULL
);
/* Make sure we do NOT honor the locale for numeric input/output */
/* since the database wants teh standard decimal point */
setlocale
(
LC_NUMERIC
,
"C"
);
if
(
!
ecpg_init
(
con
,
connection_name
,
lineno
))
{
setlocale
(
LC_NUMERIC
,
locale
);
return
(
false
);
}
/* are we connected? */
if
(
con
==
NULL
||
con
->
connection
==
NULL
)
{
ECPGlog
(
"ECPGdo: not connected to %s
\n
"
,
con
->
name
);
register_error
(
ECPG_NOT_CONN
,
"Not connected in line %d."
,
lineno
);
setlocale
(
LC_NUMERIC
,
locale
);
return
false
;
}
status
=
execute_descriptor
(
lineno
,
query
,
con
,
resultptr
);
/* and reset locale value so our application is not affected */
setlocale
(
LC_NUMERIC
,
locale
);
return
(
status
);
}
bool
ECPGdo_descriptor
(
int
line
,
const
char
*
connection
,
const
char
*
descriptor
,
const
char
*
query
)
{
struct
descriptor
*
i
;
for
(
i
=
all_descriptors
;
i
!=
NULL
;
i
=
i
->
next
)
{
if
(
!
strcmp
(
descriptor
,
i
->
name
))
{
bool
status
;
/* free previous result */
if
(
i
->
result
)
PQclear
(
i
->
result
);
i
->
result
=
NULL
;
status
=
do_descriptor2
(
line
,
connection
,
&
i
->
result
,
query
);
if
(
!
i
->
result
)
PQmakeEmptyPGresult
(
NULL
,
0
);
return
(
status
);
}
}
ECPGraise
(
line
,
ECPG_UNKNOWN_DESCRIPTOR
);
return
false
;
}
PGresult
*
ECPGresultByDescriptor
(
int
line
,
const
char
*
name
)
{
struct
descriptor
*
i
;
for
(
i
=
all_descriptors
;
i
!=
NULL
;
i
=
i
->
next
)
{
if
(
!
strcmp
(
name
,
i
->
name
))
return
i
->
result
;
}
ECPGraise
(
line
,
ECPG_UNKNOWN_DESCRIPTOR
);
return
0
;
}
bool
ECPGdeallocate_desc
(
int
line
,
const
char
*
name
)
{
struct
descriptor
*
i
;
struct
descriptor
**
lastptr
=&
all_descriptors
;
for
(
i
=
all_descriptors
;
i
;
lastptr
=&
i
->
next
,
i
=
i
->
next
)
{
if
(
!
strcmp
(
name
,
i
->
name
))
{
*
lastptr
=
i
->
next
;
free
(
i
->
name
);
PQclear
(
i
->
result
);
free
(
i
);
return
true
;
}
}
ECPGraise
(
line
,
ECPG_UNKNOWN_DESCRIPTOR
);
return
false
;
}
bool
ECPGallocate_desc
(
int
line
,
const
char
*
name
)
{
struct
descriptor
*
new
=
(
struct
descriptor
*
)
malloc
(
sizeof
(
struct
descriptor
));
new
->
next
=
all_descriptors
;
new
->
name
=
malloc
(
strlen
(
name
)
+
1
);
new
->
result
=
PQmakeEmptyPGresult
(
NULL
,
0
);
strcpy
(
new
->
name
,
name
);
all_descriptors
=
new
;
return
true
;
}
void
ECPGraise
(
int
line
,
int
code
)
{
sqlca
.
sqlcode
=
code
;
switch
(
code
)
{
case
ECPG_NOT_FOUND
:
snprintf
(
sqlca
.
sqlerrm
.
sqlerrmc
,
sizeof
(
sqlca
.
sqlerrm
.
sqlerrmc
),
"No data found line %d."
,
line
);
break
;
case
ECPG_MISSING_INDICATOR
:
snprintf
(
sqlca
.
sqlerrm
.
sqlerrmc
,
sizeof
(
sqlca
.
sqlerrm
.
sqlerrmc
),
"NULL value without indicator, line %d."
,
line
);
break
;
case
ECPG_UNKNOWN_DESCRIPTOR
:
snprintf
(
sqlca
.
sqlerrm
.
sqlerrmc
,
sizeof
(
sqlca
.
sqlerrm
.
sqlerrmc
),
"descriptor not found, line %d."
,
line
);
break
;
case
ECPG_INVALID_DESCRIPTOR_INDEX
:
snprintf
(
sqlca
.
sqlerrm
.
sqlerrmc
,
sizeof
(
sqlca
.
sqlerrm
.
sqlerrmc
),
"descriptor index out of range, line %d."
,
line
);
break
;
default:
snprintf
(
sqlca
.
sqlerrm
.
sqlerrmc
,
sizeof
(
sqlca
.
sqlerrm
.
sqlerrmc
),
"SQL error #%d, line %d."
,
code
,
line
);
break
;
}
}
src/interfaces/ecpg/lib/ecpglib.c
View file @
35ba9de2
...
...
@@ -20,7 +20,6 @@
#include <ctype.h>
#include <locale.h>
#include <libpq-fe.h>
#include <libpq/pqcomm.h>
#include <ecpgtype.h>
#include <ecpglib.h>
...
...
@@ -1130,7 +1129,7 @@ ECPGdo(int lineno, const char *connection_name, char *query,...)
va_list
args
;
struct
statement
*
stmt
;
struct
connection
*
con
=
get_connection
(
connection_name
);
bool
status
;
bool
status
=
true
;
char
*
locale
=
setlocale
(
LC_NUMERIC
,
NULL
);
/* Make sure we do NOT honor the locale for numeric input/output */
...
...
@@ -1138,25 +1137,33 @@ ECPGdo(int lineno, const char *connection_name, char *query,...)
setlocale
(
LC_NUMERIC
,
"C"
);
if
(
!
ecpg_init
(
con
,
connection_name
,
lineno
))
{
setlocale
(
LC_NUMERIC
,
locale
);
return
(
false
);
}
va_start
(
args
,
query
);
if
(
create_statement
(
lineno
,
con
,
&
stmt
,
query
,
args
)
==
false
)
{
setlocale
(
LC_NUMERIC
,
locale
);
return
(
false
);
}
va_end
(
args
);
/* are we connected? */
if
(
con
==
NULL
||
con
->
connection
==
NULL
)
{
free_statement
(
stmt
);
ECPGlog
(
"ECPGdo: not connected to %s
\n
"
,
con
->
name
);
register_error
(
ECPG_NOT_CONN
,
"Not connected in line %d."
,
lineno
);
setlocale
(
LC_NUMERIC
,
locale
);
return
false
;
}
status
=
ECPGexecute
(
stmt
);
free_statement
(
stmt
);
/* and rese
r
value so our application is not affected */
/* and rese
t locale
value so our application is not affected */
setlocale
(
LC_NUMERIC
,
locale
);
return
(
status
);
}
...
...
@@ -1508,3 +1515,5 @@ ECPGprepared_statement(char *name)
for
(
this
=
prep_stmts
;
this
!=
NULL
&&
strcmp
(
this
->
name
,
name
)
!=
0
;
this
=
this
->
next
);
return
(
this
)
?
this
->
stmt
->
command
:
NULL
;
}
#include "dynamic.c"
src/interfaces/ecpg/preproc/ecpg_keywords.c
View file @
35ba9de2
...
...
@@ -19,6 +19,7 @@
*/
static
ScanKeyword
ScanKeywords
[]
=
{
/* name value */
{
"allocate"
,
SQL_ALLOCATE
},
{
"at"
,
SQL_AT
},
{
"autocommit"
,
SQL_AUTOCOMMIT
},
{
"bool"
,
SQL_BOOL
},
...
...
@@ -28,10 +29,12 @@ static ScanKeyword ScanKeywords[] = {
{
"connection"
,
SQL_CONNECTION
},
{
"continue"
,
SQL_CONTINUE
},
{
"deallocate"
,
SQL_DEALLOCATE
},
{
"descriptor"
,
SQL_DESCRIPTOR
},
{
"disconnect"
,
SQL_DISCONNECT
},
{
"enum"
,
SQL_ENUM
},
{
"found"
,
SQL_FOUND
},
{
"free"
,
SQL_FREE
},
{
"get"
,
SQL_GET
},
{
"go"
,
SQL_GO
},
{
"goto"
,
SQL_GOTO
},
{
"identified"
,
SQL_IDENTIFIED
},
...
...
@@ -46,12 +49,14 @@ static ScanKeyword ScanKeywords[] = {
{
"section"
,
SQL_SECTION
},
{
"short"
,
SQL_SHORT
},
{
"signed"
,
SQL_SIGNED
},
{
"sql"
,
SQL_SQL
},
// strange thing, used for into sql descriptor MYDESC;
{
"sqlerror"
,
SQL_SQLERROR
},
{
"sqlprint"
,
SQL_SQLPRINT
},
{
"sqlwarning"
,
SQL_SQLWARNING
},
{
"stop"
,
SQL_STOP
},
{
"struct"
,
SQL_STRUCT
},
{
"unsigned"
,
SQL_UNSIGNED
},
{
"value"
,
SQL_VALUE
},
{
"var"
,
SQL_VAR
},
{
"whenever"
,
SQL_WHENEVER
},
};
...
...
src/interfaces/ecpg/preproc/extern.h
View file @
35ba9de2
...
...
@@ -29,6 +29,7 @@ extern struct arguments *argsinsert;
extern
struct
arguments
*
argsresult
;
extern
struct
when
when_error
,
when_nf
,
when_warn
;
extern
struct
ECPGstruct_member
*
struct_member_list
[
STRUCT_DEPTH
];
extern
struct
descriptor
*
descriptors
;
/* functions */
...
...
src/interfaces/ecpg/preproc/preproc.y
View file @
35ba9de2
...
...
@@ -23,6 +23,8 @@
int struct_level = 0;
char errortext[128];
static char *connection = NULL;
static char *descriptor_name = NULL;
static char *descriptor_index= NULL;
static int QueryIsRule = 0, ForUpdateNotAllowed = 0, FoundInto = 0;
static int FoundSort = 0;
static int initializer = 0;
...
...
@@ -38,6 +40,11 @@ struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};
struct ECPGtype ecpg_query = {ECPGt_char_variable, 0L, {NULL}};
/* variable lookup */
static struct variable * find_variable(char * name);
static void whenever_action(int mode);
/*
* Handle parsing errors and warnings
*/
...
...
@@ -80,6 +87,275 @@ output_simple_statement(char *cmd)
free(cmd);
}
/*
* assignment handling function (descriptor)
*/
static struct assignment *assignments;
static void push_assignment(char *var,char *value)
{
struct assignment *new=(struct assignment *)mm_alloc(sizeof(struct assignment));
new->next=assignments;
new->variable=mm_alloc(strlen(var)+1);
strcpy(new->variable,var);
new->value=mm_alloc(strlen(value)+1);
strcpy(new->value,value);
assignments=new;
}
static void drop_assignments(void)
{ while (assignments)
{ struct assignment *old_head=assignments;
assignments=old_head->next;
free(old_head->variable);
free(old_head->value);
free(old_head);
}
}
/* XXX: these should be more accurate (consider ECPGdump_a_* ) */
static void ECPGnumeric_lvalue(FILE *f,char *name)
{ const struct variable *v=find_variable(name);
switch(v->type->typ)
{ case ECPGt_short:
case ECPGt_int:
case ECPGt_long:
case ECPGt_unsigned_short:
case ECPGt_unsigned_int:
case ECPGt_unsigned_long:
fputs(name,yyout);
break;
default:
snprintf(errortext,sizeof errortext,"variable %s: numeric type needed"
,name);
mmerror(ET_ERROR,errortext);
break;
}
}
static void ECPGstring_buffer(FILE *f,char *name)
{ const struct variable *v=find_variable(name);
switch(v->type->typ)
{ case ECPGt_varchar:
fprintf(yyout,"%s.arr",name);
break;
case ECPGt_char:
case ECPGt_unsigned_char:
fputs(name,yyout);
break;
default:
snprintf(errortext,sizeof errortext,"variable %s: character type needed"
,name);
mmerror(ET_ERROR,errortext);
break;
}
}
static void ECPGstring_length(FILE *f,char *name)
{ const struct variable *v=find_variable(name);
switch(v->type->typ)
{ case ECPGt_varchar:
case ECPGt_char:
case ECPGt_unsigned_char:
if (!v->type->size)
{ snprintf(errortext,sizeof errortext,"zero length char variable %s for assignment",
v->name);
mmerror(ET_ERROR,errortext);
}
fprintf(yyout,"%ld",v->type->size);
break;
default:
snprintf(errortext,sizeof errortext,"variable %s: character type needed"
,name);
mmerror(ET_ERROR,errortext);
break;
}
}
static void ECPGdata_assignment(char *variable,char *index_plus_1)
{ const struct variable *v=find_variable(variable);
fprintf(yyout,"\t\t\tif (!PQgetisnull(ECPGresult,0,(%s)-1))\n",index_plus_1);
switch(v->type->typ)
{ case ECPGt_short:
case ECPGt_int: /* use the same conversion as ecpglib does */
case ECPGt_long:
fprintf(yyout,"\t\t\t\t%s=strtol(PQgetvalue(ECPGresult,0,(%s)-1),NULL,10);\n"
,variable,index_plus_1);
break;
case ECPGt_unsigned_short:
case ECPGt_unsigned_int:
case ECPGt_unsigned_long:
fprintf(yyout,"\t\t\t\t%s=strtoul(PQgetvalue(ECPGresult,0,(%s)-1),NULL,10);\n"
,variable,index_plus_1);
break;
case ECPGt_float:
case ECPGt_double:
fprintf(yyout,"\t\t\t\t%s=strtod(PQgetvalue(ECPGresult,0,(%s)-1),NULL);\n"
,variable,index_plus_1);
break;
case ECPGt_bool:
fprintf(yyout,"\t\t\t\t%s=PQgetvalue(ECPGresult,0,(%s)-1)[0]=='t';\n"
,variable,index_plus_1);
break;
case ECPGt_varchar:
fprintf(yyout,"\t\t\t{\tstrncpy(%s.arr,PQgetvalue(ECPGresult,0,(%s)-1),%ld);\n"
,variable,index_plus_1,v->type->size);
fprintf(yyout,"\t\t\t\t%s.len=strlen(PQgetvalue(ECPGresult,0,(%s)-1)\n"
,variable,index_plus_1);
fprintf(yyout,"\t\t\t\tif (%s.len>%ld) { %s.len=%ld; sqlca.sqlwarn[0]=sqlca.sqlwarn[1]='W'; }\n"
,variable,v->type->size,variable,v->type->size);
fputs("\t\t\t}\n",yyout);
break;
case ECPGt_char:
case ECPGt_unsigned_char:
if (!v->type->size)
{ snprintf(errortext,sizeof errortext,"zero length char variable %s for DATA assignment",
v->name);
mmerror(ET_ERROR,errortext);
}
fprintf(yyout,"\t\t\t{\tstrncpy(%s,PQgetvalue(ECPGresult,0,(%s)-1),%ld);\n"
,variable,index_plus_1,v->type->size);
fprintf(yyout,"\t\t\t\tif (strlen(PQgetvalue(ECPGresult,0,(%s)-1))>=%ld)\n"
"\t\t\t\t{ %s[%ld]=0; sqlca.sqlwarn[0]=sqlca.sqlwarn[1]='W'; }\n"
,index_plus_1,v->type->size,variable,v->type->size-1);
fputs("\t\t\t}\n",yyout);
break;
default:
snprintf(errortext,sizeof errortext,"unknown variable type %d for DATA assignment"
,v->type->typ);
mmerror(ET_ERROR,errortext);
break;
}
}
static void
output_get_descr_header(char *desc_name)
{ struct assignment *results;
fprintf(yyout,"{\tPGresult *ECPGresult=ECPGresultByDescriptor(%d, \"%s\");\n"
,yylineno,desc_name);
fputs("\tif (ECPGresult)\n\t{",yyout);
for (results=assignments;results!=NULL;results=results->next)
{ if (!strcasecmp(results->value,"count"))
{ fputs("\t\t",yyout);
ECPGnumeric_lvalue(yyout,results->variable);
fputs("=PQnfields(ECPGresult);\n",yyout);
}
else
{ snprintf(errortext,sizeof errortext,"unknown descriptor header item '%s'",results->value);
mmerror(ET_WARN,errortext);
}
}
drop_assignments();
fputs("}",yyout);
whenever_action(2|1);
}
static void
output_get_descr(char *desc_name)
{ struct assignment *results;
int flags=0;
const int DATA_SEEN=1;
const int INDICATOR_SEEN=2;
fprintf(yyout,"{\tPGresult *ECPGresult=ECPGresultByDescriptor(%d, \"%s\");\n"
,yylineno,desc_name);
fputs("\tif (ECPGresult)\n\t{",yyout);
fprintf(yyout,"\tif (PQntuples(ECPGresult)<1) ECPGraise(%d,ECPG_NOT_FOUND);\n",yylineno);
fprintf(yyout,"\t\telse if (%s<1 || %s>PQnfields(ECPGresult))\n"
"\t\t\tECPGraise(%d,ECPG_INVALID_DESCRIPTOR_INDEX);\n"
,descriptor_index,descriptor_index,yylineno);
fputs("\t\telse\n\t\t{\n",yyout);
for (results=assignments;results!=NULL;results=results->next)
{ if (!strcasecmp(results->value,"type"))
{ fputs("\t\t\t",yyout);
ECPGnumeric_lvalue(yyout,results->variable);
fprintf(yyout,"=ECPGDynamicType(PQftype(ECPGresult,(%s)-1));\n",descriptor_index);
}
else if (!strcasecmp(results->value,"datetime_interval_code"))
{ fputs("\t\t\t",yyout);
ECPGnumeric_lvalue(yyout,results->variable);
fprintf(yyout,"=ECPGDynamicType_DDT(PQftype(ECPGresult,(%s)-1));\n",descriptor_index);
}
else if (!strcasecmp(results->value,"length"))
{ fputs("\t\t\t",yyout);
ECPGnumeric_lvalue(yyout,results->variable);
fprintf(yyout,"=PQfmod(ECPGresult,(%s)-1)-VARHDRSZ;\n",descriptor_index);
}
else if (!strcasecmp(results->value,"octet_length"))
{ fputs("\t\t\t",yyout);
ECPGnumeric_lvalue(yyout,results->variable);
fprintf(yyout,"=PQfsize(ECPGresult,(%s)-1);\n",descriptor_index);
}
else if (!strcasecmp(results->value,"returned_length")
|| !strcasecmp(results->value,"returned_octet_length"))
{ fputs("\t\t\t",yyout);
ECPGnumeric_lvalue(yyout,results->variable);
fprintf(yyout,"=PQgetlength(ECPGresult,0,(%s)-1);\n",descriptor_index);
}
else if (!strcasecmp(results->value,"precision"))
{ fputs("\t\t\t",yyout);
ECPGnumeric_lvalue(yyout,results->variable);
fprintf(yyout,"=PQfmod(ECPGresult,(%s)-1)>>16;\n",descriptor_index);
}
else if (!strcasecmp(results->value,"scale"))
{ fputs("\t\t\t",yyout);
ECPGnumeric_lvalue(yyout,results->variable);
fprintf(yyout,"=(PQfmod(ECPGresult,(%s)-1)-VARHDRSZ)&0xffff;\n",descriptor_index);
}
else if (!strcasecmp(results->value,"nullable"))
{ mmerror(ET_WARN,"nullable is always 1");
fputs("\t\t\t",yyout);
ECPGnumeric_lvalue(yyout,results->variable);
fprintf(yyout,"=1;\n");
}
else if (!strcasecmp(results->value,"key_member"))
{ mmerror(ET_WARN,"key_member is always 0");
fputs("\t\t\t",yyout);
ECPGnumeric_lvalue(yyout,results->variable);
fprintf(yyout,"=0;\n");
}
else if (!strcasecmp(results->value,"name"))
{ fputs("\t\t\tstrncpy(",yyout);
ECPGstring_buffer(yyout,results->variable);
fprintf(yyout,",PQfname(ECPGresult,(%s)-1),",descriptor_index);
ECPGstring_length(yyout,results->variable);
fputs(");\n",yyout);
}
else if (!strcasecmp(results->value,"indicator"))
{ flags|=INDICATOR_SEEN;
fputs("\t\t\t",yyout);
ECPGnumeric_lvalue(yyout,results->variable);
fprintf(yyout,"=-PQgetisnull(ECPGresult,0,(%s)-1);\n",descriptor_index);
}
else if (!strcasecmp(results->value,"data"))
{ flags|=DATA_SEEN;
ECPGdata_assignment(results->variable,descriptor_index);
}
else
{ snprintf(errortext,sizeof errortext,"unknown descriptor header item '%s'",results->value);
mmerror(ET_WARN,errortext);
}
}
if (flags==DATA_SEEN) /* no indicator */
{ fprintf(yyout,"\t\t\tif (PQgetisnull(ECPGresult,0,(%s)-1))\n"
"\t\t\t\tECPGraise(%d,ECPG_MISSING_INDICATOR);\n"
,descriptor_index,yylineno);
}
drop_assignments();
fputs("\t\t}\n\t}\n",yyout);
whenever_action(2|1);
}
/*
* store the whenever action here
*/
...
...
@@ -157,8 +433,6 @@ new_variable(const char * name, struct ECPGtype * type)
return(p);
}
static struct variable * find_variable(char * name);
static struct variable *
find_struct_member(char *name, char *str, struct ECPGstruct_member *members)
{
...
...
@@ -401,6 +675,67 @@ check_indicator(struct ECPGtype *var)
}
}
/*
* descriptor name lookup
*/
static struct descriptor *descriptors;
static void add_descriptor(char *name,char *connection)
{
struct descriptor *new=(struct descriptor *)mm_alloc(sizeof(struct descriptor));
new->next=descriptors;
new->name=mm_alloc(strlen(name)+1);
strcpy(new->name,name);
if (connection)
{ new->connection=mm_alloc(strlen(connection)+1);
strcpy(new->connection,connection);
}
else new->connection=connection;
descriptors=new;
}
static void drop_descriptor(char *name,char *connection)
{ struct descriptor *i;
struct descriptor **lastptr=&descriptors;
for (i=descriptors;i;lastptr=&i->next,i=i->next)
{ if (!strcmp(name,i->name))
{ if ((!connection && !i->connection)
|| (connection && i->connection
&& !strcmp(connection,i->connection)))
{ *lastptr=i->next;
if (i->connection) free(i->connection);
free(i->name);
free(i);
return;
}
}
}
snprintf(errortext,sizeof errortext,"unknown descriptor %s",name);
mmerror(ET_WARN,errortext);
}
static struct descriptor *lookup_descriptor(char *name,char *connection)
{ struct descriptor *i;
for (i=descriptors;i;i=i->next)
{ if (!strcmp(name,i->name))
{ if ((!connection && !i->connection)
|| (connection && i->connection
&& !strcmp(connection,i->connection)))
{ return i;
}
}
}
snprintf(errortext,sizeof errortext,"unknown descriptor %s",name);
mmerror(ET_WARN,errortext);
return NULL;
}
/*
* string concatenation
*/
static char *
cat2_str(char *str1, char *str2)
{
...
...
@@ -522,6 +857,32 @@ output_statement(char * stmt, int mode)
free(connection);
}
static void
output_statement_desc(char * stmt, int mode)
{
int i, j=strlen(stmt);
fprintf(yyout, "{ ECPGdo_descriptor(__LINE__, %s, \"%s\", \"",
connection ? connection : "NULL", descriptor_name);
/* do this char by char as we have to filter '\"' */
for (i = 0;i < j; i++) {
if (stmt[i] != '\"')
fputc(stmt[i], yyout);
else
fputs("\\\"", yyout);
}
fputs("\");", yyout);
mode |= 2;
whenever_action(mode);
free(stmt);
if (connection != NULL)
free(connection);
free(descriptor_name);
}
static struct typedefs *
get_typedef(char *name)
{
...
...
@@ -632,15 +993,16 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
}
/* special embedded SQL token */
%token SQL_AT SQL_AUTOCOMMIT SQL_BOOL SQL_BREAK
%token SQL_A
LLOCATE SQL_A
T SQL_AUTOCOMMIT 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_DEALLOCATE SQL_D
ESCRIPTOR SQL_D
ISCONNECT SQL_ENUM
%token SQL_FOUND SQL_FREE SQL_G
ET SQL_G
O SQL_GOTO
%token SQL_IDENTIFIED SQL_INDICATOR SQL_INT SQL_LONG
%token SQL_OFF SQL_OPEN SQL_PREPARE SQL_RELEASE SQL_REFERENCE
%token SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQLERROR SQL_SQLPRINT
%token SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQL
%token SQL_SQLERROR SQL_SQLPRINT
%token SQL_SQLWARNING SQL_START SQL_STOP SQL_STRUCT SQL_UNSIGNED
%token SQL_VAR SQL_WHENEVER
%token SQL_VA
LUE SQL_VA
R SQL_WHENEVER
/* C token */
%token S_ANYTHING S_AUTO S_CONST S_EXTERN
...
...
@@ -829,6 +1191,9 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
%type <str> ECPGFree ECPGDeclare ECPGVar opt_at enum_definition
%type <str> struct_type s_struct declaration declarations variable_declarations
%type <str> s_struct s_union union_type ECPGSetAutocommit on_off
%type <str> ECPGAllocateDescr ECPGDeallocateDescr
%type <str> ECPGGetDescriptor ECPGGetDescriptorHeader
%type <str> FetchDescriptorStmt
%type <type_enum> simple_type signed_type unsigned_type varchar_type
...
...
@@ -879,6 +1244,7 @@ stmt: AlterTableStmt { output_statement($1, 0); }
| ExtendStmt { output_statement($1, 0); }
| ExplainStmt { output_statement($1, 0); }
| FetchStmt { output_statement($1, 1); }
| FetchDescriptorStmt { output_statement_desc($1, 1); }
| GrantStmt { output_statement($1, 0); }
| IndexStmt { output_statement($1, 0); }
| ListenStmt { output_statement($1, 0); }
...
...
@@ -912,6 +1278,10 @@ stmt: AlterTableStmt { output_statement($1, 0); }
| VariableShowStmt { output_statement($1, 0); }
| VariableResetStmt { output_statement($1, 0); }
| ConstraintsSetStmt { output_statement($1, 0); }
| ECPGAllocateDescr { fprintf(yyout,"ECPGallocate_desc(__LINE__, \"%s\");",$1);
whenever_action(0);
free($1);
}
| ECPGConnect {
if (connection)
mmerror(ET_ERROR, "no at option for connect statement.\n");
...
...
@@ -932,6 +1302,10 @@ stmt: AlterTableStmt { output_statement($1, 0); }
whenever_action(2);
free($1);
}
| ECPGDeallocateDescr { fprintf(yyout,"ECPGdeallocate_desc(__LINE__, \"%s\");",$1);
whenever_action(0);
free($1);
}
| ECPGDeclare {
output_simple_statement($1);
}
...
...
@@ -952,6 +1326,14 @@ stmt: AlterTableStmt { output_statement($1, 0); }
whenever_action(2);
free($1);
}
| ECPGGetDescriptor {
lookup_descriptor($1,connection);
output_get_descr($1);
}
| ECPGGetDescriptorHeader {
lookup_descriptor($1,connection);
output_get_descr_header($1);
}
| ECPGOpen {
struct cursor *ptr;
...
...
@@ -5014,6 +5396,78 @@ ECPGPrepare: SQL_PREPARE ident FROM execstring
$$ = cat2_str(make3_str(make_str("\""), $2, make_str("\",")), $4);
}
/*
* dynamic SQL: descriptor based access
* written by Christof Petig <christof.petig@wtal.de>
*/
/*
* deallocate a descriptor
*/
ECPGDeallocateDescr: SQL_DEALLOCATE SQL_DESCRIPTOR ident
{ drop_descriptor($3,connection);
$$ = $3;
}
/*
* allocate a descriptor
*/
ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR ident
{ add_descriptor($3,connection);
$$ = $3;
}
/*
* read from descriptor
*/
ECPGGetDescHeaderItem: cvariable '=' ident {
push_assignment($1,$3);
}
ECPGGetDescItem: cvariable '=' ident {
push_assignment($1,$3);
}
| cvariable '=' TYPE_P {
push_assignment($1,"type");
}
| cvariable '=' PRECISION {
push_assignment($1,"precision");
}
| cvariable '=' SQL_INDICATOR {
push_assignment($1,"indicator");
}
ECPGGetDescHeaderItems: ECPGGetDescHeaderItem
| ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem;
ECPGGetDescItems: ECPGGetDescItem
| ECPGGetDescItems ',' ECPGGetDescItem;
ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR ident ECPGGetDescHeaderItems
{ $$ = $3; }
ECPGGetDescriptor: SQL_GET SQL_DESCRIPTOR ident SQL_VALUE cvariable ECPGGetDescItems
{ $$ = $3; descriptor_index=$5; }
| SQL_GET SQL_DESCRIPTOR ident SQL_VALUE Iconst ECPGGetDescItems
{ $$ = $3; descriptor_index=$5; }
/*
* fetch [ in | from ] <portalname> into sql descriptor <name>
*/
FetchDescriptorStmt: FETCH from_in name INTO SQL_SQL SQL_DESCRIPTOR ident
{
$$ = cat_str(3, make_str("fetch"), $2, $3);
descriptor_name=$7;
}
| FETCH name INTO SQL_SQL SQL_DESCRIPTOR ident
{
$$ = cat2_str(make_str("fetch"), $2);
descriptor_name=$6;
}
;
/*
* for compatibility with ORACLE we will also allow the keyword RELEASE
* after a transaction statement to disconnect from the database.
...
...
src/interfaces/ecpg/preproc/type.h
View file @
35ba9de2
...
...
@@ -139,4 +139,18 @@ struct arguments
struct
arguments
*
next
;
};
struct
descriptor
{
char
*
name
;
char
*
connection
;
struct
descriptor
*
next
;
};
struct
assignment
{
char
*
variable
;
char
*
value
;
struct
assignment
*
next
;
};
enum
errortype
{
ET_WARN
,
ET_ERROR
,
ET_FATAL
};
src/interfaces/ecpg/test/Makefile
View file @
35ba9de2
all
:
stp.so test1 test2 test3 test4 test5 perftest
all
:
stp.so test1 test2 test3 test4 test5 perftest
dyntest
#LDFLAGS=-g -I /usr/local/pgsql/include -L/usr/local/pgsql/lib -lecpg -lpq -lcrypt
#
LDFLAGS=-g -I../include -I/usr/include/postgresql -L/usr/lib/postgresql -L../lib -lecpg -lpq -lcrypt
LDFLAGS
=
-g
-I
/usr/include/postgresql
-lecpg
-lpq
-lcrypt
LDFLAGS
=
-g
-I
../include
-I
/usr/include/postgresql
-L
/usr/lib/postgresql
-L
../lib
-lecpg
-lpq
-lcrypt
#
LDFLAGS=-g -I/usr/include/postgresql -lecpg -lpq -lcrypt
#ECPG=/usr/local/pgsql/bin/ecpg
ECPG
=
../preproc/ecpg
-I
../include
...
...
@@ -16,6 +16,7 @@ test3: test3.c
test4
:
test4.c
test5
:
test5.c
perftest
:
perftest.c
dyntest
:
dyntest.c
.pgc.c
:
$(ECPG)
$?
...
...
src/interfaces/ecpg/test/dyntest.pgc
0 → 100644
View file @
35ba9de2
/* dynamic SQL test program
*
* Copyright (c) 2000, Christof Petig <christof.petig@wtal.de>
*
* $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Attic/dyntest.pgc,v 1.1 2000/02/16 16:18:29 meskes Exp $
*/
#include <stdio.h>
exec sql include sql3types;
exec sql include sqlca;
void error()
{ printf("#%d:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
exit(1);
}
int main(int argc,char **argv)
{ exec sql begin declare section;
int COUNT;
int INTVAR;
int INDEX;
int INDICATOR;
int TYPE,LENGTH,OCTET_LENGTH,PRECISION,SCALE,NULLABLE,RETURNED_OCTET_LENGTH;
int DATETIME_INTERVAL_CODE;
char NAME[120];
char STRINGVAR[1024];
float FLOATVAR;
double DOUBLEVAR;
char QUERY[1024];
exec sql end declare section;
int done=0;
snprintf(QUERY,sizeof QUERY,"select * from %s",argc>1?argv[1]:"pg_tables");
exec sql whenever sqlerror do error();
exec sql allocate descriptor MYDESC;
exec sql connect to test;
exec sql prepare MYQUERY from :QUERY;
exec sql declare MYCURS cursor for MYQUERY;
exec sql open MYCURS;
while (1)
{ exec sql fetch in MYCURS into sql descriptor MYDESC;
if (sqlca.sqlcode) break;
exec sql get descriptor MYDESC :COUNT = count;
if (!done)
{ printf("Count %d\n",COUNT);
done=1;
}
for (INDEX=1;INDEX<=COUNT;++INDEX)
{ exec sql get descriptor MYDESC value :INDEX
:TYPE = type,
:LENGTH = length, :OCTET_LENGTH=octet_length,
:RETURNED_OCTET_LENGTH=returned_octet_length,
:PRECISION = precision, :SCALE=scale,
:NULLABLE=nullable, :NAME=name,
:INDICATOR=indicator;
printf("%2d %s %d(%d)(%d,%d) %d,%d %d = "
,INDEX,NAME,TYPE,LENGTH,PRECISION,SCALE
,OCTET_LENGTH,RETURNED_OCTET_LENGTH,NULLABLE);
if (INDICATOR==-1) printf("NULL\n");
else switch (TYPE)
{ case SQL3_BOOLEAN:
exec sql get descriptor MYDESC value :INDEX :INTVAR=data;
printf("%s\n",INTVAR?"true":"false");
break;
case SQL3_NUMERIC:
case SQL3_DECIMAL:
if (SCALE==0)
{ exec sql get descriptor MYDESC value :INDEX :INTVAR=data;
printf("%d\n",INTVAR);
}
else
{ exec sql get descriptor MYDESC value :INDEX :FLOATVAR=data;
printf("%.*f\n",SCALE,FLOATVAR);
}
break;
case SQL3_INTEGER:
case SQL3_SMALLINT:
exec sql get descriptor MYDESC value :INDEX :INTVAR=data;
printf("%d\n",INTVAR);
break;
case SQL3_FLOAT:
case SQL3_REAL:
exec sql get descriptor MYDESC value :INDEX :FLOATVAR=data;
printf("%.*f\n",PRECISION,FLOATVAR);
break;
case SQL3_DOUBLE_PRECISION:
exec sql get descriptor MYDESC value :INDEX :DOUBLEVAR=data;
printf("%.*f\n",PRECISION,DOUBLEVAR);
break;
case SQL3_DATE_TIME_TIMESTAMP:
exec sql get descriptor MYDESC value :INDEX
:DATETIME_INTERVAL_CODE=datetime_interval_code,
:STRINGVAR=data;
printf("%d \"%s\"\n",DATETIME_INTERVAL_CODE,STRINGVAR);
break;
case SQL3_INTERVAL:
exec sql get descriptor MYDESC value :INDEX :STRINGVAR=data;
printf("\"%s\"\n",STRINGVAR);
break;
case SQL3_CHARACTER:
case SQL3_CHARACTER_VARYING:
exec sql get descriptor MYDESC value :INDEX :STRINGVAR=data;
printf("\"%s\"\n",STRINGVAR);
break;
default:
exec sql get descriptor MYDESC value :INDEX :STRINGVAR=data;
printf("<\"%s\">\n",STRINGVAR);
break;
}
}
}
exec sql close MYCURS;
exec sql deallocate descriptor MYDESC;
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