回答

收藏

Oracle 12在SQL中的本地集合类型上是否有问题?

技术问答 技术问答 273 人阅读 | 0 人回复 | 2023-09-14

长话短说,我建议讨论您在下面看到的代码。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 z
6 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/
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则