December 1, 2010
Another recent blog article forced me to Stop, Think, … and just about understand (in case you are wondering about the blog title, the definition of invalid).
Consider the following table definition:
CREATE TABLE T3( V1 VARCHAR2(10), D2 DATE, N3 NUMBER); INSERT INTO T3 VALUES( CHR(65), TRUNC(SYSDATE)-65, 65); EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=>USER,TABNAME=>'T3') SELECT * FROM T3; V1 D2 N3 ---------- --------- ---------- A 27-SEP-10 65
—
Which of the following SQL statements are valid SQL statements for the above table (E is not an option)?
A:
SELECT * FROM T3 WHERE TO_NUMBER(V1)=1;
B:
SELECT * FROM T3 WHERE TO_NUMBER(V1)=TO_NUMBER('A');
C:
SELECT * FROM T3 WHERE TO_NUMBER(V1)=1 AND ROWNUM=2;
D:
SELECT * FROM T3 WHERE TO_NUMBER(V1)=1 AND 1=2;
E:
SELECT * FROM T3 WHERE TO_NUMBER(V1)=1 AND 1=2;
F:
SELECT * FROM T3 WHERE TO_DATE(D2) = '27-SEP-2010';
G:
SELECT * FROM T3 WHERE TO_DATE(D2) = '32-SEP-2010';
H:
SELECT * FROM T3 WHERE D2 = '32-SEP-2010' AND 1=2;
I:
SELECT * FROM T3 WHERE TO_DATE(D2) = N3;
J:
SELECT * FROM T3 WHERE TO_DATE(D2) = N3 AND TO_CHAR(1)='2';
K:
SELECT * FROM T3 WHERE TO_DATE(D2) = N3 AND 1=2;
L:
SELECT * FROM T3 WHERE N3 = 'A';
M:
SELECT * FROM T3 WHERE N3 = '27-SEP-2010';
N:
SELECT * FROM T3 WHERE N3 = '32-SEP-2010';
——————-
Stop and think about it for a moment, which of the above are valid SQL statements?
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
We could use the AUTOTRACE feature in SQL*Plus to tell which are valid, and which are not:
SET LINESIZE 140 SET TRIMSPOOL ON SET PAGESIZE 1000 SET AUTOTRACE TRACEONLY EXPLAIN SELECT * FROM T3 WHERE TO_NUMBER(V1)=1; SELECT * FROM T3 WHERE TO_NUMBER(V1)=TO_NUMBER('A'); SELECT * FROM T3 WHERE TO_NUMBER(V1)=1 AND ROWNUM=2; SELECT * FROM T3 WHERE TO_NUMBER(V1)=1 AND 1=2; SELECT * FROM T3 WHERE TO_DATE(D2) = '27-SEP-2010'; SELECT * FROM T3 WHERE TO_DATE(D2) = '32-SEP-2010'; SELECT * FROM T3 WHERE D2 = '32-SEP-2010' AND 1=2; SELECT * FROM T3 WHERE TO_DATE(D2) = N3; SELECT * FROM T3 WHERE TO_DATE(D2) = N3 AND TO_CHAR(1)='2'; SELECT * FROM T3 WHERE TO_DATE(D2) = N3 AND 1=2; SELECT * FROM T3 WHERE N3 = 'A'; SELECT * FROM T3 WHERE N3 = '27-SEP-2010'; SELECT * FROM T3 WHERE N3 = '32-SEP-2010';
The results might look like this:
A:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_NUMBER(V1)=1; Execution Plan ---------------------------------------------------------- Plan hash value: 4161002650 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 13 | 2 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| T3 | 1 | 13 | 2 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(TO_NUMBER("V1")=1)
B:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_NUMBER(V1)=TO_NUMBER('A'); Execution Plan ---------------------------------------------------------- Plan hash value: 4161002650 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 13 | 2 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| T3 | 1 | 13 | 2 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(TO_NUMBER("V1")=TO_NUMBER('A'))
C:
SQL> SELECT 2 * 3 FROM 4 T3 WHERE TO_NUMBER(V1)=1 5 AND ROWNUM=2; Execution Plan ---------------------------------------------------------- Plan hash value: 1538339754 ---------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 13 | 2 (0)| 00:00:01 | | 1 | COUNT | | | | | | |* 2 | FILTER | | | | | | |* 3 | TABLE ACCESS FULL| T3 | 1 | 13 | 2 (0)| 00:00:01 | ---------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter(ROWNUM=2) 3 - filter(TO_NUMBER("V1")=1)
D:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_NUMBER(V1)=1 7 AND 1=2; Execution Plan ---------------------------------------------------------- Plan hash value: 3859223164 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 13 | 0 (0)| | |* 1 | FILTER | | | | | | |* 2 | TABLE ACCESS FULL| T3 | 1 | 13 | 2 (0)| 00:00:01 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(NULL IS NOT NULL) 2 - filter(TO_NUMBER("V1")=1)
F:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_DATE(D2) = '27-SEP-2010'; Execution Plan ---------------------------------------------------------- Plan hash value: 4161002650 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 13 | 2 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| T3 | 1 | 13 | 2 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(TO_DATE(INTERNAL_FUNCTION("D2"))=TO_DATE(' 2010-09-27 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
G:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_DATE(D2) = '32-SEP-2010'; Execution Plan ---------------------------------------------------------- Plan hash value: 4161002650 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 13 | 2 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| T3 | 1 | 13 | 2 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(TO_DATE(INTERNAL_FUNCTION("D2"))='32-SEP-2010')
H:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 D2 = '32-SEP-2010' 7 AND 1=2; Execution Plan ---------------------------------------------------------- Plan hash value: 3859223164 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 13 | 0 (0)| | |* 1 | FILTER | | | | | | |* 2 | TABLE ACCESS FULL| T3 | 1 | 13 | 2 (0)| 00:00:01 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(NULL IS NOT NULL) 2 - filter("D2"='32-SEP-2010')
I:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_DATE(D2) = N3; TO_DATE(D2) = N3 * ERROR at line 6: ORA-00932: inconsistent datatypes: expected DATE got NUMBER
J:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_DATE(D2) = N3 7 AND TO_CHAR(1)='2'; TO_DATE(D2) = N3 * ERROR at line 6: ORA-00932: inconsistent datatypes: expected DATE got NUMBER
K:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_DATE(D2) = N3 7 AND 1=2; TO_DATE(D2) = N3 * ERROR at line 6: ORA-00932: inconsistent datatypes: expected DATE got NUMBER
L:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 N3 = 'A'; Execution Plan ---------------------------------------------------------- Plan hash value: 4161002650 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 13 | 2 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| T3 | 1 | 13 | 2 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("N3"=TO_NUMBER('A'))
M:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 N3 = '27-SEP-2010'; Execution Plan ---------------------------------------------------------- Plan hash value: 4161002650 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 13 | 2 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| T3 | 1 | 13 | 2 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("N3"=TO_NUMBER('27-SEP-2010'))
N:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 N3 = '32-SEP-2010'; Execution Plan ---------------------------------------------------------- Plan hash value: 4161002650 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 13 | 2 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| T3 | 1 | 13 | 2 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("N3"=TO_NUMBER('32-SEP-2010'))
So, which SQL statements are valid, and which are not? Did you guess correctly? Are you surprised, or still not sure?
How about if we do this just to confirm:
SET AUTOTRACE OFF ALTER SESSION SET TRACEFILE_IDENTIFIER = 'TEST_SQL_OK'; ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT FOREVER, LEVEL 8'; SELECT * FROM T3 WHERE TO_NUMBER(V1)=1; SELECT * FROM T3 WHERE TO_NUMBER(V1)=TO_NUMBER('A'); SELECT * FROM T3 WHERE TO_NUMBER(V1)=1 AND ROWNUM=2; SELECT * FROM T3 WHERE TO_NUMBER(V1)=1 AND 1=2; SELECT * FROM T3 WHERE TO_DATE(D2) = '27-SEP-2010'; SELECT * FROM T3 WHERE TO_DATE(D2) = '32-SEP-2010'; SELECT * FROM T3 WHERE D2 = '32-SEP-2010' AND 1=2; SELECT * FROM T3 WHERE TO_DATE(D2) = N3; SELECT * FROM T3 WHERE TO_DATE(D2) = N3 AND TO_CHAR(1)='2'; SELECT * FROM T3 WHERE TO_DATE(D2) = N3 AND 1=2; SELECT * FROM T3 WHERE N3 = 'A'; SELECT * FROM T3 WHERE N3 = '27-SEP-2010'; SELECT * FROM T3 WHERE N3 = '32-SEP-2010'; ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT OFF';
The output looks like this:
A:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_NUMBER(V1)=1; TO_NUMBER(V1)=1 * ERROR at line 6: ORA-01722: invalid number
B:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_NUMBER(V1)=TO_NUMBER('A'); TO_NUMBER(V1)=TO_NUMBER('A') * ERROR at line 6: ORA-01722: invalid number
C:
SQL> SELECT 2 * 3 FROM 4 T3 WHERE TO_NUMBER(V1)=1 5 AND ROWNUM=2; T3 WHERE TO_NUMBER(V1)=1 * ERROR at line 4: ORA-01722: invalid number
D:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_NUMBER(V1)=1 7 AND 1=2; no rows selected
F:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_DATE(D2) = '27-SEP-2010'; V1 D2 N3 ---------- --------- ---------- A 27-SEP-10 65
G:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_DATE(D2) = '32-SEP-2010'; TO_DATE(D2) = '32-SEP-2010' * ERROR at line 6: ORA-01847: day of month must be between 1 and last day of month
H:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 D2 = '32-SEP-2010' 7 AND 1=2; no rows selected
I:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_DATE(D2) = N3; TO_DATE(D2) = N3 * ERROR at line 6: ORA-00932: inconsistent datatypes: expected DATE got NUMBER
J:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_DATE(D2) = N3 7 AND TO_CHAR(1)='2'; TO_DATE(D2) = N3 * ERROR at line 6: ORA-00932: inconsistent datatypes: expected DATE got NUMBER
K:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 TO_DATE(D2) = N3 7 AND 1=2; TO_DATE(D2) = N3 * ERROR at line 6: ORA-00932: inconsistent datatypes: expected DATE got NUMBER
L:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 N3 = 'A'; N3 = 'A' * ERROR at line 6: ORA-01722: invalid number
M:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 N3 = '27-SEP-2010'; N3 = '27-SEP-2010' * ERROR at line 6: ORA-01722: invalid number
N:
SQL> SELECT 2 * 3 FROM 4 T3 5 WHERE 6 N3 = '32-SEP-2010'; N3 = '32-SEP-2010' * ERROR at line 6: ORA-01722: invalid number
So, which SQL statements are invalid? Last chance.
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
—-
Good idea, let’s take a look inside the 10046 trace file to see if it provides any critical clues:
WAIT #6: nam='SQL*Net message to client' ela= 3 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208311587 WAIT #6: nam='SQL*Net message from client' ela= 409 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208313312 CLOSE #6:c=0,e=0,dep=0,type=1,tim=106208312194 WAIT #0: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208313394 WAIT #0: nam='SQL*Net message from client' ela= 1137 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208314551 ===================== PARSING IN CURSOR #2 len=44 dep=0 uid=185 oct=3 lid=185 tim=106208312194 hv=2056319931 ad='1e367f68' sqlid='94uqsttx91wxv' SELECT * FROM T3 WHERE TO_NUMBER(V1)=1 END OF STMT PARSE #2:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208312194 EXEC #2:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208312194 WAIT #2: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208314830 FETCH #2:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208312194 STAT #2 id=1 cnt=0 pid=0 pos=1 obj=104348 op='TABLE ACCESS FULL T3 (cr=0 pr=0 pw=0 time=0 us cost=2 size=13 card=1)' WAIT #2: nam='SQL*Net break/reset to client' ela= 3 driver id=1413697536 break?=1 p3=0 obj#=-1 tim=106208315213 WAIT #2: nam='SQL*Net break/reset to client' ela= 124 driver id=1413697536 break?=0 p3=0 obj#=-1 tim=106208315356 CLOSE #2:c=0,e=0,dep=0,type=0,tim=106208312194 WAIT #0: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208315926 WAIT #0: nam='SQL*Net message from client' ela= 1229 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208317175 ===================== PARSING IN CURSOR #4 len=57 dep=0 uid=185 oct=3 lid=185 tim=106208312194 hv=4036914934 ad='1e3647e4' sqlid='b34gs4zs9wvrq' SELECT * FROM T3 WHERE TO_NUMBER(V1)=TO_NUMBER('A') END OF STMT PARSE #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208312194 EXEC #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208312194 WAIT #4: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208317422 FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208312194 STAT #4 id=1 cnt=0 pid=0 pos=1 obj=104348 op='TABLE ACCESS FULL T3 (cr=0 pr=0 pw=0 time=0 us cost=2 size=13 card=1)' WAIT #4: nam='SQL*Net break/reset to client' ela= 2 driver id=1413697536 break?=1 p3=0 obj#=-1 tim=106208317617 WAIT #4: nam='SQL*Net break/reset to client' ela= 125 driver id=1413697536 break?=0 p3=0 obj#=-1 tim=106208317761 CLOSE #4:c=0,e=0,dep=0,type=0,tim=106208312194 WAIT #0: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208318310 WAIT #0: nam='SQL*Net message from client' ela= 1084 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208319413 ===================== PARSING IN CURSOR #8 len=57 dep=0 uid=185 oct=3 lid=185 tim=106208312194 hv=3419871603 ad='1e3641f4' sqlid='2g02uyv5xf6bm' SELECT * FROM T3 WHERE TO_NUMBER(V1)=1 AND ROWNUM=2 END OF STMT PARSE #8:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1538339754,tim=106208312194 EXEC #8:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1538339754,tim=106208312194 WAIT #8: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208319705 FETCH #8:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=0,dep=0,og=1,plh=1538339754,tim=106208312194 STAT #8 id=1 cnt=0 pid=0 pos=1 obj=0 op='COUNT (cr=0 pr=0 pw=0 time=0 us)' STAT #8 id=2 cnt=0 pid=1 pos=1 obj=0 op='FILTER (cr=0 pr=0 pw=0 time=0 us)' STAT #8 id=3 cnt=0 pid=2 pos=1 obj=104348 op='TABLE ACCESS FULL T3 (cr=0 pr=0 pw=0 time=0 us cost=2 size=13 card=1)' WAIT #8: nam='SQL*Net break/reset to client' ela= 2 driver id=1413697536 break?=1 p3=0 obj#=-1 tim=106208319939 WAIT #8: nam='SQL*Net break/reset to client' ela= 112 driver id=1413697536 break?=0 p3=0 obj#=-1 tim=106208320070 CLOSE #8:c=0,e=0,dep=0,type=0,tim=106208312194 WAIT #0: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208320807 WAIT #0: nam='SQL*Net message from client' ela= 1240 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208322066 ===================== PARSING IN CURSOR #3 len=54 dep=0 uid=185 oct=3 lid=185 tim=106208312194 hv=1521821591 ad='1e363c04' sqlid='3ty5saddba9wr' SELECT * FROM T3 WHERE TO_NUMBER(V1)=1 AND 1=2 END OF STMT PARSE #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=3859223164,tim=106208312194 EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=3859223164,tim=106208312194 WAIT #3: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208322296 FETCH #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=3859223164,tim=106208312194 STAT #3 id=1 cnt=0 pid=0 pos=1 obj=0 op='FILTER (cr=0 pr=0 pw=0 time=0 us)' STAT #3 id=2 cnt=0 pid=1 pos=1 obj=104348 op='TABLE ACCESS FULL T3 (cr=0 pr=0 pw=0 time=0 us cost=2 size=13 card=1)' WAIT #3: nam='SQL*Net message from client' ela= 366 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208322774 CLOSE #3:c=0,e=0,dep=0,type=1,tim=106208312194 WAIT #0: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208322830 WAIT #0: nam='SQL*Net message from client' ela= 1249 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208324098 ===================== PARSING IN CURSOR #2 len=56 dep=0 uid=185 oct=3 lid=185 tim=106208312194 hv=1963953631 ad='1e3634ec' sqlid='du7hngjuhz3fz' SELECT * FROM T3 WHERE TO_DATE(D2) = '27-SEP-2010' END OF STMT PARSE #2:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208312194 EXEC #2:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208312194 WAIT #2: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208326129 FETCH #2:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=0,og=1,plh=4161002650,tim=106208312194 WAIT #2: nam='SQL*Net message from client' ela= 182 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208326423 FETCH #2:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208312194 STAT #2 id=1 cnt=1 pid=0 pos=1 obj=104348 op='TABLE ACCESS FULL T3 (cr=7 pr=0 pw=0 time=0 us cost=2 size=13 card=1)' WAIT #2: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208326523 WAIT #2: nam='SQL*Net message from client' ela= 411 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208327021 CLOSE #2:c=0,e=0,dep=0,type=0,tim=106208312194 WAIT #0: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208327083 WAIT #0: nam='SQL*Net message from client' ela= 28084 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208355185 ===================== PARSING IN CURSOR #4 len=56 dep=0 uid=185 oct=3 lid=185 tim=106208339668 hv=1226802804 ad='1e362dd4' sqlid='1hqqd0x4jz1mn' SELECT * FROM T3 WHERE TO_DATE(D2) = '32-SEP-2010' END OF STMT PARSE #4:c=15625,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208339668 EXEC #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208339668 WAIT #4: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208355455 FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208339668 STAT #4 id=1 cnt=0 pid=0 pos=1 obj=104348 op='TABLE ACCESS FULL T3 (cr=0 pr=0 pw=0 time=0 us cost=2 size=13 card=1)' WAIT #4: nam='SQL*Net break/reset to client' ela= 2 driver id=1413697536 break?=1 p3=0 obj#=-1 tim=106208355669 WAIT #4: nam='SQL*Net break/reset to client' ela= 134 driver id=1413697536 break?=0 p3=0 obj#=-1 tim=106208355822 CLOSE #4:c=0,e=0,dep=0,type=0,tim=106208339668 WAIT #0: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208356681 WAIT #0: nam='SQL*Net message from client' ela= 1259 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208357960 ===================== PARSING IN CURSOR #8 len=57 dep=0 uid=185 oct=3 lid=185 tim=106208339668 hv=2831431159 ad='1e3627e4' sqlid='3u7tx3knc8dgr' SELECT * FROM T3 WHERE D2 = '32-SEP-2010' AND 1=2 END OF STMT PARSE #8:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=3859223164,tim=106208339668 EXEC #8:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=3859223164,tim=106208339668 WAIT #8: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208358205 FETCH #8:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=3859223164,tim=106208339668 STAT #8 id=1 cnt=0 pid=0 pos=1 obj=0 op='FILTER (cr=0 pr=0 pw=0 time=0 us)' STAT #8 id=2 cnt=0 pid=1 pos=1 obj=104348 op='TABLE ACCESS FULL T3 (cr=0 pr=0 pw=0 time=0 us cost=2 size=13 card=1)' WAIT #8: nam='SQL*Net message from client' ela= 439 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208358756 CLOSE #8:c=0,e=0,dep=0,type=0,tim=106208339668 WAIT #0: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208358815 WAIT #0: nam='SQL*Net message from client' ela= 1489 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208360322 WAIT #3: nam='SQL*Net break/reset to client' ela= 5 driver id=1413697536 break?=1 p3=0 obj#=-1 tim=106208363231 WAIT #3: nam='SQL*Net break/reset to client' ela= 133 driver id=1413697536 break?=0 p3=0 obj#=-1 tim=106208363398 WAIT #3: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208363421 WAIT #3: nam='SQL*Net message from client' ela= 701 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208364163 CLOSE #3:c=0,e=0,dep=0,type=0,tim=106208339668 WAIT #0: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208364233 WAIT #0: nam='SQL*Net message from client' ela= 1322 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208365574 WAIT #6: nam='SQL*Net break/reset to client' ela= 3 driver id=1413697536 break?=1 p3=0 obj#=-1 tim=106208366129 WAIT #6: nam='SQL*Net break/reset to client' ela= 126 driver id=1413697536 break?=0 p3=0 obj#=-1 tim=106208366285 WAIT #6: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208366308 WAIT #6: nam='SQL*Net message from client' ela= 679 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208367019 CLOSE #6:c=0,e=0,dep=0,type=0,tim=106208339668 WAIT #0: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208367086 WAIT #0: nam='SQL*Net message from client' ela= 1229 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208368340 WAIT #2: nam='SQL*Net break/reset to client' ela= 4 driver id=1413697536 break?=1 p3=0 obj#=-1 tim=106208368838 WAIT #2: nam='SQL*Net break/reset to client' ela= 122 driver id=1413697536 break?=0 p3=0 obj#=-1 tim=106208368989 WAIT #2: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208369011 WAIT #2: nam='SQL*Net message from client' ela= 679 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208369721 CLOSE #2:c=0,e=0,dep=0,type=0,tim=106208339668 WAIT #0: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208369786 WAIT #0: nam='SQL*Net message from client' ela= 1010 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208370816 ===================== PARSING IN CURSOR #4 len=37 dep=0 uid=185 oct=3 lid=185 tim=106208339668 hv=1569184524 ad='1e361d0c' sqlid='54544w5fsgqsc' SELECT * FROM T3 WHERE N3 = 'A' END OF STMT PARSE #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208339668 EXEC #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208370919 WAIT #4: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208371121 FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208370919 STAT #4 id=1 cnt=0 pid=0 pos=1 obj=104348 op='TABLE ACCESS FULL T3 (cr=0 pr=0 pw=0 time=0 us cost=2 size=13 card=1)' WAIT #4: nam='SQL*Net break/reset to client' ela= 2 driver id=1413697536 break?=1 p3=0 obj#=-1 tim=106208371337 WAIT #4: nam='SQL*Net break/reset to client' ela= 108 driver id=1413697536 break?=0 p3=0 obj#=-1 tim=106208371463 CLOSE #4:c=0,e=0,dep=0,type=0,tim=106208370919 WAIT #0: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208372094 WAIT #0: nam='SQL*Net message from client' ela= 1072 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208373186 ===================== PARSING IN CURSOR #8 len=47 dep=0 uid=185 oct=3 lid=185 tim=106208370919 hv=2630877256 ad='1e36173c' sqlid='5xks2pufd0028' SELECT * FROM T3 WHERE N3 = '27-SEP-2010' END OF STMT PARSE #8:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208370919 EXEC #8:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208370919 WAIT #8: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208373423 FETCH #8:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208370919 STAT #8 id=1 cnt=0 pid=0 pos=1 obj=104348 op='TABLE ACCESS FULL T3 (cr=0 pr=0 pw=0 time=0 us cost=2 size=13 card=1)' WAIT #8: nam='SQL*Net break/reset to client' ela= 2 driver id=1413697536 break?=1 p3=0 obj#=-1 tim=106208373612 WAIT #8: nam='SQL*Net break/reset to client' ela= 102 driver id=1413697536 break?=0 p3=0 obj#=-1 tim=106208373732 CLOSE #8:c=0,e=0,dep=0,type=0,tim=106208370919 WAIT #0: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208374372 WAIT #0: nam='SQL*Net message from client' ela= 1083 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208375474 ===================== PARSING IN CURSOR #3 len=47 dep=0 uid=185 oct=3 lid=185 tim=106208370919 hv=1567527007 ad='1e36116c' sqlid='c5w7qdxfqx42z' SELECT * FROM T3 WHERE N3 = '32-SEP-2010' END OF STMT PARSE #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208370919 EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208370919 WAIT #3: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208375702 FETCH #3:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=0,dep=0,og=1,plh=4161002650,tim=106208370919 STAT #3 id=1 cnt=0 pid=0 pos=1 obj=104348 op='TABLE ACCESS FULL T3 (cr=0 pr=0 pw=0 time=0 us cost=2 size=13 card=1)' WAIT #3: nam='SQL*Net break/reset to client' ela= 2 driver id=1413697536 break?=1 p3=0 obj#=-1 tim=106208375886 WAIT #3: nam='SQL*Net break/reset to client' ela= 102 driver id=1413697536 break?=0 p3=0 obj#=-1 tim=106208376006 CLOSE #3:c=0,e=0,dep=0,type=0,tim=106208370919 WAIT #0: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208376714 WAIT #0: nam='SQL*Net message from client' ela= 719 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=106208377453 PARSE #6:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,plh=0,tim=106208370919 EXEC #6:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,plh=0,tim=106208370919
It is a little painful that not even the PARSE call for some of the SQL statements completed, therefore the SQL statement is not written to the 10046 trace file.
Maybe I should have clarified what I was asking for? When we say that a SQL statement is invalid, do we mean:
- It generates an error message when it is executed.
- It generates an error message when it is parsed.
- It generates no error message, yet is logically invalid due to impossible values: 1=2 ; September 32, 2010 ; TO_NUMBER(‘A’)
- Something else?
From mine point of view a-“It generates an error message when it is executed.”
Look for automatic casting (string is multiplying a number):
SQL> select ‘0.18’ * 10 from dual;
‘0.18’*10
———-
1.8
SQL>
Result is number and correct one.
Rg,
Damir
I’m not sure if you really ask for invalid? At the other end of the discussion I would say ‘do not expect anything, be clear what you want’. Therefore no implicit castings etc.
e.g. your tests with any date in string format will fail in my env as I use ‘YYYY-MM-DD HH24:MI’ as default format.
I would therefore suggest ‘be precise in what you want’.
This will limit the case, when it ‘does not act as expected at the time written’. (and this is my definition of ‘invalid’!)
Yes, of course this will not save against ‘logically invalid’ situations. But are they expected? 😉
To be honest, I did not pass ‘TO_DATE(D2) = N3’.
Martin,
I was very much hoping that someone would argue that the implicit casting of the VARCHAR to DATE makes that SQL statement invalid (I agree). That reminds me of a comment that I made in this book review: https://hoopercharles.wordpress.com/2010/06/06/book-review-oracle-sql-recipes-a-problem-solution-approach/
Invalid in this sense is that the SQL statement might not generate an error when being parsed, might not generate an error when being executed, and is logically valid – but only in the environment where the SQL statement is executed. As you stated, all that it takes is a change in the default date format.
It could be argued that the example provided by Damir should also fail because a VARCHAR cannot be multiplied by a number, yet changing that behavior would break programs that incorrectly define numeric bind variables as VARCHAR2, and probably cause problems for EXPLAIN PLAN when SQL statements are submitted with bind variables.
I am not sure that I understand your comment about “TO_DATE(D2) = N3” – if you are saying that I cannot explicitly convert a value that is already a DATE into a DATE value, and then compare that value to a number, I say why not? Simple algebra: 🙂
The result of subtracting a number from a date is… if we assume N3 is 65:
But then we reach a problem: September 27 is not equal to 0, unless 1 is equal to 2 (https://hoopercharles.wordpress.com/2009/12/25/proving-that-12-is-oracle-wrong-to-short-circuit-an-execution-plan/). OK, enough joking.
Actually, I saw a couple of recent threads on the OTN forums that included SQL statements with silly syntax like TO_DATE(D2) – that mistake really causes problems for the optimizer’s cardinality estimates. Therefore, it *could* be argued that the SQL statement with “TO_DATE(D2) = ’27-SEP-2010′” in the WHERE clause is invalid not just because of the implicit data type conversion, but also because of the affect on the cardinality estimates that are produced by the cost based optimizer.
An alternative definition of ‘invalid’ is whether it can be included as a static SQL statement in a PL/SQL stored procedure.
That doesn’t mean it can be parsed though, let alone executed. I blogged an example of that with GROUP BY here : http://blog.sydoracle.com/2010/10/fun-with-group-by.html
VPD can also come into play. A statement might be valid when executed with one policy but not with another.
I prefer to be guided by whether a statement is correct or not, with correctness being defined as always producing the desired result. The desired result MIGHT be an exception (and in the PL/SQL world that might be NO_DATA_FOUND or TOO_MANY_ROWS)
I followed the other arguments here also.
Based on these, and some more thinking about it, I’d like the PARSE as the separator.
My idea behind is this: use all your statements with bin variables – therefore you do not know anything about their values at parsing time (well, sometimes you can. but I also can explicit parse a statement without any bind variables provided).
If it is correct, everything which passes this line is not an invalid statement anymore but invalid data?
(in set theory we could argue this tuple of bind variables provided to the statement is not part of the set, (so it is ‘invalid’) and there is no need for the statement to execute this tuple anyhow).
A little bit philosophical now …
Gary and Martin,
Thank you for your points of view on this topic. I was waiting to see if anyone else had an opinion to offer.
Martin, I was close to suggesting that another example of an “invalid” SQL statement is a SQL statement that is written in such a manner that it causes poor performance – that is only a small step away from, “Therefore, it *could* be argued that the SQL statement with “TO_DATE(D2) = ’27-SEP-2010′” in the WHERE clause is invalid not just because of the implicit data type conversion, but also because of the affect on the cardinality estimates that are produced by the cost based optimizer.” I follow your line of thought.
Gary, VPD is something that was completely off my radar. What about relying on public synonyms and the possiblity that an object will exist in the user’s schema with the same object name? Such a situation might make a SQL statement appear to be invalid for only a single user. Yet, if the schema name is prefixed to table names, that could limit the DBA’s ability to consolidate data from multiple databases into a single database with the help of multiple schemas (as would public synonyms I suppose).
What do you say about a statement which throws an ORA-31603 without a hint, but works fine with a hint? My example: http://berxblog.blogspot.com/2010/12/invalid-sql-if-hint-is-missing.html
Martin,
Your test SQL statement work OK on 64 bit Windows 11.2.0.1. However, there is something odd about your output that I was also able to reproduce. Take a look at the following blog article:
https://hoopercharles.wordpress.com/2009/12/09/failure-to-collect-fixed-object-statistics-leads-to-ora-01013-or-ora-07445/
That blog article suggests to execute the following SQL statement to verify that the fixed object statistics were collected:
When I executed the above, the SQL statement returned no rows. We will come back to this in a minute.
The AUTOTRACE execution plans that I received are as follows:
My database can not only parse the unhinted and the hinted SQL statement, but it can also execute it. Note that the “Predicate Information” section is printed just below the execution plan – the same result that you received.
Now, let’s go back to the problem where I somehow forgot to collect fixed object statistics:
Now to collect the fixed object statistics and re-check the above SQL statement:
Now the SELECT produces 798 rows. Let’s retry the SQL statement (actually executing it) with a 10053 trace enabled:
Note that the “Predicate Information” section is NO LONGER printed just below the execution plan. The same changed behavior is also seen with AUTOTRACE.
From the 10053 trace file, the unhinted query after all transformations:
A Google search for ORA-31603 (mostly items found on forums.oracle.com) seems to point to a permissions problem when the error appears with dbms_metadata.get_ddl, but that should not be the case for you if you are executing the query as the SYS (internal) user.
Charles,
I tried to crosscheck on my system.
1st, I have also 798 rows in SYS.TAB_STATS$. So I assume I have no issues with the statistics?
2nd my unhinted select statement has the same Plan hash value: 739349040. I assume this is enough to say, they are the same.
The 10053 trace is uploaded here https://docs.google.com/leaf?id=0B6c1gsEhfcN1MGMxMWUxYTAtYTkzMS00Y2U1LWFjNjEtZTBkMGE5NzJiMmU0&sort=name&layout=list&num=50
Also there the Final query after transformations looks quite similar to me. I have some guesses right now (du you have a user PSFT with a set of views?) but they are not elaborated.
Maybe I manage to simplify the testcase, probably with generated tables to make it more digestive.
Martin
Martin,
I checked both Linux and Window 11.2.0.1, as well as a freshly created template database that was created by the DBCA – that user does not exist in any of the databases. I had not considered that as a possible problem area, so I repeated the test when connected as the SYS user with a slightly modified version of the SQL statement that you provided:
The AUTOTRACE execution plan for this SQL statement (on 11.2.0.1 Windows 64 bit) looks like this:
I executed the SQL statement with AUTOTRACE turned off, and after a couple of minutes the following appeared:
For some reason, I am not able to access the 10053 trace file that you shared –
youdo you need to specify permissions so that I am able to access that file? If you leave off the WHERE clause, do you receive the same number of rows from the hinted and unhinted versions of your query?Are you able to execute my modified version of the SQL statement?
I tried to lower the permissions on the google doc document as good as I could. but it seems a login is still required. To lower these barriers, I put the file at http://berx.at/traces/PSCRT022_ora_22249_ERROR_SQL.trc .
You will not find the user PSFT in any general Oracle DB. My particular DB was populated with exp/imp from a 9i Peoplesoft database.
Your modified version of the SQL-statement provided this AUTOTRACE:
Running ‘my’ SQL (owner=PSFT) witout the outer WHERE gibes me 8802 rows back in any case.
(and I did a quickcheck with AUTOTRACE, they generated different execution plans).
I’m quite sure I did not manipulate the data dictionary (as there are also other DBAs I can not be 100% sure on this kind of test/sandbox system).
(edited to remove tabs from the execution plan to improve readability)
Hi Charles,
Some hours without a keyboard but with my children made my brain working again. So I changed the way I attack my problem:
Based on the Final query after transformations here the part of interest:
The dba_views.owner and dba_views.view_name does NOT come from one table, but from a join of OBJ$ and SYS.USER$ (and some others). To get this tupel, Oracle joins USER$ (after the filter for NAME via I_USER1) with I_OBJ5. In this join (access(“O”.”SPARE3″=”U”.”USER#”)) at the same time it has all informations it needs to apply this filter also: filter(“DBMS_METADATA”.”GET_DDL”(‘VIEW’,”O”.”NAME”,”U”.”NAME”) LIKE ‘%TEST%’)
But the filter, if the data returned from I_OBJ5 is really a View (access(“O”.”OBJ#”=”V”.”OBJ#”)) is done later.
There is nothing bad about this action, only DBMS_METADATA.GET_DDL returns an error if the object named by 2nd and 3rd parameter does not match the 1st.
In my case it tries to provide the DDL for “SYS”.”/1000323d_DelegateInvocationHa” (which is a java related object) and fails.
Are my observations correct?
Martin
It is interesting to note that the hash value for your plan matches the hash value that I received on 11.2.0.1 on 64 bit Linux, but the hash value for the plan does NOT match the hash value that I received on 11.2.0.1 on 64 bit Windows. With that in mind, what happens when I run the following script on 11.2.0.1 on 64 bit Linux?
This is what I received:
That error message seems to match what you received, which suggests that this is a bug in the 11.2.0.1 Linux release which was fixed before the 11.2.0.1 Windows release (I think that the Windows release was launched 3 or 4 months later).
Here is the final query after transformation from 11.2.0.1 Linux:
Here is the execution plan from the 10053 trace file:
It might be worthwhile to search through Metalink to see if there is a one-off patch for Linux that corrects this specific problem, or investigate if it is possible to upgrade to 11.2.0.2. This is certainly an interesting problem.
I am a bit unsure what happened. Now when I execute this script in 11.2.0.1 on 64 bit Windows I receive the same error that I saw on Linux:
Last night when I excuted this same SQL statement it retrieved 20 rows. This is the plan that I am currently receiving with AUTOTRACE enabled:
There is only one mention of object “/1000323d_DelegateInvocationHa” on Metalink, in this article:
“Bug 6964025: Exceptions while trying to configure JDBC Connection Validation in GF 3.0.1”
Checking DBA_OBJECTS, I see that “/1000323d_DelegateInvocationHa” is a Java class that is owned by the SYS user, and is also a public synonym – it should have been eliminated due to the o.object_type=’VIEW’ predicate in the WHERE clause. The problem is that the o.object_type=’VIEW’ predicate is not applied until execution plan ID 21, which in the unhinted plan is executed after the call to DBMS_METADATA.GET_DDL on line 8 of the execution plan – not all objects in the database are views, and not all objects are owned by one user.
What you might be able to do is something like this:
In the above, I added the OBJECT_TYPE column to the list of columns retrieved by the inline view, and then passed that column into the DBMS_METADATA.GET_DDL call. That change allowed the SQL statement to complete – return 20 rows. Now the final query after transformation is this:
This is an AUTOTRACE version of the execution plan:
I still do not know why I was able to excute my test SQL statement last night without problem, but cannot execute it today – I thought that computer software was supposed to be logically consistent. 🙂 (Maybe I should spend some more time looking at the execution plans.)
Hmm, I do not have Oracle@Windows available anywhere around, so I tested some of the versions here.
To keep it simpler I used this test-statement:
select
owner,
view_name
from
(select
v.owner, v.view_name
from
dba_views v
where
v.owner =’SYS’ ) vv
where
dbms_metadata.get_ddl(‘VIEW’, vv.view_name, vv.owner) like ‘%TEST%’;
I tested 11.2.0.2 @ Linux 64bit, 11.2.0.1 @ Linux 64bit, 11.1.0.7 @ Solaris 64bit, 10.2.0.4 @ Solaris 64bit, 9.2.0.8 @ Solaris 64bit.
I found this errorstack everywhere. (To not spam this Reply, I put the results into http://berx.at/traces/sql_20110101.txt ).
From my point of view Windows is the alien 😉
Do you have any posibility to croscheck with other Versions/OS?
Martin
Martin,
Good news (or maybe bad news). Today 11.2.0.1 on Windows is now giving me the same error message as on Linux – see my previous two comments.
I only spent a couple of minutes reviewing the execution plan where the SQL statement fails to execute. However, in one of my previous comments I mentioned that the execution plan indicated that Oracle was processing this line in the execution plan on plan ID line 8:
That was processed *before* it filtered the list of objects to eliminate everything that was not a VIEW (that was on plan ID line 21). The owner is filtered on plan ID lines 7, 19 and 31, so line 7 should have been able to restrict the objects to just those owned by SYS when line 8 of the execution plan was executed through a nested loops join. Please try the *fixed* version of the SQL statement that I provided to you:
Here is the 10053 trace file of the latest statement (from my ‘original’ DB): http://berx.at/traces/PSCRT021_ora_11954_TEST_SYS2.trc
Do you agree it’s a problem of the function dbms_metadata.get_ddl() in case it gets some parameter combinations it does not expect?
To come back to the topic of this blog: what’s ‘invalid’ here? I don’t think we can blame the optimizer for that, can we?
There might be some ways to circumvent it: you show one, but this still can fail if the optimizer decides to push the filter too ‘deep’.
My ‘no_merge’ hint will also prevent this behavior. But I’d expect a SQL to return the same values (and fail the same way) regardless of any hint?
Oracle could also associate some extended statistics to the function dbms_stats.get_ddl to make it so ‘expensive’ to the optimizer, the optimizer would always try to elaborate the smallest result-set possible before apply the ‘expensive’ get_ddl function to the ‘totally elaborated’ sub-result.
What do you think?
Is there anything we can dwell deeper?
(I’d like to play ma preferred support-game *g*)
Martin,
It would be interesting to see if my modified version of your query could still fail to execute (I do not know the answer).
From looking at the execution plan, I am note sure that this would be called a bug – at least not a bug with DBMS_METADATA.GET_DDL.
Consider this example. Assume that there are three (and only three) objects in a schema:
You then code a PL/SQL function (maybe someone more skilled with PL/SQL than me can code an example) with a couple of IN parameters. If the word ‘VIEW’ is passed in as a parameter, the PL/SQL function takes one code path, maybe it selects all rows from the view. If the word ‘INDEX’ is passed in as a parameter, the PL/SQL function takes a different code path, maybe selecting a list of columns that are in the index definition. If you then code error checking into the PL/SQL function so that it returns an error message when the user submits an impossible combination (‘VIEW’ and ‘T1_TEST_C1_IND’, for example), that is probably considered good programming practice – possibly better than returning a NULL or random garbage.
I believe that the above is what is happening in your SQL statement. DBA_VIEWS and DBA_OBJECTS are not simple tables, but instead are complex views that are built from several underlying objects. Through an unfortunate optimization, the optimizer has decided to pass the object names through the PL/SQL function (DBMS_METADATA.GET_DDL in your case) before that object list is reduced to just include the list of object names that *are* views.
See if the following will work – it worked OK for me on 11.2.0.1 (64 bit Windows), although it was slow:
Just tested on 11.2.0.1 64 bit Linux, and it also works there:
I (re-)tested both of your statements – both worked fine.
I assume our observations are now quite consistent. My initial goal to find what’s going on there is met.
You raised a good question about good programming practice. Basically dbms_metadata.get_ddl is supposed to be used in the SELECT part of a query, my utilisation as a filter is quite un-common. So should the (any) function be coded to fulfill the designed situation (and throw an error if anything is wrong) of should it stay any situation where it can be used? Quite a nice question about programming principles.
Martin,
I made some poor assumptions yesterday when Oracle on Windows was able to execute my test SQL statement and Linux could not execute the test SQL statement – it must be a year 2011 problem because Oracle on Windows cannot execute the test SQL statement today either. 🙂
I did not spend as much time looking at the execution plan that you provided as I should have, instead I wasted time heading in other directions trying to determine why the test SQL statement seemed to work in some cases and not in other cases.
I think that the reason why your SQL statement which had a plan hash value of 739349040 failed is simply because a hash join was performed on plan ID line 4 of the execution plan, rather than a nested loops join. That hash join is what joins the DBA_OBJECTS view to the DBMS_METADATA.GET_DDL function that is on plan ID line 30 of the execution plan – I think that a nested loops join here would have been able to provide the list of objects (drive into the second object) that were SYS owned views, while a hash join is supposed to fully scan the second object listed in the hash join.
In earlier testing, if I did not specify the /*+ NO_QUERY_TRANSFORMATION */ hint in my modified query, it would fail with the same error message that we encountered earlier.
This was an interesting exercise, and I agree with your comments.
This was very illuminating.
I surmise the bug is in Oracle instrumentation – if it is going to be doing overly helpful stuff transforming deep under the covers, it needs to be better about informing what problem it hit. I don’t see at all why using a supplied package as a filter would be bad programming practice. I’d think it would be good programming practice.
But then again, that makes iffy assumptions about how well engineered and documented supplied packages are.