|
长话短说,我建议讨论您在下面看到的代码。3 R# ?5 b% o* E6 P- S
运行时:
* x" F) X* D/ |9 jOracle 11编译器提高 7 p( t! A. l8 Z4 L X+ [
8 x5 F' l @- Z; a8 Q8 Z9 K
: l8 k; ?4 Y* _6 ]. n; G
“ PLS-00306:调用“ PIPE_TABLE”时出现错误的数量或类型的参数提示”
5 h& }5 r1 B6 n1 C* o- j- d“ PLS-00642:SQL语句中不允许使用本地集合类型”' F( i' e# ~5 K0 f$ p
' S1 ] B. `0 m8 s) ^Oracle 12编译以下软件包时没有出现此类警告,但我们对运行时感到惊讶
+ H8 h0 r1 A- }: G3 t8 z6 f3 @$ w- y* ^4 x
5 a! N* u7 k( ~, t6 Y+ `8 L" Q+ i当按原样执行匿名块时-一切都很好(我们可以在pipe_table函数中传递一些行-不会影响)
2 m; A- p+ f; o( {! x8 z现在,让我们取消注释行hello;或对任何过程进行调用,然后再次运行更改的匿名块,我们将得到“ ORA-22163:左手和右手边的集合不是同一类型”
5 k: v1 Y5 V* b `6 h: \4 g/ W3 ]1 Y" f/ J( Q, d
问题是:Oracle 12是否允许SQL中的本地集合类型?如果是,那么代码有PACKAGE buggy_report什么问题?8 H' Z: W+ Y* N1 _
CREATE OR REPLACE PACKAGE buggy_report IS
7 `' u/ K) D9 K# k' v- { SUBTYPE t_id IS NUMBER(10);# |) A. L( H5 H8 G) G/ ?: H$ z1 A+ P" P
TYPE t_id_table IS TABLE OF t_id;
# c" s4 G4 t1 N+ F7 [ TYPE t_info_rec IS RECORD ( first NUMBER );
0 Q$ x0 N, ^) g TYPE t_info_table IS TABLE OF t_info_rec;- y5 v/ A9 Z/ S" k9 \% {
TYPE t_info_cur IS REF CURSOR RETURN t_info_rec;4 _, \4 h) { J+ [3 l$ h
FUNCTION pipe_table(p t_id_table) RETURN t_info_table PIPELINED;
3 I) w* _8 V2 d4 k' Y FUNCTION get_cursor RETURN t_info_cur;- `. \- Y: p5 T; J, U
END buggy_report;
% J$ B5 R6 I+ t7 T- p, i0 E% n/$ ?% e' c) u0 r2 ], ]" j, S' \$ i
CREATE OR REPLACE PACKAGE BODY buggy_report IS6 I" h6 K3 M% d) L4 H0 X
FUNCTION pipe_table(p t_id_table) RETURN t_info_table PIPELINED IS: k, y- o9 z: {/ @0 p: f
l_table t_id_table;
' E+ v1 G. h. E2 K5 L; ]# j1 [# h BEGIN
# g2 j) Y' K8 L l_table := p;
& v' E( F' U' ~& I6 p0 Y. V" B END;) F7 l+ P9 R* z- N) E n; k7 a7 Y
FUNCTION get_cursor RETURN t_info_cur IS! Q2 z' x: n+ X4 G# s8 z8 `( Z* E$ N
l_table t_id_table;7 ], b" n/ Y4 v" A6 r
l_result t_info_cur;
, F- F5 A' Z- o6 u7 n: u& ~ j BEGIN
! H( E) d' B; b9 M0 s: M2 h/ ~; l5 X$ z OPEN l_result FOR SELECT * FROM TABLE (buggy_report.pipe_table(l_table));2 l* t, T) m8 O; T
RETURN l_result;
, _, f: E3 c: d; ~7 `9 B9 T0 o END;3 T; f4 v7 M3 |1 l7 m! K+ U
END;
3 ]& s5 u6 r( k Y% Z/
$ C9 E. ^0 [9 [4 NDECLARE
3 q1 B' D) o3 Z- j, K l_cur buggy_report.t_info_cur;' V; f$ [4 J! u* L# c
l_rec l_cur%ROWTYPE;
/ ^; Z6 Y. Q, _9 n$ d PROCEDURE hello IS BEGIN NULL; END;
6 N* R( Y% m8 rBEGIN
. N. L9 N7 t$ t7 H l_cur := buggy_report.get_cursor();
( M& O+ y1 H. a5 I, t8 B -- hello;; t5 e+ k p2 F( z1 h
LOOP
8 f3 i* N( n1 y# V$ W3 J. { FETCH l_cur INTO l_rec;
# T& f) Q2 k V9 a* G3 x' R EXIT WHEN l_cur%NOTFOUND;
5 z9 Z- Y. S% \* y4 N END LOOP;
. V0 ~4 I, d( h$ e9 I. T2 r CLOSE l_cur;
[4 h; G; d1 @2 t1 H dbms_output.put_line('success');. N6 \3 ?- i+ ], o/ H
END;9 p+ w3 U' r* m! ?$ b$ `) w K
/$ Y/ k( R& Y. G: y- P% ]0 Y1 O
( l9 I# B9 E6 S* q4 X0 D5 r, U解决方案:$ I3 R# Y# H V4 G3 C
* C6 H, d7 t0 ^$ F' J( t
4 N! n6 z( q" Q- j2 j& t- ~) e" t# O0 Y5 K- \* F$ Q+ b9 _
在进一步的实验中,我们发现问题甚至比想象的要深。+ }: Q: d# R" P2 J1 ^* D; N
例如,在包中使用不同的元素时,buggy_report我们可以ORA-03113: end-of-file on communication
: F5 @" q& g/ R0 H/ a" Jchannel 在运行脚本时获得一个(问题中)。可以通过更改t_id_tabletoVARRAY或类型来实现TABLE .. INDEX BY9 S0 ?, ^! G3 n8 k. d; |
..。有很多方法和变型将我们引向不同的例外,而这些例外与本文无关。
6 w+ F: r+ C- t! X6 \( m& f+ X一件更有趣的事情是,buggy_report软件包规范的编译时间最多可能需要25秒,而通常情况下大约需要0.05秒。我可以肯定地说,这取决于函数声明中TYPE* z! n5 O3 n2 x k( |. K# u( N
t_id_table参数的存在,pipe_table在40%的安装案例中都会发生“长时间编译”。因此,似乎local collection
& x! m: F/ s/ V+ A9 W$ P0 utypes in SQL在编译过程中潜在地出现了问题。
4 O2 H/ l* i8 l/ E因此,我们看到Oracle 12.1.0.2在实现在SQL中使用本地集合类型时显然存在一个错误。
6 o0 S. t3 E; v最小的例子让ORA-22163和ORA-03113跟随。在那里,我们假设与buggy_report问题中的软件包相同。
) @5 O% u+ r$ u! a& z* \4 j-- produces 'ORA-03113: end-of-file on communication channel'
! b) A% e' b8 g% E* q8 S6 d/ o% C" fDECLARE 4 e/ Q, @5 ] T6 \0 A" C
l_cur buggy_report.t_info_cur;6 {" Y+ e4 H1 {: _ D% g, c/ i5 a
FUNCTION get_it RETURN buggy_report.t_info_cur IS BEGIN RETURN buggy_report.get_cursor(); END;
8 W* \: G! c5 s8 C' p7 iBEGIN
: I1 f, R1 @) }/ a l_cur := get_it();
% v' p6 o+ \9 L( L( n dbms_output.put_line('');* L1 D: Z8 K8 H; a
END;
]0 a6 X* a$ m! q; z; E' i* {/
# ^4 F+ i3 E/ X5 l. V-- produces 'ORA-22163: left hand and right hand side collections are not of same type'. g/ Q: L$ N4 ?8 I" p1 z) ^' o
DECLARE
: n2 Z3 O5 n3 W& L3 u l_cur buggy_report.t_info_cur;
* w4 X H) `, c) ]/ h PROCEDURE hello IS BEGIN NULL; END;1 T" S) f1 {# x( d, S% n- B
BEGIN
5 `4 ` `% ]4 h, g5 o" R l_cur := buggy_report.get_cursor;
( r, W# s K+ H6 J9 c -- comment `hello` and exception disappears
# M% M: a- _( b r& A5 j hello;
, d2 |+ D% Y: Q; l CLOSE l_cur;5 j1 @1 c- S% _( H; k0 C7 p* e
END;
3 {2 n9 C) V( Q: m1 n. Q/ |
|