-
Notifications
You must be signed in to change notification settings - Fork 185
timestamp in cursor comparison > expect() has problem with precision / nls #771
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi @MalchiasTS SQL and PLSQL engine are separate and it seems like Oracle is passing timestamp variables as variables with maximum precission The proposed fix will only work for I have updated your example to get it to work without any changes to framework. create or replace package body p_nls_test_ut
is
procedure ut_insert_into_nls_test
is
lv_new_id number;
lv_ts timestamp(9);
lc_exp sys_refcursor;
lc_act sys_refcursor;
begin
-- get new id
select max(id)+1
into lv_new_id
from tmp_nls_test;
-- get a valid timestamp with timezone
select systimestamp
into lv_ts
from dual;
-- insert a record with these values
p_nls_test.insert_into_nls_test (lv_new_id, null, lv_ts, null);
-- build two cursors
ut.set_nls();
-- fill cursor with expected values by selecting from dual
open lc_exp for
select
lv_new_id as id,
to_timestamp (null) as ats3,
cast(lv_ts as timestamp(6)) as ats6,
to_timestamp (null) as ats9
from dual;
-- fill cursor with actual table values.
open lc_act for
select id, ats3, ats6, ats9
from tmp_nls_test
where id = 2;
ut.reset_nls();
-- compare variable with table values
ut.expect (lc_act).to_equal (lc_exp);
end ut_insert_into_nls_test;
end p_nls_test_ut;
/
begin
ut.run ('p_nls_test_ut');
end;
/
The changed part is use of CAST on the PLSQL bind variable that is passed to SQL statement:
Please let me know if the solution above, is what you were seeking for. To make some additional investigation I've done a check using DECLARE
lv_ts timestamp(6);
lc_exp sys_refcursor;
c NUMBER;
d NUMBER;
col_cnt INTEGER;
f BOOLEAN;
rec_tab DBMS_SQL.DESC_TAB;
col_num NUMBER;
PROCEDURE print_rec(rec in DBMS_SQL.DESC_REC) IS
BEGIN
DBMS_OUTPUT.NEW_LINE;
DBMS_OUTPUT.PUT_LINE('col_type = '
|| rec.col_type);
DBMS_OUTPUT.PUT_LINE('col_maxlen = '
|| rec.col_max_len);
DBMS_OUTPUT.PUT_LINE('col_name = '
|| rec.col_name);
DBMS_OUTPUT.PUT_LINE('col_name_len = '
|| rec.col_name_len);
DBMS_OUTPUT.PUT_LINE('col_schema_name = '
|| rec.col_schema_name);
DBMS_OUTPUT.PUT_LINE('col_schema_name_len = '
|| rec.col_schema_name_len);
DBMS_OUTPUT.PUT_LINE('col_precision = '
|| rec.col_precision);
DBMS_OUTPUT.PUT_LINE('col_scale = '
|| rec.col_scale);
DBMS_OUTPUT.PUT('col_null_ok = ');
IF (rec.col_null_ok) THEN
DBMS_OUTPUT.PUT_LINE('true');
ELSE
DBMS_OUTPUT.PUT_LINE('false');
END IF;
END;
BEGIN
lv_ts := systimestamp;
open lc_exp for
select
lv_ts as ats9,
cast(lv_ts as timestamp(6)) as ats6
from dual;
c := DBMS_SQL.TO_CURSOR_NUMBER(lc_exp);
DBMS_SQL.DESCRIBE_COLUMNS(c, col_cnt, rec_tab);
col_num := rec_tab.first;
IF (col_num IS NOT NULL) THEN
LOOP
print_rec(rec_tab(col_num));
col_num := rec_tab.next(col_num);
EXIT WHEN (col_num IS NULL);
END LOOP;
END IF;
DBMS_SQL.CLOSE_CURSOR(c);
END;
/ It gives:
So you can see that SCALE of variable without CAST = 6. |
Perhaps we should update documentation with this note as it seems something that might be significant. |
That solves it for us. Thank you very much. Outstanding work - as usual :-) |
Hi, why not simply change declaration: into: or better define pl/sql variable the same as table: |
Hi @emanueol to answer your questions: Because - strangely enough - neither of your suggestions solve the problem. Both will lead to the failure I described. Only the |
I have a second thought on this.
If we force users to use So it seems that the fix could be as simple as change of one line in FROM: gc_timestamp_format constant varchar2(100) := 'yyyy-mm-dd"T"hh24:mi:ssxff'; TO: gc_timestamp_format constant varchar2(100) := 'yyyy-mm-dd"T"hh24:mi:ssxff9'; Note that that would be ff9, not like originally proposed ff6, so we can always compare with max precision. @MalchiasTS , @Shoelace @emanueol - any thoughts? |
After a bit of investigation and testing I have realized, it is not doable in PLSQL. The only thing to be done is to raise a defect/bug to Oracle Support to get that resolved. |
In our project we use a lot of
timestamp(6)
columns. Our calls tout.expect()
run into problems with comparisons between sys_refcursors that containtimestamp(6)
columns.I prepared three little attachments that should help demonstrate the problem and show our current solution. But this solution is not perfect, as it only fixes the problem for our
timestamp(6)
columns and we would like to see a more general solution.If you can help in any way, that would be great.
Attachments
setup.sql
- creates one table and two packages designed to demonstrate the problem.problem_demo.sql
- shows our NLS_SESSION_PARAMETERS, starts the ut-test and quotes the fail message we get from this unit test run ... if we do not patch the current UT3 installationour_solution_so_far.txt
- describes how we got around the problem with a very small patch, but we lack the utplsql knowlege to find a general fix, so we ask you for help.setup.sql
- creates one table and two packages designed to demonstrate the problemproblem_demo.sql
- shows our NLS_SESSION_PARAMETERS, starts the ut-test and quotes the fail message we get from this unit test run ... if we do not patch the current UT3 installation.our_solution_so_far.txt
- describes how we got around the problem with a very small patch, but we lack the utplsql knowlege to find a general fix, so we ask you for help.What fixed it for us was ...
We patched two rows in the header of package
UT_UTILS
:line 120:
line 121:
This patch only fixes it for
timestamp(6)
.Lucky for us, if we use timestamp types at all, then we always use
TIMESTAMP(6)
... presently.What would be a general solution?
The text was updated successfully, but these errors were encountered: