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
01e32265
Commit
01e32265
authored
Mar 14, 2002
by
Hiroshi Inoue
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
1) Internal improvements to handle updatable cursors(1st cut).
2) Fix a bug in SQLColAttribute().
parent
f362dcec
Changes
20
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
414 additions
and
372 deletions
+414
-372
src/interfaces/odbc/connection.c
src/interfaces/odbc/connection.c
+14
-8
src/interfaces/odbc/connection.h
src/interfaces/odbc/connection.h
+4
-1
src/interfaces/odbc/convert.c
src/interfaces/odbc/convert.c
+22
-2
src/interfaces/odbc/environ.c
src/interfaces/odbc/environ.c
+3
-0
src/interfaces/odbc/execute.c
src/interfaces/odbc/execute.c
+18
-3
src/interfaces/odbc/info.c
src/interfaces/odbc/info.c
+14
-14
src/interfaces/odbc/info30.c
src/interfaces/odbc/info30.c
+18
-13
src/interfaces/odbc/multibyte.c
src/interfaces/odbc/multibyte.c
+1
-1
src/interfaces/odbc/odbcapi30.c
src/interfaces/odbc/odbcapi30.c
+4
-164
src/interfaces/odbc/options.c
src/interfaces/odbc/options.c
+31
-54
src/interfaces/odbc/parse.c
src/interfaces/odbc/parse.c
+28
-10
src/interfaces/odbc/psqlodbc.h
src/interfaces/odbc/psqlodbc.h
+2
-1
src/interfaces/odbc/psqlodbc_api30.def
src/interfaces/odbc/psqlodbc_api30.def
+1
-1
src/interfaces/odbc/psqlodbc_api30w.def
src/interfaces/odbc/psqlodbc_api30w.def
+1
-1
src/interfaces/odbc/qresult.c
src/interfaces/odbc/qresult.c
+30
-2
src/interfaces/odbc/qresult.h
src/interfaces/odbc/qresult.h
+4
-0
src/interfaces/odbc/results.c
src/interfaces/odbc/results.c
+181
-78
src/interfaces/odbc/statement.c
src/interfaces/odbc/statement.c
+19
-19
src/interfaces/odbc/statement.h
src/interfaces/odbc/statement.h
+6
-0
src/interfaces/odbc/tuple.h
src/interfaces/odbc/tuple.h
+13
-0
No files found.
src/interfaces/odbc/connection.c
View file @
01e32265
...
...
@@ -374,7 +374,7 @@ CC_begin(ConnectionClass *self)
char
ret
=
TRUE
;
if
(
!
CC_is_in_trans
(
self
))
{
QResultClass
*
res
=
CC_send_query
(
self
,
"BEGIN"
,
NULL
,
TRUE
);
QResultClass
*
res
=
CC_send_query
(
self
,
"BEGIN"
,
NULL
,
CLEAR_RESULT_ON_ABORT
);
mylog
(
"CC_begin: sending BEGIN!
\n
"
);
if
(
res
!=
NULL
)
...
...
@@ -401,7 +401,7 @@ CC_commit(ConnectionClass *self)
char
ret
=
FALSE
;
if
(
CC_is_in_trans
(
self
))
{
QResultClass
*
res
=
CC_send_query
(
self
,
"COMMIT"
,
NULL
,
TRUE
);
QResultClass
*
res
=
CC_send_query
(
self
,
"COMMIT"
,
NULL
,
CLEAR_RESULT_ON_ABORT
);
mylog
(
"CC_commit: sending COMMIT!
\n
"
);
CC_set_no_trans
(
self
);
...
...
@@ -427,7 +427,7 @@ CC_abort(ConnectionClass *self)
{
if
(
CC_is_in_trans
(
self
))
{
QResultClass
*
res
=
CC_send_query
(
self
,
"ROLLBACK"
,
NULL
,
TRUE
);
QResultClass
*
res
=
CC_send_query
(
self
,
"ROLLBACK"
,
NULL
,
CLEAR_RESULT_ON_ABORT
);
mylog
(
"CC_abort: sending ABORT!
\n
"
);
CC_set_no_trans
(
self
);
...
...
@@ -919,7 +919,7 @@ another_version_retry:
*/
mylog
(
"sending an empty query...
\n
"
);
res
=
CC_send_query
(
self
,
" "
,
NULL
,
TRUE
);
res
=
CC_send_query
(
self
,
" "
,
NULL
,
CLEAR_RESULT_ON_ABORT
);
if
(
res
==
NULL
||
QR_get_status
(
res
)
!=
PGRES_EMPTY_QUERY
)
{
mylog
(
"got no result from the empty query. (probably database does not exist)
\n
"
);
...
...
@@ -956,7 +956,7 @@ another_version_retry:
* Multibyte handling is available ?
*/
#ifdef MULTIBYTE
if
(
PG_VERSION_GE
(
self
,
7
.
0
))
if
(
PG_VERSION_GE
(
self
,
6
.
4
))
{
CC_lookup_characterset
(
self
);
if
(
self
->
errornumber
!=
0
)
...
...
@@ -977,7 +977,7 @@ another_version_retry:
if
(
self
->
client_encoding
)
free
(
self
->
client_encoding
);
self
->
client_encoding
=
NULL
;
if
(
res
=
CC_send_query
(
self
,
"set client_encoding to 'UTF8'"
,
NULL
,
TRUE
),
res
)
if
(
res
=
CC_send_query
(
self
,
"set client_encoding to 'UTF8'"
,
NULL
,
CLEAR_RESULT_ON_ABORT
),
res
)
{
self
->
client_encoding
=
strdup
(
"UNICODE"
);
QR_Destructor
(
res
);
...
...
@@ -991,7 +991,7 @@ another_version_retry:
else
if
(
self
->
unicode
)
{
self
->
errornumber
=
CONN_NOT_IMPLEMENTED_ERROR
;
self
->
errormsg
=
"Unicode isn't supported before
7.0
"
;
self
->
errormsg
=
"Unicode isn't supported before
6.4
"
;
return
0
;
}
#endif
/* UNICODE_SUPPORT */
...
...
@@ -1128,12 +1128,14 @@ CC_get_error(ConnectionClass *self, int *number, char **message)
* 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
*/
QResultClass
*
CC_send_query
(
ConnectionClass
*
self
,
char
*
query
,
QueryInfo
*
qi
,
BOOL
clear_result_on_abort
)
CC_send_query
(
ConnectionClass
*
self
,
char
*
query
,
QueryInfo
*
qi
,
UDWORD
flag
)
{
QResultClass
*
result_in
=
NULL
,
*
cmdres
=
NULL
,
*
retres
=
NULL
,
*
res
=
NULL
;
BOOL
clear_result_on_abort
=
((
flag
&
CLEAR_RESULT_ON_ABORT
)
!=
0
),
create_keyset
=
((
flag
&
CREATE_KEYSET
)
!=
0
);
char
swallow
,
*
wq
;
int
id
;
...
...
@@ -1376,6 +1378,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, BOOL clear_resu
if
(
query_completed
)
{
res
->
next
=
QR_Constructor
();
if
(
create_keyset
)
QR_set_haskeyset
(
res
->
next
);
mylog
(
"send_query: 'T' no result_in: res = %u
\n
"
,
res
->
next
);
if
(
!
res
->
next
)
{
...
...
@@ -1392,6 +1396,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, BOOL clear_resu
}
if
(
!
used_passed_result_object
)
{
if
(
create_keyset
)
QR_set_haskeyset
(
res
);
if
(
!
QR_fetch_tuples
(
res
,
self
,
qi
?
qi
->
cursor
:
NULL
))
{
self
->
errornumber
=
CONNECTION_COULD_NOT_RECEIVE
;
...
...
src/interfaces/odbc/connection.h
View file @
01e32265
...
...
@@ -305,7 +305,7 @@ char CC_connect(ConnectionClass *self, char do_password);
char
CC_add_statement
(
ConnectionClass
*
self
,
StatementClass
*
stmt
);
char
CC_remove_statement
(
ConnectionClass
*
self
,
StatementClass
*
stmt
);
char
CC_get_error
(
ConnectionClass
*
self
,
int
*
number
,
char
**
message
);
QResultClass
*
CC_send_query
(
ConnectionClass
*
self
,
char
*
query
,
QueryInfo
*
qi
,
BOOL
);
QResultClass
*
CC_send_query
(
ConnectionClass
*
self
,
char
*
query
,
QueryInfo
*
qi
,
UDWORD
flag
);
void
CC_clear_error
(
ConnectionClass
*
self
);
char
*
CC_create_errormsg
(
ConnectionClass
*
self
);
int
CC_send_function
(
ConnectionClass
*
conn
,
int
fnid
,
void
*
result_buf
,
int
*
actual_result_len
,
int
result_is_int
,
LO_ARG
*
argv
,
int
nargs
);
...
...
@@ -316,4 +316,7 @@ void CC_initialize_pg_version(ConnectionClass *conn);
void
CC_log_error
(
const
char
*
func
,
const
char
*
desc
,
const
ConnectionClass
*
self
);
int
CC_get_max_query_len
(
const
ConnectionClass
*
self
);
/* CC_send_query_options */
#define CLEAR_RESULT_ON_ABORT 1L
#define CREATE_KEYSET (1L << 1)
/* create keyset for updatable curosrs */
#endif
src/interfaces/odbc/convert.c
View file @
01e32265
...
...
@@ -1291,6 +1291,7 @@ copy_statement_with_parameters(StatementClass *stmt)
#ifdef DRIVER_CURSOR_IMPLEMENT
BOOL
search_from_pos
=
FALSE
;
#endif
/* DRIVER_CURSOR_IMPLEMENT */
Int4
from_pos
=
-
1
,
where_pos
=
-
1
;
if
(
ci
->
disallow_premature
)
prepare_dummy_cursor
=
stmt
->
pre_executing
;
...
...
@@ -1326,7 +1327,11 @@ copy_statement_with_parameters(StatementClass *stmt)
else
if
(
!
stmt
->
ti
||
stmt
->
ntab
!=
1
)
stmt
->
options
.
scroll_concurrency
=
SQL_CONCUR_READ_ONLY
;
else
search_from_pos
=
TRUE
;
{
/** search_from_pos = TRUE; **/
from_pos
=
stmt
->
from_pos
;
where_pos
=
stmt
->
where_pos
;
}
}
#endif
/* DRIVER_CURSOR_IMPLEMENT */
...
...
@@ -1366,9 +1371,18 @@ copy_statement_with_parameters(StatementClass *stmt)
#ifdef MULTIBYTE
make_encoded_str
(
&
encstr
,
conn
,
old_statement
);
#endif
for
(
opos
=
0
;
opos
<
oldstmtlen
;
opos
++
)
{
if
(
from_pos
==
(
Int4
)
opos
)
{
CVT_APPEND_STR
(
", CTID, OID "
);
}
else
if
(
where_pos
==
(
Int4
)
opos
)
{
stmt
->
load_statement
=
malloc
(
npos
+
1
);
memcpy
(
stmt
->
load_statement
,
new_statement
,
npos
);
stmt
->
load_statement
[
npos
]
=
'\0'
;
}
#ifdef MULTIBYTE
oldchar
=
encoded_byte_check
(
&
encstr
,
opos
);
if
(
ENCODE_STATUS
(
encstr
)
!=
0
)
...
...
@@ -2033,6 +2047,12 @@ copy_statement_with_parameters(StatementClass *stmt)
#ifdef DRIVER_CURSOR_IMPLEMENT
if
(
search_from_pos
)
stmt
->
options
.
scroll_concurrency
=
SQL_CONCUR_READ_ONLY
;
if
(
!
stmt
->
load_statement
&&
from_pos
>=
0
)
{
stmt
->
load_statement
=
malloc
(
npos
+
1
);
memcpy
(
stmt
->
load_statement
,
new_statement
,
npos
);
stmt
->
load_statement
[
npos
]
=
'\0'
;
}
#endif
/* DRIVER_CURSOR_IMPLEMENT */
if
(
prepare_dummy_cursor
&&
SC_is_pre_executable
(
stmt
))
{
...
...
src/interfaces/odbc/environ.c
View file @
01e32265
...
...
@@ -245,6 +245,9 @@ PGAPI_StmtError( HSTMT hstmt,
case
STMT_INVALID_CURSOR_STATE_ERROR
:
strcpy
(
szSqlState
,
"24000"
);
break
;
case
STMT_ERROR_IN_ROW
:
strcpy
(
szSqlState
,
"01S01"
);
break
;
case
STMT_OPTION_VALUE_CHANGED
:
strcpy
(
szSqlState
,
"01S02"
);
break
;
...
...
src/interfaces/odbc/execute.c
View file @
01e32265
...
...
@@ -94,6 +94,12 @@ PGAPI_Prepare(HSTMT hstmt,
if
(
self
->
statement
)
free
(
self
->
statement
);
if
(
self
->
stmt_with_params
)
free
(
self
->
stmt_with_params
);
self
->
stmt_with_params
=
NULL
;
if
(
self
->
load_statement
)
free
(
self
->
load_statement
);
self
->
load_statement
=
NULL
;
self
->
statement
=
make_string
(
szSqlStr
,
cbSqlStr
,
NULL
);
if
(
!
self
->
statement
)
...
...
@@ -141,6 +147,12 @@ PGAPI_ExecDirect(
if
(
stmt
->
statement
)
free
(
stmt
->
statement
);
if
(
stmt
->
stmt_with_params
)
free
(
stmt
->
stmt_with_params
);
stmt
->
stmt_with_params
=
NULL
;
if
(
stmt
->
load_statement
)
free
(
stmt
->
load_statement
);
stmt
->
load_statement
=
NULL
;
/*
* keep a copy of the un-parametrized statement, in case they try to
...
...
@@ -421,7 +433,7 @@ next_param_row:
BOOL
in_trans
=
CC_is_in_trans
(
conn
);
BOOL
issued_begin
=
FALSE
,
begin_included
=
FALSE
;
QResultClass
*
res
;
QResultClass
*
res
,
*
curres
;
if
(
strnicmp
(
stmt
->
stmt_with_params
,
"BEGIN;"
,
6
)
==
0
)
begin_included
=
TRUE
;
...
...
@@ -436,7 +448,7 @@ next_param_row:
}
/* we are now in a transaction */
CC_set_in_trans
(
conn
);
res
=
CC_send_query
(
conn
,
stmt
->
stmt_with_params
,
NULL
,
TRUE
);
res
=
CC_send_query
(
conn
,
stmt
->
stmt_with_params
,
NULL
,
CLEAR_RESULT_ON_ABORT
);
if
(
!
res
)
{
CC_abort
(
conn
);
...
...
@@ -445,6 +457,9 @@ next_param_row:
return
SQL_ERROR
;
}
SC_set_Result
(
stmt
,
res
);
for
(
curres
=
res
;
!
curres
->
num_fields
;
curres
=
curres
->
next
)
;
SC_set_Curres
(
stmt
,
curres
);
if
(
CC_is_in_autocommit
(
conn
))
{
if
(
issued_begin
)
...
...
@@ -518,7 +533,7 @@ PGAPI_Transact(
{
mylog
(
"PGAPI_Transact: sending on conn %d '%s'
\n
"
,
conn
,
stmt_string
);
res
=
CC_send_query
(
conn
,
stmt_string
,
NULL
,
TRUE
);
res
=
CC_send_query
(
conn
,
stmt_string
,
NULL
,
CLEAR_RESULT_ON_ABORT
);
CC_set_no_trans
(
conn
);
if
(
!
res
)
...
...
src/interfaces/odbc/info.c
View file @
01e32265
...
...
@@ -2858,7 +2858,7 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc
return
ret
;
if
(
!
conn
->
server_encoding
)
{
if
(
res
=
CC_send_query
(
conn
,
"select getdatabaseencoding()"
,
NULL
,
TRUE
),
res
)
if
(
res
=
CC_send_query
(
conn
,
"select getdatabaseencoding()"
,
NULL
,
CLEAR_RESULT_ON_ABORT
),
res
)
{
if
(
QR_get_num_tuples
(
res
)
>
0
)
conn
->
server_encoding
=
strdup
(
QR_get_value_backend_row
(
res
,
0
,
0
));
...
...
@@ -2868,11 +2868,11 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc
if
(
!
conn
->
server_encoding
)
return
ret
;
sprintf
(
query
,
"SET CLIENT_ENCODING TO '%s'"
,
conn
->
server_encoding
);
bError
=
(
CC_send_query
(
conn
,
query
,
NULL
,
TRUE
)
==
NULL
);
bError
=
(
CC_send_query
(
conn
,
query
,
NULL
,
CLEAR_RESULT_ON_ABORT
)
==
NULL
);
if
(
!
bError
&&
continueExec
)
{
sprintf
(
query
,
"select OID from pg_class where relname = '%s'"
,
serverTableName
);
if
(
res
=
CC_send_query
(
conn
,
query
,
NULL
,
TRUE
),
res
)
if
(
res
=
CC_send_query
(
conn
,
query
,
NULL
,
CLEAR_RESULT_ON_ABORT
),
res
)
{
if
(
QR_get_num_tuples
(
res
)
>
0
)
strcpy
(
saveoid
,
QR_get_value_backend_row
(
res
,
0
,
0
));
...
...
@@ -2891,11 +2891,11 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc
}
/* restore the client encoding */
sprintf
(
query
,
"SET CLIENT_ENCODING TO '%s'"
,
conn
->
client_encoding
);
bError
=
(
CC_send_query
(
conn
,
query
,
NULL
,
TRUE
)
==
NULL
);
bError
=
(
CC_send_query
(
conn
,
query
,
NULL
,
CLEAR_RESULT_ON_ABORT
)
==
NULL
);
if
(
bError
||
!
continueExec
)
return
ret
;
sprintf
(
query
,
"select relname from pg_class where OID = %s"
,
saveoid
);
if
(
res
=
CC_send_query
(
conn
,
query
,
NULL
,
TRUE
),
res
)
if
(
res
=
CC_send_query
(
conn
,
query
,
NULL
,
CLEAR_RESULT_ON_ABORT
),
res
)
{
if
(
QR_get_num_tuples
(
res
)
>
0
)
{
...
...
@@ -2922,7 +2922,7 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se
return
ret
;
if
(
!
conn
->
server_encoding
)
{
if
(
res
=
CC_send_query
(
conn
,
"select getdatabaseencoding()"
,
NULL
,
TRUE
),
res
)
if
(
res
=
CC_send_query
(
conn
,
"select getdatabaseencoding()"
,
NULL
,
CLEAR_RESULT_ON_ABORT
),
res
)
{
if
(
QR_get_num_tuples
(
res
)
>
0
)
conn
->
server_encoding
=
strdup
(
QR_get_value_backend_row
(
res
,
0
,
0
));
...
...
@@ -2932,13 +2932,13 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se
if
(
!
conn
->
server_encoding
)
return
ret
;
sprintf
(
query
,
"SET CLIENT_ENCODING TO '%s'"
,
conn
->
server_encoding
);
bError
=
(
CC_send_query
(
conn
,
query
,
NULL
,
TRUE
)
==
NULL
);
bError
=
(
CC_send_query
(
conn
,
query
,
NULL
,
CLEAR_RESULT_ON_ABORT
)
==
NULL
);
if
(
!
bError
&&
continueExec
)
{
sprintf
(
query
,
"select attrelid, attnum from pg_class, pg_attribute "
"where relname = '%s' and attrelid = pg_class.oid "
"and attname = '%s'"
,
serverTableName
,
serverColumnName
);
if
(
res
=
CC_send_query
(
conn
,
query
,
NULL
,
TRUE
),
res
)
if
(
res
=
CC_send_query
(
conn
,
query
,
NULL
,
CLEAR_RESULT_ON_ABORT
),
res
)
{
if
(
QR_get_num_tuples
(
res
)
>
0
)
{
...
...
@@ -2960,11 +2960,11 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se
}
/* restore the cleint encoding */
sprintf
(
query
,
"SET CLIENT_ENCODING TO '%s'"
,
conn
->
client_encoding
);
bError
=
(
CC_send_query
(
conn
,
query
,
NULL
,
TRUE
)
==
NULL
);
bError
=
(
CC_send_query
(
conn
,
query
,
NULL
,
CLEAR_RESULT_ON_ABORT
)
==
NULL
);
if
(
bError
||
!
continueExec
)
return
ret
;
sprintf
(
query
,
"select attname from pg_attribute where attrelid = %s and attnum = %s"
,
saveattrelid
,
saveattnum
);
if
(
res
=
CC_send_query
(
conn
,
query
,
NULL
,
TRUE
),
res
)
if
(
res
=
CC_send_query
(
conn
,
query
,
NULL
,
CLEAR_RESULT_ON_ABORT
),
res
)
{
if
(
QR_get_num_tuples
(
res
)
>
0
)
{
...
...
@@ -3790,7 +3790,7 @@ PGAPI_Procedures(
" case when prorettype = 0 then 1::int2 else 2::int2 end as "
"PROCEDURE_TYPE"
" from pg_proc"
);
my_strcat
(
proc_query
,
" where proname like '%.*s'"
,
szProcName
,
cbProcName
);
if
(
res
=
CC_send_query
(
conn
,
proc_query
,
NULL
,
TRUE
),
!
res
)
if
(
res
=
CC_send_query
(
conn
,
proc_query
,
NULL
,
CLEAR_RESULT_ON_ABORT
),
!
res
)
{
stmt
->
errornumber
=
STMT_EXEC_ERROR
;
stmt
->
errormsg
=
"PGAPI_Procedures query error"
;
...
...
@@ -3927,7 +3927,7 @@ PGAPI_TablePrivileges(
my_strcat
(
proc_query
,
" relname like '%.*s' and"
,
esc_table_name
,
escTbnamelen
);
}
strcat
(
proc_query
,
" pg_user.usesysid = relowner"
);
if
(
res
=
CC_send_query
(
conn
,
proc_query
,
NULL
,
TRUE
),
!
res
)
if
(
res
=
CC_send_query
(
conn
,
proc_query
,
NULL
,
CLEAR_RESULT_ON_ABORT
),
!
res
)
{
stmt
->
errornumber
=
STMT_EXEC_ERROR
;
stmt
->
errormsg
=
"PGAPI_TablePrivileges query error"
;
...
...
@@ -3935,7 +3935,7 @@ PGAPI_TablePrivileges(
}
strncpy_null
(
proc_query
,
"select usename, usesysid, usesuper from pg_user"
,
sizeof
(
proc_query
));
tablecount
=
QR_get_num_tuples
(
res
);
if
(
allures
=
CC_send_query
(
conn
,
proc_query
,
NULL
,
TRUE
),
!
allures
)
if
(
allures
=
CC_send_query
(
conn
,
proc_query
,
NULL
,
CLEAR_RESULT_ON_ABORT
),
!
allures
)
{
QR_Destructor
(
res
);
stmt
->
errornumber
=
STMT_EXEC_ERROR
;
...
...
@@ -3983,7 +3983,7 @@ PGAPI_TablePrivileges(
char
*
grolist
,
*
uid
,
*
delm
;
snprintf
(
proc_query
,
sizeof
(
proc_query
)
-
1
,
"select grolist from pg_group where groname = '%s'"
,
user
);
if
(
gres
=
CC_send_query
(
conn
,
proc_query
,
NULL
,
TRUE
))
if
(
gres
=
CC_send_query
(
conn
,
proc_query
,
NULL
,
CLEAR_RESULT_ON_ABORT
))
{
grolist
=
QR_get_value_backend_row
(
gres
,
0
,
0
);
if
(
grolist
&&
grolist
[
0
]
==
'{'
)
...
...
src/interfaces/odbc/info30.c
View file @
01e32265
...
...
@@ -47,14 +47,15 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
break
;
case
SQL_KEYSET_CURSOR_ATTRIBUTES1
:
len
=
4
;
value
=
SQL_CA1_NEXT
|
SQL_CA1_ABSOLUTE
value
=
0
;
if
(
ci
->
updatable_cursors
||
ci
->
drivers
.
lie
)
value
|=
(
SQL_CA1_NEXT
|
SQL_CA1_ABSOLUTE
|
SQL_CA1_RELATIVE
|
SQL_CA1_BOOKMARK
|
SQL_CA1_LOCK_NO_CHANGE
|
SQL_CA1_POS_POSITION
|
SQL_CA1_POS_UPDATE
|
SQL_CA1_POS_DELETE
|
SQL_CA1_POS_REFRESH
;
|
SQL_CA1_POS_REFRESH
)
;
if
(
ci
->
drivers
.
lie
)
value
|=
(
SQL_CA1_BULK_ADD
value
|=
(
SQL_CA1_BULK_ADD
|
SQL_CA1_BULK_UPDATE_BY_BOOKMARK
|
SQL_CA1_BULK_DELETE_BY_BOOKMARK
|
SQL_CA1_BULK_FETCH_BY_BOOKMARK
...
...
@@ -68,13 +69,14 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
break
;
case
SQL_KEYSET_CURSOR_ATTRIBUTES2
:
len
=
4
;
value
=
SQL_CA2_OPT_ROWVER_CONCURRENCY
value
=
0
;
if
(
ci
->
updatable_cursors
||
ci
->
drivers
.
lie
)
value
|=
(
SQL_CA2_OPT_ROWVER_CONCURRENCY
|
SQL_CA2_SENSITIVITY_ADDITIONS
|
SQL_CA2_SENSITIVITY_DELETIONS
|
SQL_CA2_SENSITIVITY_UPDATES
;
|
SQL_CA2_SENSITIVITY_UPDATES
)
;
if
(
ci
->
drivers
.
lie
)
value
|=
(
SQL_CA2_READ_ONLY_CONCURRENCY
value
|=
(
SQL_CA2_READ_ONLY_CONCURRENCY
|
SQL_CA2_LOCK_CONCURRENCY
|
SQL_CA2_OPT_VALUES_CONCURRENCY
|
SQL_CA2_MAX_ROWS_SELECT
...
...
@@ -95,16 +97,19 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
len
=
4
;
value
=
SQL_CA1_NEXT
|
SQL_CA1_ABSOLUTE
|
SQL_CA1_RELATIVE
|
SQL_CA1_BOOKMARK
|
SQL_CA1_LOCK_NO_CHANGE
|
SQL_CA1_POS_POSITION
|
SQL_CA1_POS_UPDATE
|
SQL_CA1_POS_DELETE
|
SQL_CA1_POS_REFRESH
;
|
SQL_CA1_LOCK_NO_CHANGE
|
SQL_CA1_POS_POSITION
;
if
(
ci
->
updatable_cursors
)
value
|=
(
SQL_CA1_POS_UPDATE
|
SQL_CA1_POS_DELETE
|
SQL_CA1_POS_REFRESH
);
break
;
case
SQL_STATIC_CURSOR_ATTRIBUTES2
:
len
=
4
;
value
=
SQL_CA2_OPT_ROWVER_CONCURRENCY
value
=
0
;
if
(
ci
->
updatable_cursors
)
value
|=
(
SQL_CA2_OPT_ROWVER_CONCURRENCY
|
SQL_CA2_SENSITIVITY_ADDITIONS
|
SQL_CA2_SENSITIVITY_DELETIONS
|
SQL_CA2_SENSITIVITY_UPDATES
;
|
SQL_CA2_SENSITIVITY_UPDATES
)
;
break
;
case
SQL_ODBC_INTERFACE_CONFORMANCE
:
...
...
src/interfaces/odbc/multibyte.c
View file @
01e32265
...
...
@@ -300,7 +300,7 @@ CC_lookup_cs_new(ConnectionClass *self)
char
*
encstr
=
NULL
;
QResultClass
*
res
;
res
=
CC_send_query
(
self
,
"select pg_client_encoding()"
,
NULL
,
TRUE
);
res
=
CC_send_query
(
self
,
"select pg_client_encoding()"
,
NULL
,
CLEAR_RESULT_ON_ABORT
);
if
(
res
)
{
char
*
enc
=
QR_get_value_backend_row
(
res
,
0
,
0
);
...
...
src/interfaces/odbc/odbcapi30.c
View file @
01e32265
...
...
@@ -419,177 +419,17 @@ SQLSetConnectAttr(HDBC ConnectionHandle,
return
PGAPI_SetConnectOption
(
ConnectionHandle
,
(
UWORD
)
Attribute
,
(
UDWORD
)
Value
);
}
static
RETCODE
SQL_API
ARDSetField
(
StatementClass
*
stmt
,
SQLSMALLINT
RecNumber
,
SQLSMALLINT
FieldIdentifier
,
PTR
Value
,
SQLINTEGER
BufferLength
)
{
RETCODE
ret
=
SQL_SUCCESS
;
PTR
tptr
;
switch
(
FieldIdentifier
)
{
case
SQL_DESC_ARRAY_SIZE
:
stmt
->
options
.
rowset_size
=
(
SQLUINTEGER
)
Value
;
break
;
case
SQL_DESC_ARRAY_STATUS_PTR
:
stmt
->
options
.
row_operation_ptr
=
Value
;
break
;
case
SQL_DESC_BIND_OFFSET_PTR
:
stmt
->
options
.
row_offset_ptr
=
Value
;
break
;
case
SQL_DESC_BIND_TYPE
:
stmt
->
options
.
bind_size
=
(
SQLUINTEGER
)
Value
;
break
;
case
SQL_DESC_DATA_PTR
:
if
(
!
RecNumber
)
stmt
->
bookmark
.
buffer
=
Value
;
else
stmt
->
bindings
[
RecNumber
-
1
].
buffer
=
Value
;
break
;
case
SQL_DESC_INDICATOR_PTR
:
if
(
!
RecNumber
)
tptr
=
stmt
->
bookmark
.
used
;
else
tptr
=
stmt
->
bindings
[
RecNumber
-
1
].
used
;
if
(
Value
!=
tptr
)
{
ret
=
SQL_ERROR
;
stmt
->
errornumber
=
STMT_INVALID_OPTION_IDENTIFIER
;
stmt
->
errormsg
=
"INDICATOR != OCTET_LENGTH_PTR"
;
}
break
;
case
SQL_DESC_OCTET_LENGTH_PTR
:
if
(
!
RecNumber
)
stmt
->
bookmark
.
used
=
Value
;
else
stmt
->
bindings
[
RecNumber
-
1
].
used
=
Value
;
break
;
default:
ret
=
SQL_ERROR
;
stmt
->
errornumber
=
STMT_INVALID_OPTION_IDENTIFIER
;
stmt
->
errormsg
=
"not implemedted yet"
;
}
return
ret
;
}
static
RETCODE
SQL_API
APDSetField
(
StatementClass
*
stmt
,
SQLSMALLINT
RecNumber
,
SQLSMALLINT
FieldIdentifier
,
PTR
Value
,
SQLINTEGER
BufferLength
)
{
RETCODE
ret
=
SQL_SUCCESS
;
switch
(
FieldIdentifier
)
{
case
SQL_DESC_ARRAY_SIZE
:
stmt
->
options
.
paramset_size
=
(
SQLUINTEGER
)
Value
;
break
;
case
SQL_DESC_ARRAY_STATUS_PTR
:
stmt
->
options
.
param_operation_ptr
=
Value
;
break
;
case
SQL_DESC_BIND_OFFSET_PTR
:
stmt
->
options
.
param_offset_ptr
=
Value
;
break
;
case
SQL_DESC_BIND_TYPE
:
stmt
->
options
.
param_bind_type
=
(
SQLUINTEGER
)
Value
;
break
;
case
SQL_DESC_DATA_PTR
:
if
(
stmt
->
parameters_allocated
<
RecNumber
)
PGAPI_BindParameter
(
stmt
,
RecNumber
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
);
stmt
->
parameters
[
RecNumber
-
1
].
buffer
=
Value
;
break
;
case
SQL_DESC_INDICATOR_PTR
:
if
(
stmt
->
parameters_allocated
<
RecNumber
||
Value
!=
stmt
->
parameters
[
RecNumber
-
1
].
used
)
{
ret
=
SQL_ERROR
;
stmt
->
errornumber
=
STMT_INVALID_OPTION_IDENTIFIER
;
stmt
->
errormsg
=
"INDICATOR != OCTET_LENGTH_PTR"
;
}
break
;
case
SQL_DESC_OCTET_LENGTH_PTR
:
if
(
stmt
->
parameters_allocated
<
RecNumber
)
PGAPI_BindParameter
(
stmt
,
RecNumber
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
);
stmt
->
parameters
[
RecNumber
-
1
].
used
=
Value
;
break
;
default:
ret
=
SQL_ERROR
;
stmt
->
errornumber
=
STMT_INVALID_OPTION_IDENTIFIER
;
}
return
ret
;
}
static
RETCODE
SQL_API
IRDSetField
(
StatementClass
*
stmt
,
SQLSMALLINT
RecNumber
,
SQLSMALLINT
FieldIdentifier
,
PTR
Value
,
SQLINTEGER
BufferLength
)
{
RETCODE
ret
=
SQL_SUCCESS
;
switch
(
FieldIdentifier
)
{
case
SQL_DESC_ARRAY_STATUS_PTR
:
stmt
->
options
.
rowStatusArray
=
(
SQLUSMALLINT
*
)
Value
;
break
;
case
SQL_DESC_ROWS_PROCESSED_PTR
:
stmt
->
options
.
rowsFetched
=
(
SQLUINTEGER
*
)
Value
;
break
;
default:
ret
=
SQL_ERROR
;
stmt
->
errornumber
=
STMT_INVALID_OPTION_IDENTIFIER
;
}
return
ret
;
}
static
RETCODE
SQL_API
IPDSetField
(
StatementClass
*
stmt
,
SQLSMALLINT
RecNumber
,
SQLSMALLINT
FieldIdentifier
,
PTR
Value
,
SQLINTEGER
BufferLength
)
{
RETCODE
ret
=
SQL_SUCCESS
;
switch
(
FieldIdentifier
)
{
case
SQL_DESC_ARRAY_STATUS_PTR
:
stmt
->
options
.
param_status_ptr
=
(
SQLUSMALLINT
*
)
Value
;
break
;
case
SQL_DESC_ROWS_PROCESSED_PTR
:
stmt
->
options
.
param_processed_ptr
=
(
SQLUINTEGER
*
)
Value
;
break
;
default:
ret
=
SQL_ERROR
;
stmt
->
errornumber
=
STMT_INVALID_OPTION_IDENTIFIER
;
}
return
ret
;
}
/* new function */
RETCODE
SQL_API
SQLSetDescField
(
SQLHDESC
DescriptorHandle
,
SQLSMALLINT
RecNumber
,
SQLSMALLINT
FieldIdentifier
,
PTR
Value
,
SQLINTEGER
BufferLength
)
{
RETCODE
ret
=
SQL_SUCCESS
;
HSTMT
hstmt
;
SQLUINTEGER
descType
;
StatementClass
*
stmt
;
static
const
char
*
func
=
"SQLSetDescField"
;
RETCODE
ret
;
mylog
(
"[[SQLSetDescField]] h=%u rec=%d field=%d val=%x
\n
"
,
DescriptorHandle
,
RecNumber
,
FieldIdentifier
,
Value
);
hstmt
=
statementHandleFromDescHandle
(
DescriptorHandle
,
&
descType
);
mylog
(
"stmt=%x type=%d
\n
"
,
hstmt
,
descType
);
stmt
=
(
StatementClass
*
)
hstmt
;
switch
(
descType
)
{
case
SQL_ATTR_APP_ROW_DESC
:
ret
=
ARDSetField
(
stmt
,
RecNumber
,
FieldIdentifier
,
Value
,
BufferLength
);
break
;
case
SQL_ATTR_APP_PARAM_DESC
:
ret
=
APDSetField
(
stmt
,
RecNumber
,
FieldIdentifier
,
Value
,
BufferLength
);
break
;
case
SQL_ATTR_IMP_ROW_DESC
:
ret
=
IRDSetField
(
stmt
,
RecNumber
,
FieldIdentifier
,
Value
,
BufferLength
);
break
;
case
SQL_ATTR_IMP_PARAM_DESC
:
ret
=
IPDSetField
(
stmt
,
RecNumber
,
FieldIdentifier
,
Value
,
BufferLength
);
break
;
default:
ret
=
SQL_ERROR
;
stmt
->
errornumber
=
STMT_INTERNAL_ERROR
;
stmt
->
errormsg
=
"Error not implemented"
;
}
if
(
ret
==
SQL_ERROR
)
SC_log_error
(
func
,
""
,
stmt
);
ret
=
PGAPI_SetDescField
(
DescriptorHandle
,
RecNumber
,
FieldIdentifier
,
Value
,
BufferLength
);
return
ret
;
}
...
...
@@ -602,7 +442,7 @@ SQLSetDescRec(SQLHDESC DescriptorHandle,
PTR
Data
,
SQLINTEGER
*
StringLength
,
SQLINTEGER
*
Indicator
)
{
const
char
*
func
=
"SQLSetDesc
Field
"
;
const
char
*
func
=
"SQLSetDesc
Rec
"
;
mylog
(
"[[SQLSetDescRec]]
\n
"
);
mylog
(
"Error not implemented
\n
"
);
...
...
src/interfaces/odbc/options.c
View file @
01e32265
...
...
@@ -39,6 +39,7 @@ set_statement_option(ConnectionClass *conn,
static
char
*
func
=
"set_statement_option"
;
char
changed
=
FALSE
;
ConnInfo
*
ci
=
NULL
;
UDWORD
setval
;
if
(
conn
)
ci
=
&
(
conn
->
connInfo
);
...
...
@@ -63,22 +64,21 @@ set_statement_option(ConnectionClass *conn,
* positioned update isn't supported so cursor concurrency is
* read-only
*/
mylog
(
"SetStmtOption(): SQL_CONCURRENCY = %d
\n
"
,
vParam
);
if
(
ci
->
drivers
.
lie
||
vParam
==
SQL_CONCUR_READ_ONLY
||
vParam
==
SQL_CONCUR_ROWVER
)
{
if
(
conn
)
conn
->
stmtOptions
.
scroll_concurrency
=
vParam
;
if
(
stmt
)
stmt
->
options
.
scroll_concurrency
=
vParam
;
}
else
{
mylog
(
"SetStmtOption(): SQL_CONCURRENCY = %d "
,
vParam
);
setval
=
SQL_CONCUR_READ_ONLY
;
if
(
SQL_CONCUR_READ_ONLY
==
vParam
)
;
if
(
ci
->
drivers
.
lie
)
setval
=
vParam
;
else
if
(
ci
->
updatable_cursors
)
setval
=
SQL_CONCUR_ROWVER
;
if
(
conn
)
conn
->
stmtOptions
.
scroll_concurrency
=
SQL_CONCUR_ROWVER
;
if
(
stmt
)
stmt
->
options
.
scroll_concurrency
=
SQL_CONCUR_ROWVER
;
conn
->
stmtOptions
.
scroll_concurrency
=
setval
;
else
if
(
stmt
)
stmt
->
options
.
scroll_concurrency
=
setval
;
if
(
setval
!=
vParam
)
changed
=
TRUE
;
}
mylog
(
"-> %d
\n
"
,
setval
);
break
;
case
SQL_CURSOR_TYPE
:
...
...
@@ -87,47 +87,24 @@ set_statement_option(ConnectionClass *conn,
* if declare/fetch, then type can only be forward. otherwise,
* it can only be forward or static.
*/
mylog
(
"SetStmtOption(): SQL_CURSOR_TYPE = %d
\n
"
,
vParam
);
mylog
(
"SetStmtOption(): SQL_CURSOR_TYPE = %d
"
,
vParam
);
setval
=
SQL_CURSOR_FORWARD_ONLY
;
if
(
ci
->
drivers
.
lie
)
{
if
(
conn
)
conn
->
stmtOptions
.
cursor_type
=
vParam
;
if
(
stmt
)
stmt
->
options
.
cursor_type
=
vParam
;
}
else
{
if
(
ci
->
drivers
.
use_declarefetch
)
{
if
(
conn
)
conn
->
stmtOptions
.
cursor_type
=
SQL_CURSOR_FORWARD_ONLY
;
if
(
stmt
)
stmt
->
options
.
cursor_type
=
SQL_CURSOR_FORWARD_ONLY
;
setval
=
vParam
;
else
if
(
ci
->
drivers
.
use_declarefetch
)
;
else
if
(
SQL_CURSOR_STATIC
==
vParam
)
setval
=
vParam
;
/** else if (SQL_CURSOR_KEYSET_DRIVEN == vParam && ci->updatable)
setval = vParam; **/
if
(
vParam
!=
SQL_CURSOR_FORWARD_ONLY
)
changed
=
TRUE
;
}
else
{
if
(
vParam
==
SQL_CURSOR_FORWARD_ONLY
||
vParam
==
SQL_CURSOR_STATIC
)
{
if
(
conn
)
conn
->
stmtOptions
.
cursor_type
=
vParam
;
/* valid type */
if
(
stmt
)
stmt
->
options
.
cursor_type
=
vParam
;
/* valid type */
}
else
{
if
(
conn
)
conn
->
stmtOptions
.
cursor_type
=
SQL_CURSOR_STATIC
;
if
(
stmt
)
stmt
->
options
.
cursor_type
=
SQL_CURSOR_STATIC
;
conn
->
stmtOptions
.
cursor_type
=
setval
;
else
if
(
stmt
)
stmt
->
options
.
cursor_type
=
setval
;
if
(
setval
!=
vParam
)
changed
=
TRUE
;
}
}
}
mylog
(
"-> %d
\n
"
,
setval
);
break
;
case
SQL_KEYSET_SIZE
:
/* ignored, but saved and returned */
...
...
src/interfaces/odbc/parse.c
View file @
01e32265
...
...
@@ -297,7 +297,6 @@ parse_statement(StatementClass *stmt)
in_distinct
=
FALSE
,
in_on
=
FALSE
,
in_from
=
FALSE
,
from_found
=
FALSE
,
in_where
=
FALSE
,
in_table
=
FALSE
;
char
in_field
=
FALSE
,
...
...
@@ -309,7 +308,6 @@ parse_statement(StatementClass *stmt)
i
,
k
=
0
,
n
,
first_where
=
0
,
blevel
=
0
;
FIELD_INFO
**
fi
;
TABLE_INFO
**
ti
;
...
...
@@ -318,6 +316,7 @@ parse_statement(StatementClass *stmt)
HSTMT
hcol_stmt
;
StatementClass
*
col_stmt
;
RETCODE
result
;
BOOL
updatable
=
TRUE
;
mylog
(
"%s: entering...
\n
"
,
func
);
...
...
@@ -327,6 +326,8 @@ parse_statement(StatementClass *stmt)
stmt
->
nfld
=
0
;
stmt
->
ntab
=
0
;
stmt
->
from_pos
=
-
1
;
stmt
->
where_pos
=
-
1
;
#ifdef MULTIBYTE
while
(
pptr
=
ptr
,
(
ptr
=
getNextToken
(
conn
->
ccsc
,
pptr
,
token
,
sizeof
(
token
),
&
delim
,
&
quote
,
&
dquote
,
&
numeric
))
!=
NULL
)
...
...
@@ -343,6 +344,7 @@ parse_statement(StatementClass *stmt)
if
(
!
stricmp
(
token
,
"distinct"
))
{
in_distinct
=
TRUE
;
updatable
=
FALSE
;
mylog
(
"DISTINCT
\n
"
);
continue
;
...
...
@@ -359,11 +361,11 @@ parse_statement(StatementClass *stmt)
{
in_select
=
FALSE
;
in_from
=
TRUE
;
if
(
!
from_found
&&
if
(
stmt
->
from_pos
<
0
&&
(
!
strnicmp
(
pptr
,
"from"
,
4
)))
{
mylog
(
"First "
);
from_found
=
TRUE
;
stmt
->
from_pos
=
pptr
-
stmt
->
statement
;
}
mylog
(
"FROM
\n
"
);
...
...
@@ -384,9 +386,13 @@ parse_statement(StatementClass *stmt)
in_from
=
FALSE
;
in_where
=
TRUE
;
if
(
!
first_where
&&
(
!
stricmp
(
token
,
"where"
)))
first_where
=
ptr
-
stmt
->
statement
;
if
(
!
stricmp
(
token
,
"where"
))
{
if
(
stmt
->
where_pos
<
0
)
stmt
->
where_pos
=
pptr
-
stmt
->
statement
;
}
else
if
(
stricmp
(
token
,
"order"
))
updatable
=
FALSE
;
mylog
(
"WHERE...
\n
"
);
break
;
...
...
@@ -733,6 +739,10 @@ parse_statement(StatementClass *stmt)
*/
/* Call SQLColumns for each table and store the result */
if
(
stmt
->
ntab
>
1
)
updatable
=
FALSE
;
else
if
(
stmt
->
from_pos
<
0
)
updatable
=
FALSE
;
for
(
i
=
0
;
i
<
stmt
->
ntab
;
i
++
)
{
/* See if already got it */
...
...
@@ -828,9 +838,11 @@ parse_statement(StatementClass *stmt)
*/
for
(
i
=
0
;
i
<
stmt
->
nfld
;)
{
fi
[
i
]
->
updatable
=
updatable
;
/* Dont worry about functions or quotes */
if
(
fi
[
i
]
->
func
||
fi
[
i
]
->
quote
||
fi
[
i
]
->
numeric
)
{
fi
[
i
]
->
updatable
=
FALSE
;
i
++
;
continue
;
}
...
...
@@ -928,6 +940,7 @@ parse_statement(StatementClass *stmt)
mylog
(
"about to copy at %d
\n
"
,
n
+
i
);
getColInfo
(
the_ti
->
col_info
,
fi
[
n
+
i
],
n
);
fi
[
n
+
i
]
->
updatable
=
updatable
;
mylog
(
"done copying
\n
"
);
}
...
...
@@ -945,24 +958,29 @@ parse_statement(StatementClass *stmt)
else
if
(
fi
[
i
]
->
ti
)
{
if
(
!
searchColInfo
(
fi
[
i
]
->
ti
->
col_info
,
fi
[
i
]))
{
parse
=
FALSE
;
fi
[
i
]
->
updatable
=
FALSE
;
}
i
++
;
}
/* Don't know the table -- search all tables in "from" list */
else
{
parse
=
FALSE
;
for
(
k
=
0
;
k
<
stmt
->
ntab
;
k
++
)
{
if
(
searchColInfo
(
ti
[
k
]
->
col_info
,
fi
[
i
]))
{
fi
[
i
]
->
ti
=
ti
[
k
];
/* now know the table */
parse
=
TRUE
;
break
;
}
}
if
(
k
>=
stmt
->
ntab
)
{
parse
=
FALSE
;
fi
[
i
]
->
updatable
=
FALSE
;
}
i
++
;
}
}
...
...
src/interfaces/odbc/psqlodbc.h
View file @
01e32265
...
...
@@ -5,7 +5,7 @@
*
* Comments: See "notice.txt" for copyright and license information.
*
* $Id: psqlodbc.h,v 1.
59 2002/03/11 10:25:57
inoue Exp $
* $Id: psqlodbc.h,v 1.
60 2002/03/14 05:42:03
inoue Exp $
*
*/
...
...
@@ -166,6 +166,7 @@ typedef struct TupleListClass_ TupleListClass;
typedef
struct
EnvironmentClass_
EnvironmentClass
;
typedef
struct
TupleNode_
TupleNode
;
typedef
struct
TupleField_
TupleField
;
typedef
struct
KeySet_
KeySet
;
typedef
struct
col_info
COL_INFO
;
typedef
struct
lo_arg
LO_ARG
;
...
...
src/interfaces/odbc/psqlodbc_api30.def
View file @
01e32265
...
...
@@ -5,7 +5,7 @@ SQLAllocEnv @2
SQLAllocStmt @3
SQLBindCol @4
SQLCancel @5
SQLColAttributes @6
; SQLColAttributes @6 */
SQLConnect @7
SQLDescribeCol @8
SQLDisconnect @9
...
...
src/interfaces/odbc/psqlodbc_api30w.def
View file @
01e32265
...
...
@@ -5,7 +5,7 @@ SQLAllocEnv @2
SQLAllocStmt @3
SQLBindCol @4
SQLCancel @5
SQLColAttributes @6
;
SQLColAttributes @6
SQLConnect @7
SQLDescribeCol @8
SQLDisconnect @9
...
...
src/interfaces/odbc/qresult.c
View file @
01e32265
...
...
@@ -121,6 +121,8 @@ QR_Constructor()
rv
->
cache_size
=
0
;
rv
->
rowset_size
=
1
;
rv
->
haskeyset
=
0
;
rv
->
keyset
=
NULL
;
}
mylog
(
"exit QR_Constructor
\n
"
);
...
...
@@ -221,6 +223,11 @@ QR_free_memory(QResultClass *self)
free
(
self
->
backend_tuples
);
self
->
backend_tuples
=
NULL
;
}
if
(
self
->
keyset
)
{
free
(
self
->
keyset
);
self
->
keyset
=
NULL
;
}
self
->
fcount
=
0
;
...
...
@@ -296,6 +303,8 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
mylog
(
"MALLOC: tuple_size = %d, size = %d
\n
"
,
tuple_size
,
self
->
num_fields
*
sizeof
(
TupleField
)
*
tuple_size
);
self
->
count_allocated
=
0
;
self
->
backend_tuples
=
(
TupleField
*
)
malloc
(
self
->
num_fields
*
sizeof
(
TupleField
)
*
tuple_size
);
if
(
self
->
haskeyset
)
self
->
keyset
=
(
KeySet
*
)
calloc
(
sizeof
(
KeySet
),
tuple_size
);
if
(
!
self
->
backend_tuples
)
{
self
->
status
=
PGRES_FATAL_ERROR
;
...
...
@@ -347,7 +356,7 @@ QR_close(QResultClass *self)
sprintf
(
buf
,
"close %s"
,
self
->
cursor
);
mylog
(
"QResult: closing cursor: '%s'
\n
"
,
buf
);
res
=
CC_send_query
(
self
->
conn
,
buf
,
NULL
,
TRUE
);
res
=
CC_send_query
(
self
->
conn
,
buf
,
NULL
,
CLEAR_RESULT_ON_ABORT
);
self
->
inTuples
=
FALSE
;
self
->
currTuple
=
-
1
;
...
...
@@ -482,6 +491,8 @@ QR_next_tuple(QResultClass *self)
QR_set_message
(
self
,
"Out of memory while reading tuples."
);
return
FALSE
;
}
if
(
self
->
haskeyset
)
self
->
keyset
=
(
KeySet
*
)
realloc
(
self
->
keyset
,
sizeof
(
KeySet
)
*
self
->
cache_size
);
self
->
count_allocated
=
self
->
cache_size
;
}
sprintf
(
fetch
,
"fetch %d in %s"
,
fetch_size
,
self
->
cursor
);
...
...
@@ -492,7 +503,7 @@ QR_next_tuple(QResultClass *self)
qi
.
row_size
=
self
->
cache_size
;
qi
.
result_in
=
self
;
qi
.
cursor
=
NULL
;
res
=
CC_send_query
(
self
->
conn
,
fetch
,
&
qi
,
TRUE
);
res
=
CC_send_query
(
self
->
conn
,
fetch
,
&
qi
,
CLEAR_RESULT_ON_ABORT
);
if
(
res
==
NULL
)
{
self
->
status
=
PGRES_FATAL_ERROR
;
...
...
@@ -552,6 +563,8 @@ QR_next_tuple(QResultClass *self)
QR_set_message
(
self
,
"Out of memory while reading tuples."
);
return
FALSE
;
}
if
(
self
->
haskeyset
)
self
->
keyset
=
(
KeySet
*
)
realloc
(
self
->
keyset
,
sizeof
(
KeySet
)
*
tuple_size
);
self
->
count_allocated
=
tuple_size
;
}
...
...
@@ -626,6 +639,7 @@ QR_read_tuple(QResultClass *self, char binary)
{
Int2
field_lf
;
TupleField
*
this_tuplefield
;
KeySet
*
this_keyset
=
NULL
;
char
bmp
,
bitmap
[
MAX_FIELDS
];
/* Max. len of the bitmap */
Int2
bitmaplen
;
/* len of the bitmap in bytes */
...
...
@@ -639,6 +653,11 @@ QR_read_tuple(QResultClass *self, char binary)
/* set the current row to read the fields into */
this_tuplefield
=
self
->
backend_tuples
+
(
self
->
fcount
*
num_fields
);
if
(
self
->
haskeyset
)
{
this_keyset
=
self
->
keyset
+
self
->
fcount
;
this_keyset
->
status
=
0
;
}
bitmaplen
=
(
Int2
)
num_fields
/
BYTELEN
;
if
((
num_fields
%
BYTELEN
)
>
0
)
...
...
@@ -709,6 +728,15 @@ QR_read_tuple(QResultClass *self, char binary)
else
bmp
<<=
1
;
}
if
(
this_keyset
)
{
if
(
this_tuplefield
[
num_fields
-
2
].
value
)
sscanf
(
this_tuplefield
[
num_fields
-
2
].
value
,
"(%u,%hu)"
,
&
this_keyset
->
blocknum
,
&
this_keyset
->
offset
);
if
(
this_tuplefield
[
num_fields
-
1
].
value
)
sscanf
(
this_tuplefield
[
num_fields
-
1
].
value
,
"%u"
,
&
this_keyset
->
oid
);
}
self
->
currTuple
++
;
return
TRUE
;
}
src/interfaces/odbc/qresult.h
View file @
01e32265
...
...
@@ -72,6 +72,9 @@ struct QResultClass_
char
inTuples
;
/* is a fetch of rows from the backend in
* progress? */
char
aborted
;
/* was aborted? */
char
haskeyset
;
/* this result contains keyset ? */
KeySet
*
keyset
;
};
#define QR_get_fields(self) (self->fields)
...
...
@@ -102,6 +105,7 @@ struct QResultClass_
#define QR_set_status(self, condition) ( self->status = condition )
#define QR_set_message(self, message_) ( self->message = message_)
#define QR_set_aborted(self, aborted_) ( self->aborted = aborted_)
#define QR_set_haskeyset(self) (self->haskeyset = TRUE)
#define QR_get_message(self) (self->message)
#define QR_get_command(self) (self->command)
...
...
src/interfaces/odbc/results.c
View file @
01e32265
...
...
@@ -160,8 +160,7 @@ PGAPI_NumResultCols(
*
pccol
=
QR_NumResultCols
(
result
);
/* updatable cursors */
if
(
ci
->
updatable_cursors
&&
stmt
->
options
.
scroll_concurrency
!=
SQL_CONCUR_READ_ONLY
)
if
(
result
->
keyset
)
*
pccol
-=
2
;
}
...
...
@@ -433,7 +432,7 @@ PGAPI_ColAttributes(
*/
#if (ODBCVER >= 0x0300)
if
(
0
==
icol
)
/* bookmark column */
if
(
0
==
icol
&&
SQL_DESC_COUNT
!=
fDescType
)
/* bookmark column */
{
switch
(
fDescType
)
{
...
...
@@ -473,7 +472,11 @@ PGAPI_ColAttributes(
* Column Count is a special case. The Column number is ignored
* in this case.
*/
#if (ODBCVER >= 0x0300)
if
(
fDescType
==
SQL_DESC_COUNT
)
#else
if
(
fDescType
==
SQL_COLUMN_COUNT
)
#endif
/* ODBCVER */
{
if
(
pfDesc
)
*
pfDesc
=
cols
;
...
...
@@ -539,6 +542,8 @@ PGAPI_ColAttributes(
}
field_type
=
QR_get_field_type
(
SC_get_Curres
(
stmt
),
col_idx
);
if
(
stmt
->
parse_status
!=
STMT_PARSE_FATAL
&&
stmt
->
fi
&&
stmt
->
fi
[
col_idx
])
fi
=
stmt
->
fi
[
col_idx
];
}
mylog
(
"colAttr: col %d field_type = %d
\n
"
,
col_idx
,
field_type
);
...
...
@@ -549,6 +554,7 @@ PGAPI_ColAttributes(
value
=
pgtype_auto_increment
(
stmt
,
field_type
);
if
(
value
==
-
1
)
/* non-numeric becomes FALSE (ODBC Doc) */
value
=
FALSE
;
inolog
(
"AUTO_INCREMENT=%d
\n
"
,
value
);
break
;
...
...
@@ -581,9 +587,8 @@ PGAPI_ColAttributes(
#if (ODBCVER >= 0x0300)
case
SQL_DESC_NAME
:
#else
case
SQL_COLUMN_NAME
:
#endif
/* ODBCVER */
case
SQL_COLUMN_NAME
:
p
=
fi
?
(
fi
->
alias
[
0
]
?
fi
->
alias
:
fi
->
name
)
:
QR_get_fieldname
(
SC_get_Curres
(
stmt
),
col_idx
);
mylog
(
"PGAPI_ColAttr: COLUMN_NAME = '%s'
\n
"
,
p
);
...
...
@@ -597,14 +602,15 @@ PGAPI_ColAttributes(
case
SQL_COLUMN_MONEY
:
/* == SQL_DESC_FIXED_PREC_SCALE */
value
=
pgtype_money
(
stmt
,
field_type
);
inolog
(
"COLUMN_MONEY=%d
\n
"
,
value
);
break
;
#if (ODBCVER >= 0x0300)
case
SQL_DESC_NULLABLE
:
#else
case
SQL_COLUMN_NULLABLE
:
#endif
/* ODBCVER */
case
SQL_COLUMN_NULLABLE
:
value
=
fi
?
fi
->
nullable
:
pgtype_nullable
(
stmt
,
field_type
);
inolog
(
"COLUMN_NULLABLE=%d
\n
"
,
value
);
break
;
case
SQL_COLUMN_OWNER_NAME
:
/* == SQL_DESC_SCHEMA_NAME */
...
...
@@ -623,6 +629,7 @@ PGAPI_ColAttributes(
case
SQL_COLUMN_SCALE
:
value
=
pgtype_scale
(
stmt
,
field_type
,
col_idx
);
inolog
(
"COLUMN_SCALE=%d
\n
"
,
value
);
break
;
case
SQL_COLUMN_SEARCHABLE
:
/* SQL_DESC_SEARCHABLE */
...
...
@@ -637,6 +644,7 @@ PGAPI_ColAttributes(
case
SQL_COLUMN_TYPE
:
/* == SQL_DESC_CONCISE_TYPE */
value
=
pgtype_to_sqltype
(
stmt
,
field_type
);
inolog
(
"COLUMN_TYPE=%d
\n
"
,
value
);
break
;
case
SQL_COLUMN_TYPE_NAME
:
/* == SQL_DESC_TYPE_NAME */
...
...
@@ -658,7 +666,7 @@ PGAPI_ColAttributes(
* if (field_type == PG_TYPE_OID) pfDesc = SQL_ATTR_READONLY;
* else
*/
value
=
SQL_ATTR_WRITE
;
value
=
fi
?
(
fi
->
updatable
?
SQL_ATTR_WRITE
:
SQL_ATTR_READONLY
)
:
SQL_ATTR_READWRITE_UNKNOWN
;
mylog
(
"PGAPI_ColAttr: UPDATEABLE = %d
\n
"
,
value
);
break
;
...
...
@@ -1292,9 +1300,17 @@ PGAPI_ExtendedFetch(
if
(
result
==
SQL_ERROR
)
*
(
rgfRowStatus
+
i
)
=
SQL_ROW_ERROR
;
#ifdef DRIVER_CURSOR_IMPLEMENT
/* this should be refined */
else
if
(
result
>
10
&&
result
<
20
)
*
(
rgfRowStatus
+
i
)
=
result
-
10
;
else
if
(
res
->
keyset
)
{
UWORD
pstatus
=
res
->
keyset
[
stmt
->
currTuple
].
status
&
KEYSET_INFO_PUBLIC
;
if
(
pstatus
!=
0
)
{
rgfRowStatus
[
i
]
=
pstatus
;
res
->
keyset
[
stmt
->
currTuple
].
status
&=
(
~
KEYSET_INFO_PUBLIC
);
}
else
rgfRowStatus
[
i
]
=
SQL_ROW_SUCCESS
;
}
#endif
/* DRIVER_CURSOR_IMPLEMENT */
else
*
(
rgfRowStatus
+
i
)
=
SQL_ROW_SUCCESS
;
...
...
@@ -1347,7 +1363,7 @@ PGAPI_MoreResults(
mylog
(
"%s: entering...
\n
"
,
func
);
if
(
stmt
&&
(
res
=
SC_get_Curres
(
stmt
)))
SC_
get_Curres
(
stmt
)
=
res
->
next
;
SC_
set_Curres
(
stmt
,
res
->
next
)
;
if
(
SC_get_Curres
(
stmt
))
return
SQL_SUCCESS
;
return
SQL_NO_DATA_FOUND
;
...
...
@@ -1358,28 +1374,61 @@ PGAPI_MoreResults(
/*
* Stuff for updatable cursors.
*/
static
const
char
*
getOidValue
(
const
QResultClass
*
res
,
int
index
)
{
return
QR_get_value_backend_row
(
res
,
index
,
QR_NumResultCols
(
res
)
-
1
);
}
static
UInt4
getOid
(
const
QResultClass
*
res
,
int
index
)
{
return
res
->
keyset
[
index
].
oid
;
}
static
const
char
*
getTidValue
(
const
QResultClass
*
res
,
int
index
)
{
return
QR_get_value_backend_row
(
res
,
index
,
QR_NumResultCols
(
res
)
-
2
);
}
static
void
getTid
(
const
QResultClass
*
res
,
int
index
,
UInt4
*
blocknum
,
UInt2
*
offset
)
{
*
blocknum
=
res
->
keyset
[
index
].
blocknum
;
*
offset
=
res
->
keyset
[
index
].
offset
;
}
static
void
KeySetSet
(
const
QResultClass
*
res
,
int
index
)
{
int
num_fields
=
res
->
num_fields
;
TupleField
*
tuple
=
res
->
backend_tuples
+
num_fields
*
index
;
KeySet
*
keyset
=
res
->
keyset
+
index
;
sscanf
(
tuple
[
num_fields
-
2
].
value
,
"(%u,%hu)"
,
&
keyset
->
blocknum
,
&
keyset
->
offset
);
sscanf
(
tuple
[
num_fields
-
1
].
value
,
"%u"
,
&
keyset
->
oid
);
}
static
QResultClass
*
positioned_load
(
StatementClass
*
stmt
,
BOOL
latest
,
int
res_cols
,
UInt4
oid
,
const
char
*
tidval
)
{
int
i
;
QResultClass
*
qres
;
char
selstr
[
4096
];
char
*
selstr
;
UInt4
len
;
sprintf
(
selstr
,
"select"
);
for
(
i
=
0
;
i
<
res_cols
;
i
++
)
sprintf
(
selstr
,
"%s
\"
%s
\"
,"
,
selstr
,
stmt
->
fi
[
i
]
->
name
);
sprintf
(
selstr
,
"%s CTID, OID from
\"
%s
\"
where"
,
selstr
,
stmt
->
ti
[
0
]
->
name
);
len
=
strlen
(
stmt
->
load_statement
);
if
(
tidval
)
{
len
+=
100
;
selstr
=
malloc
(
len
);
if
(
latest
)
sprintf
(
selstr
,
"%s ctid = currtid2('%s', '%s') and"
,
selstr
,
stmt
->
ti
[
0
]
->
name
,
tidval
);
sprintf
(
selstr
,
"%s where ctid = currtid2('%s', '%s') and oid = %u"
,
stmt
->
load_statement
,
stmt
->
ti
[
0
]
->
name
,
tidval
,
oid
);
else
sprintf
(
selstr
,
"%s
ctid = '%s' and"
,
selstr
,
tidval
);
sprintf
(
selstr
,
"%s
where ctid = '%s' and oid = %u"
,
stmt
->
load_statement
,
tidval
,
oid
);
}
sprintf
(
selstr
,
"%s oid = %u"
,
selstr
,
oid
),
else
{
len
+=
20
;
selstr
=
malloc
(
len
);
sprintf
(
selstr
,
"%s where oid = %u"
,
stmt
->
load_statement
,
oid
);
}
mylog
(
"selstr=%s
\n
"
,
selstr
);
qres
=
CC_send_query
(
SC_get_conn
(
stmt
),
selstr
,
NULL
,
TRUE
);
qres
=
CC_send_query
(
SC_get_conn
(
stmt
),
selstr
,
NULL
,
CLEAR_RESULT_ON_ABORT
);
free
(
selstr
);
return
qres
;
}
...
...
@@ -1388,14 +1437,12 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
{
int
i
,
res_cols
;
UWORD
rcnt
,
global_ridx
;
UInt4
oid
;
UWORD
rcnt
,
global_ridx
,
offset
;
UInt4
oid
,
blocknum
;
QResultClass
*
res
,
*
qres
;
RETCODE
ret
=
SQL_ERROR
;
char
*
tidval
,
*
oidval
;
char
tidval
[
32
];
mylog
(
"positioned load fi=%x ti=%x
\n
"
,
stmt
->
fi
,
stmt
->
ti
);
rcnt
=
0
;
...
...
@@ -1412,15 +1459,18 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
}
global_ridx
=
irow
+
stmt
->
rowset_start
;
res_cols
=
QR_NumResultCols
(
res
);
if
(
!
(
oidval
=
QR_get_value_backend_row
(
res
,
global_ridx
,
res_cols
-
1
)))
if
(
!
(
oid
=
getOid
(
res
,
global_ridx
)))
return
SQL_SUCCESS_WITH_INFO
;
getTid
(
res
,
global_ridx
,
&
blocknum
,
&
offset
);
sprintf
(
tidval
,
"(%u, %u)"
,
blocknum
,
offset
);
/*if (!(oidval = getOidValue(res, global_ridx)))
return SQL_SUCCESS_WITH_INFO;
sscanf(oidval, "%u", &oid);
tidval
=
QR_get_value_backend_row
(
res
,
global_ridx
,
res_cols
-
2
);
tidval =
getTidValue(res, global_ridx);*/
res_cols
-=
2
;
if
(
qres
=
positioned_load
(
stmt
,
TRUE
,
res_cols
,
oid
,
tidval
),
qres
)
{
TupleField
*
tupleo
,
*
tuplen
;
TupleField
*
tupleo
,
*
tuplen
;
rcnt
=
QR_get_num_tuples
(
qres
);
tupleo
=
res
->
backend_tuples
+
res
->
num_fields
*
global_ridx
;
...
...
@@ -1437,6 +1487,13 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
tupleo
[
i
].
value
=
tuplen
[
i
].
value
;
tuplen
[
i
].
value
=
NULL
;
}
if
(
res
->
keyset
)
{
if
(
SQL_CURSOR_KEYSET_DRIVEN
==
stmt
->
options
.
cursor_type
&&
strcmp
(
tupleo
[
res
->
num_fields
-
2
].
value
,
tidval
))
res
->
keyset
[
global_ridx
].
status
|=
SQL_ROW_UPDATED
;
KeySetSet
(
res
,
global_ridx
);
}
ret
=
SQL_SUCCESS
;
}
else
...
...
@@ -1450,6 +1507,7 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
free
(
tupleo
[
res_cols
+
1
].
value
);
tupleo
[
res_cols
+
1
].
value
=
NULL
;
tupleo
[
res_cols
+
1
].
len
=
0
;
res
->
keyset
[
global_ridx
].
status
|=
SQL_ROW_DELETED
;
}
}
QR_Destructor
(
qres
);
...
...
@@ -1481,8 +1539,7 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval)
}
if
(
qres
=
positioned_load
(
stmt
,
TRUE
,
QR_NumResultCols
(
res
)
-
2
,
oid
,
tidval
),
qres
)
{
TupleField
*
tupleo
,
*
tuplen
;
TupleField
*
tupleo
,
*
tuplen
;
int
count
=
QR_get_num_tuples
(
qres
);
QR_set_position
(
qres
,
0
);
...
...
@@ -1507,6 +1564,8 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval)
QR_Destructor
(
qres
);
return
SQL_ERROR
;
}
if
(
res
->
haskeyset
)
res
->
keyset
=
(
KeySet
*
)
realloc
(
res
->
keyset
,
sizeof
(
KeySet
)
*
tuple_size
);
res
->
count_allocated
=
tuple_size
;
}
tupleo
=
res
->
backend_tuples
+
res
->
num_fields
*
res
->
fcount
;
...
...
@@ -1517,6 +1576,7 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval)
tupleo
[
i
].
value
=
tuplen
[
i
].
value
;
tuplen
[
i
].
value
=
NULL
;
}
KeySetSet
(
res
,
res
->
fcount
);
res
->
fcount
++
;
ret
=
SQL_SUCCESS
;
}
...
...
@@ -1533,12 +1593,12 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval)
}
static
RETCODE
SQL_API
irow_update
(
RETCODE
ret
,
StatementClass
*
stmt
,
UWORD
irow
)
irow_update
(
RETCODE
ret
,
StatementClass
*
stmt
,
StatementClass
*
ustmt
,
UWORD
irow
)
{
if
(
ret
!=
SQL_ERROR
)
{
int
updcnt
;
const
char
*
cmdstr
=
QR_get_command
(
SC_get_Curres
(
stmt
));
const
char
*
cmdstr
=
QR_get_command
(
SC_get_Curres
(
u
stmt
));
if
(
cmdstr
&&
sscanf
(
cmdstr
,
"UPDATE %d"
,
&
updcnt
)
==
1
)
...
...
@@ -1580,9 +1640,8 @@ SC_pos_update(StatementClass *stmt,
BindInfoClass
*
bindings
=
stmt
->
bindings
;
char
updstr
[
4096
];
RETCODE
ret
;
char
*
tidval
,
*
oidval
;
UInt4
offset
;
UInt4
oid
,
offset
,
blocknum
;
UInt2
pgoffset
;
Int4
*
used
;
mylog
(
"POS UPDATE %d+%d fi=%x ti=%x
\n
"
,
irow
,
SC_get_Curres
(
stmt
)
->
base
,
stmt
->
fi
,
stmt
->
ti
);
...
...
@@ -1597,12 +1656,14 @@ SC_pos_update(StatementClass *stmt,
}
global_ridx
=
irow
+
stmt
->
rowset_start
;
res_cols
=
QR_NumResultCols
(
res
);
if
(
!
(
oidval
=
QR_get_value_backend_row
(
res
,
global_ridx
,
res_cols
-
1
)))
/*if (!(oidval = getOidValue(res, global_ridx)))*/
if
(
!
(
oid
=
getOid
(
res
,
global_ridx
)))
{
stmt
->
errormsg
=
"The row is already deleted"
;
return
SQL_ERROR
;
}
tidval
=
QR_get_value_backend_row
(
res
,
global_ridx
,
res_cols
-
2
);
/*tidval = getTidValue(res, global_ridx);*/
getTid
(
res
,
global_ridx
,
&
blocknum
,
&
pgoffset
);
sprintf
(
updstr
,
"update
\"
%s
\"
set"
,
stmt
->
ti
[
0
]
->
name
);
num_cols
=
stmt
->
nfld
;
...
...
@@ -1635,8 +1696,10 @@ SC_pos_update(StatementClass *stmt,
int
res_cols
=
QR_NumResultCols
(
res
);
StatementClass
*
qstmt
;
sprintf
(
updstr
,
"%s where ctid = '%s' and oid = %s"
,
updstr
,
tidval
,
oidval
);
/*sprintf(updstr, "%s where ctid = '%s' and oid = %s", updstr,
tidval, oidval);*/
sprintf
(
updstr
,
"%s where ctid = '(%u, %u)' and oid = %u"
,
updstr
,
blocknum
,
pgoffset
,
oid
);
mylog
(
"updstr=%s
\n
"
,
updstr
);
if
(
PGAPI_AllocStmt
(
SC_get_conn
(
stmt
),
&
hstmt
)
!=
SQL_SUCCESS
)
return
SQL_ERROR
;
...
...
@@ -1676,11 +1739,13 @@ SC_pos_update(StatementClass *stmt,
stmt
->
errormsg
=
"SetPos with data_at_exec not yet supported"
;
ret
=
SQL_ERROR
;
}
ret
=
irow_update
(
ret
,
qstmt
,
irow
);
ret
=
irow_update
(
ret
,
stmt
,
qstmt
,
irow
);
PGAPI_FreeStmt
(
hstmt
,
SQL_DROP
);
}
else
ret
=
SQL_SUCCESS_WITH_INFO
;
if
(
SQL_SUCCESS
==
ret
&&
res
->
keyset
)
res
->
keyset
[
global_ridx
].
status
|=
(
SQL_ROW_UPDATED
|
DRV_SELF_UPDATED
);
#if (ODBCVER >= 0x0300)
if
(
stmt
->
options
.
rowStatusArray
)
{
...
...
@@ -1689,9 +1754,8 @@ SC_pos_update(StatementClass *stmt,
case
SQL_SUCCESS
:
stmt
->
options
.
rowStatusArray
[
irow
]
=
SQL_ROW_UPDATED
;
break
;
case
SQL_SUCCESS_WITH_INFO
:
stmt
->
options
.
rowStatusArray
[
irow
]
=
SQL_ROW_SUCCESS_WITH_INFO
;
break
;
default:
stmt
->
options
.
rowStatusArray
[
irow
]
=
ret
;
}
}
#endif
/* ODBCVER */
...
...
@@ -1703,13 +1767,13 @@ SC_pos_delete(StatementClass *stmt,
UWORD
irow
)
{
int
res_cols
;
UWORD
global_ridx
;
QResultClass
*
res
,
*
qres
;
UWORD
global_ridx
,
offset
;
QResultClass
*
res
,
*
qres
;
BindInfoClass
*
bindings
=
stmt
->
bindings
;
char
dltstr
[
4096
];
RETCODE
ret
;
char
*
oidval
;
/*const char *oidval;*/
UInt4
oid
,
blocknum
;
mylog
(
"POS DELETE fi=%x ti=%x
\n
"
,
stmt
->
fi
,
stmt
->
ti
);
if
(
!
(
res
=
SC_get_Curres
(
stmt
)))
...
...
@@ -1723,18 +1787,20 @@ SC_pos_delete(StatementClass *stmt,
}
res_cols
=
QR_NumResultCols
(
res
);
global_ridx
=
irow
+
stmt
->
rowset_start
;
if
(
!
(
oidval
=
QR_get_value_backend_row
(
res
,
global_ridx
,
res_cols
-
1
)))
/* if (!(oidval = getOidValue(res, global_ridx)))*/
if
(
!
(
oid
=
getOid
(
res
,
global_ridx
)))
{
stmt
->
errormsg
=
"The row is already deleted"
;
return
SQL_ERROR
;
}
sprintf
(
dltstr
,
"delete from
\"
%s
\"
where ctid = '%s' and oid = %s"
,
stmt
->
ti
[
0
]
->
name
,
QR_get_value_backend_row
(
SC_get_Curres
(
stmt
),
global_ridx
,
res_cols
-
2
)
,
oidval
);
getTid
(
res
,
global_ridx
,
&
blocknum
,
&
offset
);
/*sprintf(dltstr, "delete from \"%s\" where ctid = '%s' and oid = %s",*/
sprintf
(
dltstr
,
"delete from
\"
%s
\"
where ctid = '(%u, %u)' and oid = %u"
,
stmt
->
ti
[
0
]
->
name
,
blocknum
,
offset
,
oid
);
mylog
(
"dltstr=%s
\n
"
,
dltstr
);
qres
=
CC_send_query
(
SC_get_conn
(
stmt
),
dltstr
,
NULL
,
TRUE
);
qres
=
CC_send_query
(
SC_get_conn
(
stmt
),
dltstr
,
NULL
,
CLEAR_RESULT_ON_ABORT
);
ret
=
SQL_SUCCESS
;
if
(
qres
&&
QR_command_successful
(
qres
))
{
int
dltcnt
;
...
...
@@ -1769,6 +1835,8 @@ SC_pos_delete(StatementClass *stmt,
}
if
(
qres
)
QR_Destructor
(
qres
);
if
(
SQL_SUCCESS
==
ret
&&
res
->
keyset
)
res
->
keyset
[
global_ridx
].
status
|=
(
SQL_ROW_DELETED
|
DRV_SELF_DELETED
);
#if (ODBCVER >= 0x0300)
if
(
stmt
->
options
.
rowStatusArray
)
{
...
...
@@ -1777,9 +1845,8 @@ SC_pos_delete(StatementClass *stmt,
case
SQL_SUCCESS
:
stmt
->
options
.
rowStatusArray
[
irow
]
=
SQL_ROW_DELETED
;
break
;
case
SQL_SUCCESS_WITH_INFO
:
stmt
->
options
.
rowStatusArray
[
irow
]
=
SQL_ROW_SUCCESS_WITH_INFO
;
break
;
default:
stmt
->
options
.
rowStatusArray
[
irow
]
=
ret
;
}
}
#endif
/* ODBCVER */
...
...
@@ -1787,13 +1854,13 @@ SC_pos_delete(StatementClass *stmt,
}
static
RETCODE
SQL_API
irow_insert
(
RETCODE
ret
,
StatementClass
*
stmt
,
int
addpos
)
irow_insert
(
RETCODE
ret
,
StatementClass
*
stmt
,
StatementClass
*
istmt
,
int
addpos
)
{
if
(
ret
!=
SQL_ERROR
)
{
int
addcnt
;
UInt4
oid
;
const
char
*
cmdstr
=
QR_get_command
(
SC_get_Curres
(
stmt
));
const
char
*
cmdstr
=
QR_get_command
(
SC_get_Curres
(
i
stmt
));
if
(
cmdstr
&&
sscanf
(
cmdstr
,
"INSERT %u %d"
,
&
oid
,
&
addcnt
)
==
2
&&
...
...
@@ -1803,11 +1870,13 @@ irow_insert(RETCODE ret, StatementClass *stmt, int addpos)
if
(
stmt
->
bookmark
.
buffer
)
{
char
buf
[
32
];
UInt4
offset
=
stmt
->
options
.
row_offset_ptr
?
*
stmt
->
options
.
row_offset_ptr
:
0
;
sprintf
(
buf
,
"%ld"
,
addpos
);
sprintf
(
buf
,
"%ld"
,
addpos
+
1
);
copy_and_convert_field
(
stmt
,
0
,
buf
,
SQL_C_ULONG
,
stmt
->
bookmark
.
buffer
,
0
,
stmt
->
bookmark
.
used
);
SQL_C_ULONG
,
stmt
->
bookmark
.
buffer
+
offset
,
0
,
stmt
->
bookmark
.
used
?
stmt
->
bookmark
.
used
+
(
offset
>>
2
)
:
NULL
);
}
}
else
...
...
@@ -1882,6 +1951,7 @@ SC_pos_add(StatementClass *stmt,
}
if
(
add_cols
>
0
)
{
int
brow_save
;
sprintf
(
addstr
,
"%s) values ("
,
addstr
);
for
(
i
=
0
;
i
<
add_cols
;
i
++
)
...
...
@@ -1907,11 +1977,16 @@ SC_pos_add(StatementClass *stmt,
stmt
->
errormsg
=
"SetPos with data_at_exec not yet supported"
;
ret
=
SQL_ERROR
;
}
ret
=
irow_insert
(
ret
,
qstmt
,
res
->
fcount
);
brow_save
=
stmt
->
bind_row
;
stmt
->
bind_row
=
irow
;
ret
=
irow_insert
(
ret
,
stmt
,
qstmt
,
res
->
fcount
);
stmt
->
bind_row
=
brow_save
;
}
else
ret
=
SQL_SUCCESS_WITH_INFO
;
PGAPI_FreeStmt
(
hstmt
,
SQL_DROP
);
if
(
SQL_SUCCESS
==
ret
&&
res
->
keyset
)
res
->
keyset
[
res
->
fcount
-
1
].
status
|=
DRV_SELF_ADDED
;
#if (ODBCVER >= 0x0300)
if
(
stmt
->
options
.
rowStatusArray
)
{
...
...
@@ -1920,9 +1995,8 @@ SC_pos_add(StatementClass *stmt,
case
SQL_SUCCESS
:
stmt
->
options
.
rowStatusArray
[
irow
]
=
SQL_ROW_ADDED
;
break
;
case
SQL_SUCCESS_WITH_INFO
:
stmt
->
options
.
rowStatusArray
[
irow
]
=
SQL_ROW_SUCCESS_WITH_INFO
;
break
;
default:
stmt
->
options
.
rowStatusArray
[
irow
]
=
ret
;
}
}
#endif
/* ODBCVER */
...
...
@@ -1947,6 +2021,7 @@ PGAPI_SetPos(
UWORD
fLock
)
{
static
char
*
func
=
"PGAPI_SetPos"
;
RETCODE
ret
;
StatementClass
*
stmt
=
(
StatementClass
*
)
hstmt
;
QResultClass
*
res
;
int
num_cols
,
...
...
@@ -1960,7 +2035,7 @@ PGAPI_SetPos(
}
#ifdef DRIVER_CURSOR_IMPLEMENT
mylog
(
"
SetPos fOption=%d irow=%d lock=%d currt=%d
\n
"
,
fOption
,
irow
,
fLock
,
stmt
->
currTuple
);
mylog
(
"
%s fOption=%d irow=%d lock=%d currt=%d
\n
"
,
func
,
fOption
,
irow
,
fLock
,
stmt
->
currTuple
);
if
(
stmt
->
options
.
scroll_concurrency
!=
SQL_CONCUR_READ_ONLY
)
;
else
...
...
@@ -1982,13 +2057,41 @@ PGAPI_SetPos(
}
num_cols
=
QR_NumResultCols
(
res
);
if
(
irow
==
0
)
if
(
irow
==
0
)
/* bulk operation */
{
int
processed
;
if
(
SQL_POSITION
==
fOption
)
{
stmt
->
errornumber
=
STMT_ROW_OUT_OF_RANGE
;
stmt
->
errormsg
=
"Driver does not support Bulk operations
."
;
stmt
->
errormsg
=
"Bulk Fresh operations not allowed
."
;
SC_log_error
(
func
,
""
,
stmt
);
return
SQL_ERROR
;
}
ret
=
SQL_SUCCESS
;
for
(
i
=
0
,
processed
=
0
;
i
<
stmt
->
options
.
rowset_size
;
i
++
)
{
#if (ODBCVER >= 0x0300)
if
(
!
stmt
->
options
.
row_operation_ptr
||
stmt
->
options
.
row_operation_ptr
[
i
]
==
SQL_ROW_PROCEED
)
{
#endif
/* ODBCVER */
if
(
ret
=
PGAPI_SetPos
(
hstmt
,
(
UWORD
)
(
i
+
1
),
fOption
,
fLock
),
SQL_ERROR
==
ret
)
break
;
processed
++
;
#if (ODBCVER >= 0x0300)
}
#endif
/* ODBCVER */
}
if
(
processed
>
0
&&
SQL_ERROR
==
ret
)
{
processed
++
;
ret
=
SQL_SUCCESS_WITH_INFO
;
stmt
->
errornumber
=
STMT_ERROR_IN_ROW
;
}
if
(
stmt
->
options
.
rowsFetched
)
*
stmt
->
options
.
rowsFetched
=
processed
;
return
ret
;
}
if
(
irow
>
stmt
->
last_fetch_count
)
{
...
...
src/interfaces/odbc/statement.c
View file @
01e32265
...
...
@@ -242,6 +242,7 @@ SC_Constructor(void)
rv
->
statement
=
NULL
;
rv
->
stmt_with_params
=
NULL
;
rv
->
load_statement
=
NULL
;
rv
->
stmt_size_limit
=
-
1
;
rv
->
statement_type
=
STMT_TYPE_UNKNOWN
;
...
...
@@ -318,6 +319,8 @@ SC_Destructor(StatementClass *self)
free
(
self
->
stmt_with_params
);
self
->
stmt_with_params
=
NULL
;
}
if
(
self
->
load_statement
)
free
(
self
->
load_statement
);
SC_free_params
(
self
,
STMT_FREE_PARAMS_ALL
);
...
...
@@ -548,6 +551,12 @@ SC_recycle_statement(StatementClass *self)
* SQLParamData/SQLPutData is called.
*/
SC_free_params
(
self
,
STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY
);
if
(
self
->
stmt_with_params
)
free
(
self
->
stmt_with_params
);
self
->
stmt_with_params
=
NULL
;
if
(
self
->
load_statement
)
free
(
self
->
load_statement
);
self
->
load_statement
=
NULL
;
return
TRUE
;
}
...
...
@@ -635,12 +644,16 @@ SC_create_errormsg(StatementClass *self)
QResultClass
*
res
=
SC_get_Curres
(
self
);
ConnectionClass
*
conn
=
self
->
hdbc
;
int
pos
;
BOOL
detailmsg
=
FALSE
;
static
char
msg
[
4096
];
msg
[
0
]
=
'\0'
;
if
(
res
&&
res
->
message
)
{
strcpy
(
msg
,
res
->
message
);
detailmsg
=
TRUE
;
}
else
if
(
self
->
errormsg
)
strcpy
(
msg
,
self
->
errormsg
);
...
...
@@ -660,10 +673,10 @@ SC_create_errormsg(StatementClass *self)
{
SocketClass
*
sock
=
conn
->
sock
;
if
(
conn
->
errormsg
&&
conn
->
errormsg
[
0
]
!=
'\0'
)
if
(
!
detailmsg
&&
conn
->
errormsg
&&
conn
->
errormsg
[
0
]
!=
'\0'
)
{
pos
=
strlen
(
msg
);
/*sprintf(&msg[pos], ";\n%s", conn->errormsg);*/
sprintf
(
&
msg
[
pos
],
";
\n
%s"
,
conn
->
errormsg
);
}
if
(
sock
&&
sock
->
errormsg
&&
sock
->
errormsg
[
0
]
!=
'\0'
)
...
...
@@ -722,9 +735,6 @@ SC_fetch(StatementClass *self)
int
retval
,
result
;
#ifdef DRIVER_CURSOR_IMPLEMENT
int
updret
;
#endif
/* DRIVER_CURSOR_IMPLEMENT */
Int2
num_cols
,
lf
;
Oid
type
;
...
...
@@ -799,20 +809,13 @@ SC_fetch(StatementClass *self)
}
#ifdef DRIVER_CURSOR_IMPLEMENT
updret
=
0
;
if
(
self
->
options
.
scroll_concurrency
!=
SQL_CONCUR_READ_ONLY
)
{
if
(
!
QR_get_value_backend_row
(
res
,
self
->
currTuple
,
num_cols
-
1
))
updret
=
SQL_ROW_DELETED
;
num_cols
-=
2
;
}
#endif
/* DRIVER_CURSOR_IMPLEMENT */
if
(
self
->
options
.
retrieve_data
==
SQL_RD_OFF
)
/* data isn't required */
#ifdef DRIVER_CURSOR_IMPLEMENT
return
updret
?
updret
+
10
:
SQL_SUCCESS
;
#else
return
SQL_SUCCESS
;
#endif
/* DRIVER_CURSOR_IMPLEMENT */
for
(
lf
=
0
;
lf
<
num_cols
;
lf
++
)
{
mylog
(
"fetch: cols=%d, lf=%d, self = %u, self->bindings = %u, buffer[] = %u
\n
"
,
num_cols
,
lf
,
self
,
self
->
bindings
,
self
->
bindings
[
lf
].
buffer
);
...
...
@@ -893,10 +896,6 @@ SC_fetch(StatementClass *self)
}
}
#ifdef DRIVER_CURSOR_IMPLEMENT
if
(
updret
)
result
=
updret
+
10
;
#endif
/* DRIVER_CURSOR_IMPLEMENT */
return
result
;
}
...
...
@@ -955,11 +954,12 @@ SC_execute(StatementClass *self)
if
(
self
->
statement_type
==
STMT_TYPE_SELECT
)
{
char
fetch
[
128
];
UDWORD
qflag
=
(
SQL_CONCUR_ROWVER
==
self
->
options
.
scroll_concurrency
?
CREATE_KEYSET
:
0
);
mylog
(
" Sending SELECT statement on stmt=%u, cursor_name='%s'
\n
"
,
self
,
self
->
cursor_name
);
/* send the declare/select */
res
=
CC_send_query
(
conn
,
self
->
stmt_with_params
,
NULL
,
FALSE
);
res
=
CC_send_query
(
conn
,
self
->
stmt_with_params
,
NULL
,
qflag
);
if
(
SC_is_fetchcursor
(
self
)
&&
res
!=
NULL
&&
QR_command_successful
(
res
))
{
...
...
@@ -982,7 +982,7 @@ SC_execute(StatementClass *self)
*/
sprintf
(
fetch
,
"fetch %d in %s"
,
qi
.
row_size
,
self
->
cursor_name
);
res
=
CC_send_query
(
conn
,
fetch
,
&
qi
,
FALSE
);
res
=
CC_send_query
(
conn
,
fetch
,
&
qi
,
qflag
);
}
mylog
(
" done sending the query:
\n
"
);
}
...
...
@@ -990,7 +990,7 @@ SC_execute(StatementClass *self)
{
/* not a SELECT statement so don't use a cursor */
mylog
(
" it's NOT a select statement: stmt=%u
\n
"
,
self
);
res
=
CC_send_query
(
conn
,
self
->
stmt_with_params
,
NULL
,
FALSE
);
res
=
CC_send_query
(
conn
,
self
->
stmt_with_params
,
NULL
,
0
);
/*
* We shouldn't send COMMIT. Postgres backend does the autocommit
...
...
src/interfaces/odbc/statement.h
View file @
01e32265
...
...
@@ -76,6 +76,7 @@ typedef enum
#define STMT_BAD_ERROR 27
#define STMT_INVALID_OPTION_IDENTIFIER 28
#define STMT_RETURN_NULL_WITHOUT_INDICATOR 29
#define STMT_ERROR_IN_ROW 30
/* statement types */
enum
...
...
@@ -135,6 +136,7 @@ typedef struct
char
quote
;
char
dquote
;
char
numeric
;
char
updatable
;
char
dot
[
MAX_TABLE_LEN
+
1
];
char
name
[
MAX_COLUMN_LEN
+
1
];
char
alias
[
MAX_COLUMN_LEN
+
1
];
...
...
@@ -219,11 +221,15 @@ struct StatementClass_
char
miscinfo
;
SWORD
errorpos
;
SWORD
error_recsize
;
char
*
load_statement
;
/* to (re)load updatable individual rows */
Int4
from_pos
;
Int4
where_pos
;
};
#define SC_get_conn(a) (a->hdbc)
#define SC_set_Result(a, b) (a->result = a->curres = b)
#define SC_get_Result(a) (a->result)
#define SC_set_Curres(a, b) (a->curres = b)
#define SC_get_Curres(a) (a->curres)
/* options for SC_free_params() */
...
...
src/interfaces/odbc/tuple.h
View file @
01e32265
...
...
@@ -30,6 +30,19 @@ struct TupleNode_
TupleField
tuple
[
1
];
};
/* keyset(TID + OID) info */
struct
KeySet_
{
UWORD
status
;
UWORD
offset
;
UDWORD
blocknum
;
UDWORD
oid
;
};
#define KEYSET_INFO_PUBLIC 0x0f
#define DRV_SELF_ADDED (1L << 4)
#define DRV_SELF_DELETED (1L << 5)
#define DRV_SELF_UPDATED (1L << 6)
/* These macros are wrappers for the corresponding set_tuplefield functions
but these handle automatic NULL determination and call set_tuplefield_null()
if appropriate for the datatype (used by SQLGetTypeInfo).
...
...
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