Closed KarlKeiser closed 5 years ago
The reason you are seeing this is that dpiStmt_bindValueByPos() and dpiStmt_bindValueByName() only accept the native type (by design). They do not accept the Oracle type and simply use the default Oracle type (which as you noted doesn't include the time zone for DPI_NATIVE_TYPE_TIMESTAMP). If you want to bind a timestamp with time zone you'll need to use the somewhat more complex process of creating a variable and binding it. Like this:
dpiData *bindData;
dpiVar *bindVar;
if (dpiConn_newVar(conn, DPI_ORACLE_TYPE_TIMESTAMP_TZ, DPI_NATIVE_TYPE_TIMESTAMP,
1, 0, 0, 0, NULL, &bindVar, &bindData) < 0) {
printf("Failed to create variable!\n");
return -1;
}
dpiData_setTimestamp(&bindData, 2003, 1, 2, 3, 44, 55, /*fsec*/660000000, /*tzHour*/7, /*tzMin*/8);
if (dpiStmt_bindByPos(stmt, 1, bindVar) < 0) {
printf("Failed to bind data!\n");
return -1;
}
That solved my problem. Thank you very much, Anthony!
I want to store a timestamp with time zone in a database and retrieve it again. The retrieving part is working, however submitting the timestamp causes a problem. It only works correctly when I give the timestamp as a string in the SQL query. When I try to bind it instead, the time zones get deleted.
So this is working:
And this isn't:
Click here for a gist that (hopefully) reproduces the problem.
In short, it does the following:
ALTER SESSION
to something like10:55
dpiTimestamp
, inserts it using bindsdpiTimestamp
that was inserteddpiTimestamp
for both queries and prints themThis is the result:
The directly inserted timestamp has the timezone
+07:08
, as specified in the SQL query. The bound timestamp, however, lost that timezone and instead got the+10:55
timezone we set for the session earlier.What I believe to be the problem
The bind is done like this:
Here,
DPI_NATIVE_TYPE_TIMESTAMP
has to be given, there seems to be no other option for timestamps. Internally,dpiStmt_bindValueByPos
then passes that todpiStmt__createBindVar
(in dpiStmt.c). Here, this code is on line 370:If we change that
DPI_ORACLE_TYPE_TIMESTAMP
toDPI_ORACLE_TYPE_TIMESTAMP_TZ
, then the program generates the correct output:It appears that
DPI_ORACLE_TYPE_TIMESTAMP
discards the time zone info. Perhaps there was supposed to be a functionality where it recognizes that the column is defined asTIMESTAMP(9) WITH TIME ZONE
and gives the according internal datatype. Of course I'd also be very happy about a DPI_NATIVE_TYPE_TIMESTAMP_TZ type specifier. :)(or perhaps I'm completely misunderstanding how this functionality works)
Answer the following questions:
1. What version of ODPI-C are you using (see dpi.h)?
Version 3.0.0
2. What exact command caused the problem (e.g. what command did you try to install with)? Who were you logged in as?
dpiStmt_bindValueByPos
seems to be causing the issue3. What error(s) you are seeing?
The wrong time zone is stored, this can be seen both by fetching it with ODPI and by viewing the table in sqlplus
4. What OS (and version) is your application executing on?
Microsoft Windows 10 Home 10.0.17134 Build 17134
5. What is your version of the Oracle client (e.g. Instant Client)? How was it installed? Where it is installed?
instantclient_18_3, installed in C:\Oracle, downloaded from Oracle's site
6. What is your Oracle Database version?
7. What is the
PATH
environment variable (on Windows) orLD_LIBRARY_PATH
(on Linux) set to? On macOS, what is in~/lib
?8. What environment variables did you set? How exactly did you set them?
9. What compiler version did you use?
Also getting the problem with