From f5342514be51ef6242b31fccf7bbccb33bb432b8 Mon Sep 17 00:00:00 2001 From: alexeyvo Date: Wed, 10 Aug 2016 17:59:11 +0300 Subject: [PATCH] Initial commit --- ADDRESS.java | 94 + AQDemoServlet.java | 127 ++ AQHttp.java | 275 +++ AQHttpRq.java | 102 ++ AQPropServlet.java | 100 ++ Cars.java | 119 ++ Emp.java | 122 ++ MesgListener.java | 68 + Message.java | 95 + PERSON.java | 99 ++ aadvdemo.sql | 1602 +++++++++++++++++ anydata.sql | 317 ++++ anydset.sql | 246 +++ anytype.sql | 421 +++++ aqbzdemo.tar | Bin 0 -> 72704 bytes aqdemo00.sql | 216 +++ aqdemo01.sql | 374 ++++ aqdemo02.sql | 84 + aqdemo03.sql | 117 ++ aqdemo04.sql | 40 + aqdemo05.sql | 89 + aqdemo06.sql | 73 + aqdemo07.sql | 246 +++ aqdemo08.sql | 575 ++++++ aqdemo09.sql | 147 ++ aqdemo10.sql | 83 + aqdemo11.sql | 65 + aqdemo12.sql | 54 + aqjmsREADME.txt | 205 +++ aqjmsdemo01.java | 222 +++ aqjmsdemo02.java | 214 +++ aqjmsdemo03.java | 130 ++ aqjmsdemo04.java | 238 +++ aqjmsdemo05.java | 234 +++ aqjmsdemo06.java | 274 +++ aqjmsdemo07.java | 418 +++++ aqjmsdemo08.java | 410 +++++ aqjmsdemo09.java | 429 +++++ aqjmsdemo10.java | 343 ++++ aqjmsdmo.sql | 61 + aqjmsdrp.sql | 22 + aqjmskprb01.java | 173 ++ aqjmskprb01a.sql | 53 + aqjmskprb01b.sql | 43 + aqjmskprb01c.sql | 37 + aqjmskprb01d.sql | 34 + aqorademo01.java | 306 ++++ aqorademo02.java | 260 +++ aqoradmo.sql | 48 + aqoradrp.sql | 28 + aqxml01.xml | 87 + aqxml02.xml | 21 + aqxml03.xml | 67 + aqxml04.xml | 19 + aqxml05.xml | 11 + aqxml06.xml | 77 + aqxml07.xml | 19 + aqxml08.xml | 85 + aqxml09.xml | 18 + aqxml10.xml | 11 + aqxmlREADME.txt | 266 +++ aqxmldemo.ear | Bin 0 -> 9190 bytes aqxmldmo.sql | 232 +++ aqxmldrp.sql | 90 + aqxmlhtp.sql | 190 ++ blobdemo.dat | 2 + calldemo.sql | 87 + case1.rcv | 260 +++ case2.rcv | 480 +++++ case3.rcv | 261 +++ case4.rcv | 157 ++ cbdem1.cob | 481 ++++++ cbdem2.cob | 446 +++++ cbdem3.cob | 303 ++++ cdcdemo.sql | 455 +++++ cdemdp9i.sql | 112 ++ cdemdpco.c | 139 ++ cdemdpco.dat | 10 + cdemdpin.c | 124 ++ cdemdpin.dat | 10 + cdemdpit.c | 108 ++ cdemdpit.dat | 10 + cdemdplp.c | 166 ++ cdemdplp.dat | 30 + cdemdplp.sql | 83 + cdemdpno.c | 157 ++ cdemdpno.dat | 10 + cdemdpro.c | 132 ++ cdemdpro.ctl | 21 + cdemdpro.dat | 10 + cdemdpss.c | 172 ++ cdemdpss.dat | 10 + cdemo1.c | 415 +++++ cdemo2.c | 509 ++++++ cdemo3.c | 292 ++++ cdemo4.c | 413 +++++ cdemo5.c | 313 ++++ cdemo6.cc | 315 ++++ cdemo6.h | 117 ++ cdemo81.c | 445 +++++ cdemo82.c | 514 ++++++ cdemo82.h | 155 ++ cdemo82.sql | 132 ++ cdemoanydata1.c | 775 +++++++++ cdemoanydata1.sql | 59 + cdemoanydata2.c | 776 +++++++++ cdemoanydata2.sql | 49 + cdemobj.c | 895 ++++++++++ cdemobj.h | 150 ++ cdemocoll.c | 720 ++++++++ cdemocoll.h | 37 + cdemocor.c | 1098 ++++++++++++ cdemocor.h | 106 ++ cdemocor.sql | 145 ++ cdemocor1.c | 645 +++++++ cdemocp.c | 397 +++++ cdemocp.sql | 4 + cdemocpproxy.c | 332 ++++ cdemocpproxy.sql | 5 + cdemodp.c | 2887 +++++++++++++++++++++++++++++++ cdemodp.h | 114 ++ cdemodp0.h | 109 ++ cdemodp_lip.c | 171 ++ cdemodr1.c | 1318 ++++++++++++++ cdemodr1.h | 120 ++ cdemodr1.sql | 132 ++ cdemodr2.c | 1283 ++++++++++++++ cdemodr2.h | 112 ++ cdemodr2.sql | 61 + cdemodr3.c | 703 ++++++++ cdemodr3.h | 108 ++ cdemodr3.sql | 34 + cdemodsa.c | 796 +++++++++ cdemodsa.sql | 48 + cdemodsc.c | 870 ++++++++++ cdemodsc.h | 109 ++ cdemodt.c | 1225 +++++++++++++ cdemoext.c | 310 ++++ cdemoext.dat | 11 + cdemofil.c | 242 +++ cdemofo.c | 398 +++++ cdemofor.c | 143 ++ cdemoin1.c | 761 ++++++++ cdemoin1.h | 85 + cdemoin1.sql | 66 + cdemoin2.c | 488 ++++++ cdemoin2.h | 63 + cdemoin2.sql | 52 + cdemoin3.c | 675 ++++++++ cdemoin3.h | 31 + cdemoin3.sql | 84 + cdemol2l.c | 1283 ++++++++++++++ cdemolb.c | 585 +++++++ cdemolb.dat | 771 +++++++++ cdemolb.h | 129 ++ cdemolb.sql | 27 + cdemolb2.c | 962 +++++++++++ cdemolbs.c | 1012 +++++++++++ cdemoplb.c | 807 +++++++++ cdemoqc.c | 544 ++++++ cdemoqc.sql | 53 + cdemoqc2.c | 619 +++++++ cdemorid.c | 517 ++++++ cdemorid.h | 105 ++ cdemorid.sql | 57 + cdemort.c | 621 +++++++ cdemort.h | 75 + cdemosc.c | 390 +++++ cdemosc.sql | 80 + cdemoses.c | 553 ++++++ cdemoses.h | 100 ++ cdemoses.sql | 51 + cdemosp.c | 255 +++ cdemosp.h | 51 + cdemostc.c | 206 +++ cdemostc.h | 55 + cdemosyev.c | 402 +++++ cdemosyev.sql | 339 ++++ cdemosyex.sql | 43 + cdemothr.c | 587 +++++++ cdemothr.h | 111 ++ cdemoucb.c | 621 +++++++ cdemoucb.sql | 27 + cdemoucbl.c | 284 +++ cdemouni.c | 588 +++++++ cdemoup1.c | 266 +++ cdemoup2.c | 267 +++ cdemoupk.c | 466 +++++ cdemoupk.sql | 34 + cdemoxml.c | 649 +++++++ clobdemo.dat | 6 + dattime1.sql | 79 + dattime2.sql | 71 + dattime3.sql | 79 + dattime4.sql | 332 ++++ demo_rdbms.mk | 326 ++++ demo_rdbms32.mk | 337 ++++ demo_rdbms64.mk | 327 ++++ dmabdemo.java | 1125 ++++++++++++ dmabdemo.sql | 712 ++++++++ dmaidemo.java | 297 ++++ dmaidemo.sql | 184 ++ dmapplydemo.java | 743 ++++++++ dmardemo.java | 793 +++++++++ dmardemo.sql | 497 ++++++ dmdtdemo.sql | 334 ++++ dmdtxvlddemo.sql | 246 +++ dmexpimpdemo.java | 388 +++++ dmglcdem.sql | 461 +++++ dmglcdemo.java | 968 +++++++++++ dmglrdem.sql | 346 ++++ dmglrdemo.java | 787 +++++++++ dmhpdemo.sql | 1885 ++++++++++++++++++++ dmkmdemo.java | 1011 +++++++++++ dmkmdemo.sql | 378 ++++ dmnbdemo.java | 1009 +++++++++++ dmnbdemo.sql | 887 ++++++++++ dmnmdemo.java | 618 +++++++ dmnmdemo.sql | 329 ++++ dmocdemo.java | 899 ++++++++++ dmocdemo.sql | 398 +++++ dmpademo.java | 235 +++ dmsh.sql | 593 +++++++ dmshgrants.sql | 61 + dmsvcdem.sql | 746 ++++++++ dmsvcdemo.java | 770 +++++++++ dmsvodem.sql | 264 +++ dmsvodemo.java | 581 +++++++ dmsvrdem.sql | 227 +++ dmsvrdemo.java | 745 ++++++++ dmtreedemo.java | 1230 +++++++++++++ dmtxtfe.sql | 208 +++ dmtxtnmf.sql | 158 ++ dmtxtnmfdemo.java | 843 +++++++++ dmtxtsvm.sql | 229 +++ dmtxtsvmdemo.java | 774 +++++++++ dmxfdemo.java | 893 ++++++++++ epgdemo.sql | 80 + exfdemo.sql | 718 ++++++++ extdemo0.sql | 34 + extdemo1.sql | 2016 +++++++++++++++++++++ extdemo2.c | 730 ++++++++ extdemo2.h | 167 ++ extdemo2.sql | 421 +++++ extdemo3.java | 408 +++++ extdemo3.sql | 313 ++++ extdemo3a.java | 56 + extdemo4.c | 788 +++++++++ extdemo4.h | 127 ++ extdemo4.sql | 206 +++ extdemo5.c | 824 +++++++++ extdemo5.h | 173 ++ extdemo5.sql | 768 ++++++++ extdemo6.c | 960 ++++++++++ extdemo6.h | 158 ++ extdemo6.sql | 722 ++++++++ fdemo1.for | 499 ++++++ fdemo2.for | 389 +++++ fdemo3.for | 285 +++ fgacdemo.sql | 587 +++++++ giffile.dat | Bin 0 -> 64920 bytes inhdemo.sql | 737 ++++++++ maporder.sql | 308 ++++ mddemo.sql | 271 +++ mddemo2.sql | 470 +++++ mdemo1.cpp | 98 ++ mdemo1.h | 201 +++ mdemo1.sql | 34 + mdemo1.typ | 7 + mdemo1o.cpp | 422 +++++ mymdemo1.h | 8 + nchdemo1.c | 586 +++++++ nlsdemo0.sql | 133 ++ nlsdemo1.sql | 60 + nlsdemo2.sql | 60 + nlsdemo3.sql | 68 + nlsdemo4.sql | 49 + nlsdemo5.sql | 57 + o8demo.sql | 317 ++++ o8idemo.sql | 988 +++++++++++ obndra.c | 218 +++ occiaqlis.cpp | 124 ++ occiaqop.cpp | 235 +++ occiaqop.typ | 3 + occiblob.cpp | 323 ++++ occiclob.cpp | 326 ++++ occicoll.cpp | 230 +++ occidemo.sql | 344 ++++ occidemod.sql | 121 ++ occidesc.cpp | 400 +++++ occidml.cpp | 292 ++++ occiinh.cpp | 278 +++ occiinh.typ | 3 + occilbar.cpp | 400 +++++ occimb1.cpp | 190 ++ occimb1.sql | 31 + occiobj.cpp | 196 +++ occiobj.typ | 3 + occipobj.cpp | 199 +++ occipobj.typ | 3 + occipool.cpp | 129 ++ occiproc.cpp | 130 ++ occiscp.cpp | 193 +++ occistre.cpp | 98 ++ occiuni1.cpp | 186 ++ occiuni1.sql | 30 + occiuni2.cpp | 250 +++ occiuni2.sql | 36 + occiuni2.typ | 4 + occiuni2_hindi.txt | Bin 0 -> 710 bytes occiuni2_japanese.txt | Bin 0 -> 594 bytes occiuni2_korean.txt | Bin 0 -> 684 bytes occiuni2_russian.txt | Bin 0 -> 742 bytes occixa.cpp | 321 ++++ oci02.c | 353 ++++ oci02.sql | 54 + oci03.c | 353 ++++ oci03.sql | 54 + oci04.c | 354 ++++ oci04.sql | 54 + oci05.c | 368 ++++ oci05.sql | 65 + oci06.c | 383 ++++ oci06.sql | 51 + oci07.c | 382 ++++ oci07.sql | 51 + oci08.c | 427 +++++ oci08.sql | 64 + oci09.c | 347 ++++ oci09.sql | 108 ++ oci10.c | 487 ++++++ oci10.sql | 120 ++ oci11.c | 435 +++++ oci11.sql | 93 + oci12.c | 352 ++++ oci12.sql | 43 + oci13.c | 504 ++++++ oci13.sql | 39 + oci14.c | 387 +++++ oci14.sql | 27 + oci15.c | 393 +++++ oci15.sql | 27 + oci16.c | 432 +++++ oci16.sql | 28 + oci17.c | 433 +++++ oci17.sql | 27 + oci18.c | 417 +++++ oci18.sql | 63 + oci19.c | 403 +++++ oci19.sql | 30 + oci20.c | 415 +++++ oci20.sql | 30 + oci21.c | 278 +++ oci21.sql | 40 + oci22.c | 293 ++++ oci22.sql | 40 + oci23.c | 297 ++++ oci23.sql | 34 + oci24.c | 263 +++ oci24.sql | 52 + oci25.c | 246 +++ oci25.sql | 35 + oci_f.sed | 86 + oci_m.sed | 136 ++ ociaqarraydeq.c | 237 +++ ociaqarrayenq.c | 250 +++ ociaqdemo00.c | 304 ++++ ociaqdemo01.c | 344 ++++ ociaqdemo02.c | 550 ++++++ ociucb.c | 146 ++ ociucb.mk | 32 + ociucb32.mk | 32 + olsdemo.sql | 748 ++++++++ olsdrp.sql | 61 + ori_f.sed | 35 + orl_f.sed | 128 ++ orl_m.sed | 28 + oro_f.sed | 19 + oro_m.sed | 136 ++ ort_f.sed | 59 + readpipe.c | 242 +++ resultcache.sql | 169 ++ rman2.sh | 97 ++ ruldemo.sql | 1034 +++++++++++ sadv91.sql | 246 +++ sadvdemo.sql | 301 ++++ sadvuwk.sql | 49 + smdim.sql | 362 ++++ smxmv1.sql | 238 +++ smxmv2.sql | 219 +++ smxrw.sql | 1116 ++++++++++++ strmatREADME.txt | 79 + strmatp.sql | 753 ++++++++ strmats.sql | 60 + strmatu.sql | 125 ++ strmmon.c | 3845 +++++++++++++++++++++++++++++++++++++++++ strmmv1.sql | 363 ++++ strmmv1README.txt | 62 + strmmv2.sql | 493 ++++++ strmmv2README.txt | 272 +++ strmmv2s.sql | 142 ++ strmmvp1.sql | 607 +++++++ strmmvp2.sql | 2267 ++++++++++++++++++++++++ strmqp1.sql | 1098 ++++++++++++ strmqry1.sql | 507 ++++++ strmqry1README.txt | 273 +++ summit2.sql | 1286 ++++++++++++++ tyevdemo.sql | 354 ++++ ulcase.sh | 122 ++ ulcase1.ctl | 62 + ulcase1.sql | 44 + ulcase10.ctl | 82 + ulcase10.sql | 80 + ulcase11.ctl | 72 + ulcase11.dat | Bin 0 -> 932 bytes ulcase11.sql | 40 + ulcase2.ctl | 56 + ulcase2.dat | 7 + ulcase3.ctl | 83 + ulcase3.sql | 31 + ulcase4.ctl | 76 + ulcase4.dat | 18 + ulcase4.sql | 37 + ulcase5.ctl | 72 + ulcase5.dat | 12 + ulcase5.sql | 47 + ulcase6.ctl | 47 + ulcase6.dat | 7 + ulcase6.sql | 41 + ulcase7.ctl | 104 ++ ulcase7.dat | 13 + ulcase7e.sql | 30 + ulcase7s.sql | 68 + ulcase8.ctl | 53 + ulcase8.dat | 10 + ulcase8.sql | 58 + ulcase9.ctl | 66 + ulcase9.sql | 41 + ulcase91.dat | 14 + ulcase92.dat | 23 + ulcase93.dat | 7 + ulcase94.dat | 15 + ulcase95.dat | 10 + ulcase96.dat | 8 + viewdemo.sql | 177 ++ xademo1.sql | 121 ++ xademo2.sql | 154 ++ xmlgen1.sql | 302 ++++ xmlgen2.sql | 236 +++ xmltype1.sql | 175 ++ xmltype2.sql | 118 ++ xmltype3.java | 162 ++ xmltype3.sql | 137 ++ xrwutl.sql | 383 ++++ xtdemo01.dat | 7 + xtdemo01.sql | 71 + xtdemo02.sql | 86 + xtdemo03.dat | 7 + xtdemo03.sql | 94 + xtdemo04.dat | 9 + xtdemo04.sql | 124 ++ xtsetup.sql | 42 + 462 files changed, 134765 insertions(+) create mode 100644 ADDRESS.java create mode 100644 AQDemoServlet.java create mode 100644 AQHttp.java create mode 100644 AQHttpRq.java create mode 100644 AQPropServlet.java create mode 100644 Cars.java create mode 100644 Emp.java create mode 100644 MesgListener.java create mode 100644 Message.java create mode 100644 PERSON.java create mode 100644 aadvdemo.sql create mode 100644 anydata.sql create mode 100644 anydset.sql create mode 100644 anytype.sql create mode 100644 aqbzdemo.tar create mode 100644 aqdemo00.sql create mode 100644 aqdemo01.sql create mode 100644 aqdemo02.sql create mode 100644 aqdemo03.sql create mode 100644 aqdemo04.sql create mode 100644 aqdemo05.sql create mode 100644 aqdemo06.sql create mode 100644 aqdemo07.sql create mode 100644 aqdemo08.sql create mode 100644 aqdemo09.sql create mode 100644 aqdemo10.sql create mode 100644 aqdemo11.sql create mode 100644 aqdemo12.sql create mode 100644 aqjmsREADME.txt create mode 100644 aqjmsdemo01.java create mode 100644 aqjmsdemo02.java create mode 100644 aqjmsdemo03.java create mode 100644 aqjmsdemo04.java create mode 100644 aqjmsdemo05.java create mode 100644 aqjmsdemo06.java create mode 100644 aqjmsdemo07.java create mode 100644 aqjmsdemo08.java create mode 100644 aqjmsdemo09.java create mode 100644 aqjmsdemo10.java create mode 100644 aqjmsdmo.sql create mode 100644 aqjmsdrp.sql create mode 100644 aqjmskprb01.java create mode 100644 aqjmskprb01a.sql create mode 100644 aqjmskprb01b.sql create mode 100644 aqjmskprb01c.sql create mode 100644 aqjmskprb01d.sql create mode 100644 aqorademo01.java create mode 100644 aqorademo02.java create mode 100644 aqoradmo.sql create mode 100644 aqoradrp.sql create mode 100644 aqxml01.xml create mode 100644 aqxml02.xml create mode 100644 aqxml03.xml create mode 100644 aqxml04.xml create mode 100644 aqxml05.xml create mode 100644 aqxml06.xml create mode 100644 aqxml07.xml create mode 100644 aqxml08.xml create mode 100644 aqxml09.xml create mode 100644 aqxml10.xml create mode 100644 aqxmlREADME.txt create mode 100644 aqxmldemo.ear create mode 100644 aqxmldmo.sql create mode 100644 aqxmldrp.sql create mode 100644 aqxmlhtp.sql create mode 100644 blobdemo.dat create mode 100644 calldemo.sql create mode 100644 case1.rcv create mode 100644 case2.rcv create mode 100644 case3.rcv create mode 100644 case4.rcv create mode 100644 cbdem1.cob create mode 100644 cbdem2.cob create mode 100644 cbdem3.cob create mode 100644 cdcdemo.sql create mode 100644 cdemdp9i.sql create mode 100644 cdemdpco.c create mode 100644 cdemdpco.dat create mode 100644 cdemdpin.c create mode 100644 cdemdpin.dat create mode 100644 cdemdpit.c create mode 100644 cdemdpit.dat create mode 100644 cdemdplp.c create mode 100644 cdemdplp.dat create mode 100644 cdemdplp.sql create mode 100644 cdemdpno.c create mode 100644 cdemdpno.dat create mode 100644 cdemdpro.c create mode 100644 cdemdpro.ctl create mode 100644 cdemdpro.dat create mode 100644 cdemdpss.c create mode 100644 cdemdpss.dat create mode 100644 cdemo1.c create mode 100644 cdemo2.c create mode 100644 cdemo3.c create mode 100644 cdemo4.c create mode 100644 cdemo5.c create mode 100644 cdemo6.cc create mode 100644 cdemo6.h create mode 100644 cdemo81.c create mode 100644 cdemo82.c create mode 100644 cdemo82.h create mode 100644 cdemo82.sql create mode 100644 cdemoanydata1.c create mode 100644 cdemoanydata1.sql create mode 100644 cdemoanydata2.c create mode 100644 cdemoanydata2.sql create mode 100644 cdemobj.c create mode 100644 cdemobj.h create mode 100644 cdemocoll.c create mode 100644 cdemocoll.h create mode 100644 cdemocor.c create mode 100644 cdemocor.h create mode 100644 cdemocor.sql create mode 100644 cdemocor1.c create mode 100644 cdemocp.c create mode 100644 cdemocp.sql create mode 100644 cdemocpproxy.c create mode 100644 cdemocpproxy.sql create mode 100644 cdemodp.c create mode 100644 cdemodp.h create mode 100644 cdemodp0.h create mode 100644 cdemodp_lip.c create mode 100644 cdemodr1.c create mode 100644 cdemodr1.h create mode 100644 cdemodr1.sql create mode 100644 cdemodr2.c create mode 100644 cdemodr2.h create mode 100644 cdemodr2.sql create mode 100644 cdemodr3.c create mode 100644 cdemodr3.h create mode 100644 cdemodr3.sql create mode 100644 cdemodsa.c create mode 100644 cdemodsa.sql create mode 100644 cdemodsc.c create mode 100644 cdemodsc.h create mode 100644 cdemodt.c create mode 100644 cdemoext.c create mode 100644 cdemoext.dat create mode 100644 cdemofil.c create mode 100644 cdemofo.c create mode 100644 cdemofor.c create mode 100644 cdemoin1.c create mode 100644 cdemoin1.h create mode 100644 cdemoin1.sql create mode 100644 cdemoin2.c create mode 100644 cdemoin2.h create mode 100644 cdemoin2.sql create mode 100644 cdemoin3.c create mode 100644 cdemoin3.h create mode 100644 cdemoin3.sql create mode 100644 cdemol2l.c create mode 100644 cdemolb.c create mode 100644 cdemolb.dat create mode 100644 cdemolb.h create mode 100644 cdemolb.sql create mode 100644 cdemolb2.c create mode 100644 cdemolbs.c create mode 100644 cdemoplb.c create mode 100644 cdemoqc.c create mode 100644 cdemoqc.sql create mode 100644 cdemoqc2.c create mode 100644 cdemorid.c create mode 100644 cdemorid.h create mode 100644 cdemorid.sql create mode 100644 cdemort.c create mode 100644 cdemort.h create mode 100644 cdemosc.c create mode 100644 cdemosc.sql create mode 100644 cdemoses.c create mode 100644 cdemoses.h create mode 100644 cdemoses.sql create mode 100644 cdemosp.c create mode 100644 cdemosp.h create mode 100644 cdemostc.c create mode 100644 cdemostc.h create mode 100644 cdemosyev.c create mode 100644 cdemosyev.sql create mode 100644 cdemosyex.sql create mode 100644 cdemothr.c create mode 100644 cdemothr.h create mode 100644 cdemoucb.c create mode 100644 cdemoucb.sql create mode 100644 cdemoucbl.c create mode 100644 cdemouni.c create mode 100644 cdemoup1.c create mode 100644 cdemoup2.c create mode 100644 cdemoupk.c create mode 100644 cdemoupk.sql create mode 100644 cdemoxml.c create mode 100644 clobdemo.dat create mode 100644 dattime1.sql create mode 100644 dattime2.sql create mode 100644 dattime3.sql create mode 100644 dattime4.sql create mode 100644 demo_rdbms.mk create mode 100644 demo_rdbms32.mk create mode 100644 demo_rdbms64.mk create mode 100644 dmabdemo.java create mode 100644 dmabdemo.sql create mode 100644 dmaidemo.java create mode 100644 dmaidemo.sql create mode 100644 dmapplydemo.java create mode 100644 dmardemo.java create mode 100644 dmardemo.sql create mode 100644 dmdtdemo.sql create mode 100644 dmdtxvlddemo.sql create mode 100644 dmexpimpdemo.java create mode 100644 dmglcdem.sql create mode 100644 dmglcdemo.java create mode 100644 dmglrdem.sql create mode 100644 dmglrdemo.java create mode 100644 dmhpdemo.sql create mode 100644 dmkmdemo.java create mode 100644 dmkmdemo.sql create mode 100644 dmnbdemo.java create mode 100644 dmnbdemo.sql create mode 100644 dmnmdemo.java create mode 100644 dmnmdemo.sql create mode 100644 dmocdemo.java create mode 100644 dmocdemo.sql create mode 100644 dmpademo.java create mode 100644 dmsh.sql create mode 100644 dmshgrants.sql create mode 100644 dmsvcdem.sql create mode 100644 dmsvcdemo.java create mode 100644 dmsvodem.sql create mode 100644 dmsvodemo.java create mode 100644 dmsvrdem.sql create mode 100644 dmsvrdemo.java create mode 100644 dmtreedemo.java create mode 100644 dmtxtfe.sql create mode 100644 dmtxtnmf.sql create mode 100644 dmtxtnmfdemo.java create mode 100644 dmtxtsvm.sql create mode 100644 dmtxtsvmdemo.java create mode 100644 dmxfdemo.java create mode 100644 epgdemo.sql create mode 100644 exfdemo.sql create mode 100644 extdemo0.sql create mode 100644 extdemo1.sql create mode 100644 extdemo2.c create mode 100644 extdemo2.h create mode 100644 extdemo2.sql create mode 100644 extdemo3.java create mode 100644 extdemo3.sql create mode 100644 extdemo3a.java create mode 100644 extdemo4.c create mode 100644 extdemo4.h create mode 100644 extdemo4.sql create mode 100644 extdemo5.c create mode 100644 extdemo5.h create mode 100644 extdemo5.sql create mode 100644 extdemo6.c create mode 100644 extdemo6.h create mode 100644 extdemo6.sql create mode 100644 fdemo1.for create mode 100644 fdemo2.for create mode 100644 fdemo3.for create mode 100644 fgacdemo.sql create mode 100644 giffile.dat create mode 100644 inhdemo.sql create mode 100644 maporder.sql create mode 100644 mddemo.sql create mode 100644 mddemo2.sql create mode 100644 mdemo1.cpp create mode 100644 mdemo1.h create mode 100644 mdemo1.sql create mode 100644 mdemo1.typ create mode 100644 mdemo1o.cpp create mode 100644 mymdemo1.h create mode 100644 nchdemo1.c create mode 100644 nlsdemo0.sql create mode 100644 nlsdemo1.sql create mode 100644 nlsdemo2.sql create mode 100644 nlsdemo3.sql create mode 100644 nlsdemo4.sql create mode 100644 nlsdemo5.sql create mode 100644 o8demo.sql create mode 100644 o8idemo.sql create mode 100644 obndra.c create mode 100644 occiaqlis.cpp create mode 100644 occiaqop.cpp create mode 100644 occiaqop.typ create mode 100644 occiblob.cpp create mode 100644 occiclob.cpp create mode 100644 occicoll.cpp create mode 100644 occidemo.sql create mode 100644 occidemod.sql create mode 100644 occidesc.cpp create mode 100644 occidml.cpp create mode 100644 occiinh.cpp create mode 100644 occiinh.typ create mode 100644 occilbar.cpp create mode 100644 occimb1.cpp create mode 100644 occimb1.sql create mode 100644 occiobj.cpp create mode 100644 occiobj.typ create mode 100644 occipobj.cpp create mode 100644 occipobj.typ create mode 100644 occipool.cpp create mode 100644 occiproc.cpp create mode 100644 occiscp.cpp create mode 100644 occistre.cpp create mode 100644 occiuni1.cpp create mode 100644 occiuni1.sql create mode 100644 occiuni2.cpp create mode 100644 occiuni2.sql create mode 100644 occiuni2.typ create mode 100644 occiuni2_hindi.txt create mode 100644 occiuni2_japanese.txt create mode 100644 occiuni2_korean.txt create mode 100644 occiuni2_russian.txt create mode 100644 occixa.cpp create mode 100644 oci02.c create mode 100644 oci02.sql create mode 100644 oci03.c create mode 100644 oci03.sql create mode 100644 oci04.c create mode 100644 oci04.sql create mode 100644 oci05.c create mode 100644 oci05.sql create mode 100644 oci06.c create mode 100644 oci06.sql create mode 100644 oci07.c create mode 100644 oci07.sql create mode 100644 oci08.c create mode 100644 oci08.sql create mode 100644 oci09.c create mode 100644 oci09.sql create mode 100644 oci10.c create mode 100644 oci10.sql create mode 100644 oci11.c create mode 100644 oci11.sql create mode 100644 oci12.c create mode 100644 oci12.sql create mode 100644 oci13.c create mode 100644 oci13.sql create mode 100644 oci14.c create mode 100644 oci14.sql create mode 100644 oci15.c create mode 100644 oci15.sql create mode 100644 oci16.c create mode 100644 oci16.sql create mode 100644 oci17.c create mode 100644 oci17.sql create mode 100644 oci18.c create mode 100644 oci18.sql create mode 100644 oci19.c create mode 100644 oci19.sql create mode 100644 oci20.c create mode 100644 oci20.sql create mode 100644 oci21.c create mode 100644 oci21.sql create mode 100644 oci22.c create mode 100644 oci22.sql create mode 100644 oci23.c create mode 100644 oci23.sql create mode 100644 oci24.c create mode 100644 oci24.sql create mode 100644 oci25.c create mode 100644 oci25.sql create mode 100644 oci_f.sed create mode 100644 oci_m.sed create mode 100644 ociaqarraydeq.c create mode 100644 ociaqarrayenq.c create mode 100644 ociaqdemo00.c create mode 100644 ociaqdemo01.c create mode 100644 ociaqdemo02.c create mode 100644 ociucb.c create mode 100644 ociucb.mk create mode 100644 ociucb32.mk create mode 100644 olsdemo.sql create mode 100644 olsdrp.sql create mode 100644 ori_f.sed create mode 100644 orl_f.sed create mode 100644 orl_m.sed create mode 100644 oro_f.sed create mode 100644 oro_m.sed create mode 100644 ort_f.sed create mode 100644 readpipe.c create mode 100644 resultcache.sql create mode 100644 rman2.sh create mode 100644 ruldemo.sql create mode 100644 sadv91.sql create mode 100644 sadvdemo.sql create mode 100644 sadvuwk.sql create mode 100644 smdim.sql create mode 100644 smxmv1.sql create mode 100644 smxmv2.sql create mode 100644 smxrw.sql create mode 100644 strmatREADME.txt create mode 100644 strmatp.sql create mode 100644 strmats.sql create mode 100644 strmatu.sql create mode 100644 strmmon.c create mode 100644 strmmv1.sql create mode 100644 strmmv1README.txt create mode 100644 strmmv2.sql create mode 100644 strmmv2README.txt create mode 100644 strmmv2s.sql create mode 100644 strmmvp1.sql create mode 100644 strmmvp2.sql create mode 100644 strmqp1.sql create mode 100644 strmqry1.sql create mode 100644 strmqry1README.txt create mode 100644 summit2.sql create mode 100644 tyevdemo.sql create mode 100644 ulcase.sh create mode 100644 ulcase1.ctl create mode 100644 ulcase1.sql create mode 100644 ulcase10.ctl create mode 100644 ulcase10.sql create mode 100644 ulcase11.ctl create mode 100644 ulcase11.dat create mode 100644 ulcase11.sql create mode 100644 ulcase2.ctl create mode 100644 ulcase2.dat create mode 100644 ulcase3.ctl create mode 100644 ulcase3.sql create mode 100644 ulcase4.ctl create mode 100644 ulcase4.dat create mode 100644 ulcase4.sql create mode 100644 ulcase5.ctl create mode 100644 ulcase5.dat create mode 100644 ulcase5.sql create mode 100644 ulcase6.ctl create mode 100644 ulcase6.dat create mode 100644 ulcase6.sql create mode 100644 ulcase7.ctl create mode 100644 ulcase7.dat create mode 100644 ulcase7e.sql create mode 100644 ulcase7s.sql create mode 100644 ulcase8.ctl create mode 100644 ulcase8.dat create mode 100644 ulcase8.sql create mode 100644 ulcase9.ctl create mode 100644 ulcase9.sql create mode 100644 ulcase91.dat create mode 100644 ulcase92.dat create mode 100644 ulcase93.dat create mode 100644 ulcase94.dat create mode 100644 ulcase95.dat create mode 100644 ulcase96.dat create mode 100644 viewdemo.sql create mode 100644 xademo1.sql create mode 100644 xademo2.sql create mode 100644 xmlgen1.sql create mode 100644 xmlgen2.sql create mode 100644 xmltype1.sql create mode 100644 xmltype2.sql create mode 100644 xmltype3.java create mode 100644 xmltype3.sql create mode 100644 xrwutl.sql create mode 100644 xtdemo01.dat create mode 100644 xtdemo01.sql create mode 100644 xtdemo02.sql create mode 100644 xtdemo03.dat create mode 100644 xtdemo03.sql create mode 100644 xtdemo04.dat create mode 100644 xtdemo04.sql create mode 100644 xtsetup.sql diff --git a/ADDRESS.java b/ADDRESS.java new file mode 100644 index 0000000..a11d50c --- /dev/null +++ b/ADDRESS.java @@ -0,0 +1,94 @@ +/* $Header: ADDRESS.java 15-mar-00.09:06:06 rbhyrava Exp $ */ + +/* Copyright (c) Oracle Corporation 2000. All Rights Reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 03/15/00 - AQ API demo -Jpub generated class for ADDRESS Type + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: ADDRESS.java 15-mar-00.09:06:06 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/**** + * Jpub generated class for for ADDRESS object type + * Used in aqorademo02.java + ***/ +import java.sql.SQLException; +import java.sql.Connection; +import oracle.jdbc.OracleTypes; +import oracle.sql.ORAData; +import oracle.sql.ORADataFactory; +import oracle.sql.Datum; +import oracle.sql.STRUCT; +import oracle.jpub.runtime.MutableStruct; + +public class ADDRESS implements ORAData, ORADataFactory +{ + public static final String _SQL_NAME = "AQJAVA.ADDRESS"; + public static final int _SQL_TYPECODE = OracleTypes.STRUCT; + + protected MutableStruct _struct; + + private static int[] _sqlType = { 12,12 }; + private static ORADataFactory[] _factory = new ORADataFactory[2]; +protected static final ADDRESS _ADDRESSFactory = new ADDRESS(false); + + public static ORADataFactory getORADataFactory() + { return _ADDRESSFactory; } + /* constructor */ + protected ADDRESS(boolean init) + { if(init) _struct = new MutableStruct(new Object[2], _sqlType, _factory); } + public ADDRESS() + { this(true); } + public ADDRESS(String street, String city) throws SQLException + { this(true); + setStreet(street); + setCity(city); + } + + /* ORAData interface */ + public Datum toDatum(Connection c) throws SQLException + { + return _struct.toDatum(c, _SQL_NAME); + } + + + /* ORADataFactory interface */ + public ORAData create(Datum d, int sqlType) throws SQLException + { return create(null, d, sqlType); } + protected ORAData create(ADDRESS o, Datum d, int sqlType) throws SQLException + { + if (d == null) return null; + if (o == null) o = new ADDRESS(false); + o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory); + return o; + } + /* accessor methods */ + public String getStreet() throws SQLException + { return (String) _struct.getAttribute(0); } + + public void setStreet(String street) throws SQLException + { _struct.setAttribute(0, street); } + + + public String getCity() throws SQLException + { return (String) _struct.getAttribute(1); } + + public void setCity(String city) throws SQLException + { _struct.setAttribute(1, city); } + +} diff --git a/AQDemoServlet.java b/AQDemoServlet.java new file mode 100644 index 0000000..de72b35 --- /dev/null +++ b/AQDemoServlet.java @@ -0,0 +1,127 @@ +/* $Header: AQDemoServlet.java 27-oct-2004.17:29:35 rbhyrava Exp $ */ + +/* Copyright (c) 2001, 2004, Oracle. All rights reserved. */ + +/* + DESCRIPTION + AQ Demo Servlet for OC4J configuration + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 10/27/04 - enable tracing ; oc4j support + rbhyrava 09/13/04 - Pass host,port,sid as arguments + rbhyrava 03/11/02 - fix typo + rbhyrava 02/20/02 - set host/port etc + rbhyrava 04/12/01 - Merged rbhyrava_aqxmldemos + rbhyrava 04/02/01 - Creation + */ + +/** + * @version $Header: AQDemoServlet.java 27-oct-2004.17:29:35 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +import java.io.*; +import javax.servlet.*; +import javax.servlet.http.*; +import oracle.AQ.*; +import oracle.AQ.xml.*; +import java.sql.*; +import oracle.jms.*; +import javax.jms.*; +import java.io.*; +import oracle.jdbc.pool.*; + +/** + * This is a sample AQ Servlet for OC4J webserver configuration. + */ +public class AQDemoServlet extends oracle.AQ.xml.AQxmlServlet +{ + + public FileOutputStream ostream = null; + //======================================================================== + /* + * getDBDrv - specify the database to which the servlet will connect + */ + + public AQxmlDataSource createAQDataSource() throws AQxmlException + { + + //String sid = "aq2"; + //String port = "1521"; + //String host = "stacj31"; + + AQxmlDataSource db_drv = null; + String sid = System.getProperty("MYDB_SID"); + String port = System.getProperty("MYDB_PORT"); + String host = System.getProperty("MYDB_HOST"); + + System.out.println("AQDemoServlet - setting db driver using"); + System.out.println("sid:" + sid + " port:" + port + " host:" + host ) ; + + db_drv = new AQxmlDataSource("scott", "tiger", sid, host, port); + System.out.print("sid: "+ db_drv.getSid() ) ; + System.out.print(" host: "+ db_drv.getHost() ) ; + System.out.print(" port: "+ db_drv.getPort() ) ; + System.out.print(" cachesize: "+ db_drv.getCacheSize() ) ; + System.out.println(" cachescheme: "+ db_drv.getCacheScheme() ) ; + + return db_drv; + } + + //======================================================================== + public void init(ServletConfig cfg) + { + AQxmlDataSource db_drv = null; + + try + { + super.init(cfg); + + // Remove the comment below to enable tracing + /* + ostream = new FileOutputStream(fname) ; + AQxmlDebug.setTraceLevel(5); + AQxmlDebug.setDebug(true); + + //to write debug output to a file + String fname = "/tmp/wsdemoservletdebug.log" ; + File f = new File(fname) ; + AQxmlDebug.setLogStream(ostream); + + // or to write debug output to standard err + AQxmlDebug.setLogStream(System.err); + */ + + /* + AQjmsOracleDebug.setLogStream(System.err); + AQjmsOracleDebug.setTraceLevel(5); + AQjmsOracleDebug.setDebug(true); + */ + + db_drv = this.createAQDataSource(); + setAQDataSource(db_drv); + + setManualInvalidation(false); + setSessionMaxInactiveTime(30); + } + catch (AQxmlException aq_ex) + { + System.out.println("AQ exception: " + aq_ex); + aq_ex.printStackTrace(); + + aq_ex.getNextException().printStackTrace(); + } + catch (Exception ex) + { + System.out.println("Exception: " + ex); + ex.printStackTrace(); + } + } +} diff --git a/AQHttp.java b/AQHttp.java new file mode 100644 index 0000000..5040f28 --- /dev/null +++ b/AQHttp.java @@ -0,0 +1,275 @@ +/* $Header: AQHttp.java 02-nov-2004.13:47:08 rbhyrava Exp $ */ + +/* Copyright (c) 2001, 2004, Oracle. All rights reserved. */ + +/* + DESCRIPTION + AQxml HTTP/HTTPS POST an AQ XML Request using HTTP Client + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 11/02/04 - demossl + lzhao 08/28/01 - merge rbhyrava's changes-setContentType + rbhyrava 07/23/01 - use s_oracleHome as per bug1895434 + rbhyrava 07/20/01 - + rbhyrava 07/20/01 - https + rbhyrava 04/12/01 - Merged rbhyrava_aqxmldemos + rbhyrava 04/09/01 - Creation + */ + +/** + * @version $Header: AQHttp.java 02-nov-2004.13:47:08 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/* Helper class to Post AQ XML request */ +import HTTPClient.*; +import java.util.*; +import java.io.*; +import java.lang.reflect.*; + +public abstract class AQHttp { + private String server_name; // server name + private int port_number; // port number + private String protocol_type ; + private String fs = File.separator ; + private String demossl_crt_file = System.getProperty("CERT"); + private HTTPConnection con = null; // HTTP connection + private String userPass = null; + + + String oc4jcert = +"MIIB0jCCATsCBEAIDP0wDQYJKoZIhvcNAQEEBQAwMDELMAkGA1UEBhMCVVMxDzANBgNVBAoTBk9y"+ +"YWNsZTEQMA4GA1UEAxMHc29tZW9uZTAeFw0wNDAxMTYxNjEwMzdaFw0xNDAxMTMxNjEwMzdaMDAx"+ +"CzAJBgNVBAYTAlVTMQ8wDQYDVQQKEwZPcmFjbGUxEDAOBgNVBAMTB3NvbWVvbmUwgZ8wDQYJKoZI"+ +"hvcNAQEBBQADgY0AMIGJAoGBAMfTBEKasCvuWVLQZocEACMt7S03j64NBCAGBG8XAKq5gbAOAyat"+ +"fOnoV/fSeNVgBv7XuNmtysOCBCGCrNnrdGdup8CjTkfrHxFrq5cWjfLZammrFjlebIY6BPkTX4I4"+ +"zBkEyCjyFpTh1y/SzRzdsiGSPIIML2OuCpLsZCet1i67AgMBAAEwDQYJKoZIhvcNAQEEBQADgYEA"+ +"MUQy8siUiFhXJ7q7W3HThQ0pi3jO+ryJz/TjfH+RCjPPwh2Ipq5oMDoXsoBoUzc7oiYj8GM+angE"+ +"0XSkLLayqidmcXYCki92D4Wqemx90bhxVvCz6wUyG4yPm9VhKBwqiwKrw3np8RtDjD5HFEvk2Icb"+ +"3OoWB2Z/MxN0Upl/Ki4="; + + + + public AQHttp() {} + public void setProtocolType(String prot) { + try { + protocol_type = prot.toLowerCase() ; + + } catch (Exception e) { + e.printStackTrace(); + System.out.println("setProtocolType:" + e); + } + } + public void setServerPort(String sname, String pnumber ) { + try { + server_name = sname ; + port_number = Integer.parseInt(pnumber); + + } catch (Exception e) { + e.printStackTrace(); + System.out.println("setServerPort:" + e); + } + } + + // make connection + public void connect(String username, String password) { + if (con != null) con = null; + userPass = username + ":" + password ; + con = newConnection(username, password); + } + // close connection + public void close() { + try { + if (con != null) + con.stop() ; + } catch (Exception e ) { + System.out.println("Close Connection : "+ e) ; + } + } + + // This method returns a new instance of HTTPConnection + public HTTPConnection newConnection(String username, String password) { + HTTPConnection returnValue = null; + + try { + returnValue = + new HTTPConnection(protocol_type, server_name, port_number); + returnValue.addBasicAuthorization("aqxmldemo_web", username, password); + if ( protocol_type.compareTo("https") == 0) { + //cert=readFile(demossl_crt_file) ; + //System.out.println(cert) ; + returnValue.addTrustPoint(oc4jcert); + } + + NVPair[] hdrs = returnValue.getDefaultHeaders() ; + int idx =0; + for (idx=0; idx< hdrs.length ; idx++) { + System.out.println(hdrs[idx].getName()); + if (hdrs[idx].getName().equalsIgnoreCase("content-type")) { + hdrs[idx] = new NVPair("Content-Type", "text/xml") ; + } + } + if (hdrs.length == 0) { + hdrs = new NVPair[1]; + hdrs[0] = new NVPair("Content-Type", "text/xml") ; + } + returnValue.setDefaultHeaders(hdrs) ; + + } catch (Exception e) { + e.printStackTrace(); + System.out.println("Fail to connect to " + server_name + ":" + port_number); + } + return returnValue; + } + + // get response from webserver + public int getStatusCode(String urlPath) { + int code = 0; + try { + HTTPResponse resp = con.Get(urlPath); + code = resp.getStatusCode(); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("Fail to get the status code"); + } + return code; + } + + public String getStringResponse(String urlPath) { + String str = null; + try { + HTTPResponse resp = con.Get(urlPath); + str = new String(resp.getData()); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("Fail to get a String response "); + } + return str; + } + + public String postStringResponse(String urlPath, String[] xmlfiles) { + String str = ""; + String data = null; + String cookie = null; + String ret_cookie = null; + try { + for ( int i =0 ; i < xmlfiles.length ; i++) { + + if (cookie != null ) { + AuthorizationInfo au1 = AuthorizationInfo.getAuthorization( + server_name, port_number, "Basic", "aqxmldemo_web") ; + au1.setCookie(cookie) ; + } + if (xmlfiles[i] != null ) + { + data = readFile(xmlfiles[i]) ; + HTTPResponse resp = con.Post(urlPath, data.getBytes(), null); + if (i == 0) { + str = str +"URL: " +protocol_type +"://" + server_name + ":"+ + port_number+ urlPath + "\n"; + } else { + str = str + "\n" ; + } + str = str + "Setting User:: " + userPass + "\n"; + str = str + "Setting Encoded:: " + resp.getHeader("Content-Encoding") + "\n"; + if ( i != 0 ) { + str = str + "Setting cookie " + cookie + "\n"; + } + + str = str + "POSTing file: " + xmlfiles[i] + "\n"; + AuthorizationInfo au = AuthorizationInfo.getAuthorization(server_name, port_number, "Basic", "aqxmldemo_web") ; + ret_cookie = au.getCookie() ; + if (ret_cookie != null) { + cookie = ret_cookie ; + } + str = str + "Cookie " + cookie + "\n"; + str = str + "HTTP response code is " + resp.getStatusCode() + "\n"; + String con_len = resp.getHeader("Content-Length") ; + str = str+"HTTP Content Length: "+ ((con_len != null) ? con_len : "-1" ) +"\n"; + str = str+"HTTP Content Type: " + resp.getHeader("Content-Type") + "\n"; + str = str + "HTTP Content: " + "\n"; + String respdata = new String(resp.getData()) ; + str = str + respdata ; + + } + } + } catch (Exception e) { + e.printStackTrace(); + System.out.println("Fail to POST a String response "); + } + return str; + } + + /** + * This class defines a CookiePolicyHandler that + * accepts and sends all cookie without dicretion. + *@see setCookieAcceptance + */ + protected class MaxPolicyHandler implements HTTPClient.CookiePolicyHandler { + public boolean acceptCookie(Cookie cookie, RoRequest req, RoResponse resp) + { return true; } + + public boolean sendCookie(Cookie cookie, RoRequest req) + { return true; } + } + + /** + * This class defines a CookiePolicyHandler that + * rejects all cookie without dicretion. + *@see setCookieAcceptance + */ + protected class MinPolicyHandler implements HTTPClient.CookiePolicyHandler { + public boolean acceptCookie(Cookie cookie, RoRequest req, RoResponse resp) + { return false; } + + public boolean sendCookie(Cookie cookie, RoRequest req) + { return false; } + } + + protected void setCookieAcceptance(boolean accept) { + setCookieAcceptance(con, accept); + } + + protected void setCookieAcceptance(HTTPConnection con, boolean accept) { + try { + Class []c = con.getModules(); + int i; + for (i=0; i < c.length; i++) { + //System.out.println("module "+ i +" : " + c[i]); + if (c[i].equals(CookieModule.class)) break; + } + Method m = c[i].getMethod("setCookiePolicyHandler", new Class[] {CookiePolicyHandler.class}); + if (accept) + m.invoke(null, new Object[] {new MaxPolicyHandler()}); + else + m.invoke(null, new Object[] {new MinPolicyHandler()}); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("Exception thrown in setCookieAcceptance"); + } + } + + public static String readFile(String fname) throws Exception + { + FileReader fReader; + BufferedReader bReader; + String line= null; + StringBuffer data; + + fReader = new FileReader(fname); + bReader = new BufferedReader(fReader); + data = new StringBuffer(); + while ((line = bReader.readLine()) != null) + { + data.append(line + "\n"); + } + return data.toString(); + } +} diff --git a/AQHttpRq.java b/AQHttpRq.java new file mode 100644 index 0000000..2c581fd --- /dev/null +++ b/AQHttpRq.java @@ -0,0 +1,102 @@ +/* $Header: AQHttpRq.java 20-jul-2001.16:50:36 rbhyrava Exp $ */ + +/* Copyright (c) 2001, Oracle Corporation. All rights reserved. */ + +/* + DESCRIPTION + + AQXml-HTTP/HTTPS POST an AQ XML Request using HTTP Client + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 07/20/01 - + rbhyrava 07/20/01 - Protocol + rbhyrava 04/12/01 - Merged rbhyrava_aqxmldemos + rbhyrava 04/04/01 - Creation + */ + +/** + * @version $Header: AQHttpRq.java 20-jul-2001.16:50:36 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +//Post an AQ XML Request +public class AQHttpRq extends AQHttp { + + static String URL = null; + static String[] xmlfiles = new String[3]; + static String username = null; + static String password = null; + static String server = null; + static String method = null; + static String port_number = null; + static String protocol = null; + + public static void main(String args[]) + { + try + { + if(args.length < 6) + { + System.out.println ("Not enough parameters. " + + "Usage: java AQHttpRq [SERVER] [PORT] [GET/POST] [PROTOCOL] [URL] [USERNAME] [PASSWORD] [XMLFILE1] [XMLFILE2] ..\n"); + + return; + } + server = args[0] ; + port_number = args[1] ; + method = args[2] ; + protocol = args[3]; + URL = args[4] ; + username = args[5] ; + password = args[6] ; + + if (method.equals("POST") ) { + xmlfiles = new String [args.length -7] ; + for ( int i= 7 ; i < args.length ; i++) { + xmlfiles[i -7 ] = args[i] ; + } + if (xmlfiles.length == 0) { + System.out.println("Error:XMLFiles should be specified for POST"); + } + } + System.out.println("server: " + server ) ; + System.out.println("port : " + port_number ) ; + System.out.println("method " + method ) ; + System.out.println("protocol " + protocol ) ; + System.out.println("URL " + URL ) ; + System.out.println("username " + username ) ; + System.out.println("password " + password ) ; + for ( int i= 0 ; i < xmlfiles.length ; i++) { + System.out.println("xmlfiles " + xmlfiles[i] ) ; + } + new AQHttpRq().performAction() ; + } + catch (Exception ex) + { + System.out.println("MAIN : " + ex); + } + finally {} + + } + + public void performAction() { + setProtocolType(protocol) ; + setServerPort(server, port_number) ; + connect(username, password); + setCookieAcceptance(true); + if (method.equals("POST")) { + System.out.println(postStringResponse(URL, xmlfiles)); + } else { + System.out.println(getStringResponse(URL)) ; + close() ; + } + } +} diff --git a/AQPropServlet.java b/AQPropServlet.java new file mode 100644 index 0000000..9dfc181 --- /dev/null +++ b/AQPropServlet.java @@ -0,0 +1,100 @@ +/* $Header: AQPropServlet.java 27-oct-2004.17:30:12 rbhyrava Exp $ */ + +/* Copyright (c) 2001, 2004, Oracle. All rights reserved. */ + +/* + DESCRIPTION + AQ propagation using http/https. + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 10/27/04 - oc4j support;enable tracing + rbhyrava 10/26/04 - DBPort + rbhyrava 09/13/04 - Pass host,port,sid as arguments + rbhyrava 02/20/02 - set host,port,sid + rbhyrava 05/09/01 - Init for Jserv + rbhyrava 04/12/01 - Merged rbhyrava_aqxmldemos + rbhyrava 04/10/01 - comments + rbhyrava 03/30/01 - Creation + */ + +/** + * @version $Header: AQPropServlet.java 27-oct-2004.17:30:12 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/* + AQ Propagation Servlet +*/ +import java.io.*; +import javax.servlet.*; +import javax.servlet.http.*; +import oracle.AQ.*; +import oracle.AQ.xml.*; +import java.sql.*; +import oracle.jms.*; +import javax.jms.*; +import java.io.*; +import oracle.jdbc.pool.*; + +/** + * This is a AQ Propagation Servlet. + */ +public class AQPropServlet extends oracle.AQ.xml.AQxmlServlet +{ + + /*====================================================================* + * getDBDrv - specify the database to which the servlet will connect * + *====================================================================*/ + public AQxmlDataSource createAQDataSource() throws AQxmlException + { + AQxmlDataSource db_drv = null; + + //String sid = "%s_oracleSid%"; + //String port = "1521"; + //String host = "%s_oracleHost%"; + + String sid = System.getProperty("MYDB_SID"); + String port = System.getProperty("MYDB_PORT"); + String host = System.getProperty("MYDB_HOST"); + + System.err.println("AQPropServlet - setting db driver using"); + System.err.println("sid:" + sid + " port:" + port + " host:" + host ) ; + + System.err.println("AQPropServlet - setting db driver"); + db_drv = new AQxmlDataSource("scott", "tiger", sid, host, port); + System.err.print("sid: "+ db_drv.getSid() ) ; + System.err.print(" host: "+ db_drv.getHost() ) ; + System.err.print(" port: "+ db_drv.getPort() ) ; + System.err.print(" cachesize: "+ db_drv.getCacheSize() ) ; + System.err.println(" cachescheme: "+ db_drv.getCacheScheme() ) ; + return db_drv; + } + + public void init(ServletConfig cfg) + { + try + { + super.init(cfg) ; + + AQxmlDebug.setTraceLevel(5); + AQxmlDebug.setDebug(true); + AQxmlDebug.setLogStream(System.err); + + AQxmlDataSource dt_src = this.createAQDataSource(); + setAQDataSource(dt_src); + setSessionMaxInactiveTime(180) ; + } + catch (Exception ex) + { + System.err.println("Exception in init: " + ex); + } + } +} + diff --git a/Cars.java b/Cars.java new file mode 100644 index 0000000..21c92fd --- /dev/null +++ b/Cars.java @@ -0,0 +1,119 @@ +/* $Header: Cars.java 01-mar-2002.14:56:41 rbhyrava Exp $ */ + +/* Copyright (c) 2000, 2002, Oracle Corporation. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 03/01/02 - + rbhyrava 03/15/00 - AQ jms demo -Jpub generated class for CARS Type + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: Cars.java 01-mar-2002.14:56:41 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/**** + * Jpub generated class for for CARS object type + * Used in aqjmsdemo05.java, aqjmsdemo06.java + ***/ +import java.sql.SQLException; +import java.sql.Connection; +import oracle.jdbc.OracleTypes; +import oracle.sql.ORAData; +import oracle.sql.ORADataFactory; +import oracle.sql.Datum; +import oracle.sql.STRUCT; +import oracle.jpub.runtime.MutableStruct; + +public class Cars implements ORAData, ORADataFactory +{ + public static final String _SQL_NAME = "JMSUSER.CARS"; + public static final int _SQL_TYPECODE = OracleTypes.STRUCT; + + protected MutableStruct _struct; + + private static int[] _sqlType = { 2,12,2,2,12 }; + private static ORADataFactory[] _factory = new ORADataFactory[5]; +protected static final Cars _CarsFactory = new Cars(false); + + public static ORADataFactory getORADataFactory() + { return _CarsFactory; } + /* constructor */ + protected Cars(boolean init) + { if(init) _struct = new MutableStruct(new Object[5], _sqlType, _factory); } + public Cars() + { this(true); } + public Cars(java.math.BigDecimal carno, String make, java.math.BigDecimal year, java.math.BigDecimal price, String color) throws SQLException + { this(true); + setCarno(carno); + setMake(make); + setYear(year); + setPrice(price); + setColor(color); + } + + /* ORAData interface */ + public Datum toDatum(Connection c) throws SQLException + { + return _struct.toDatum(c, _SQL_NAME); + } + + + /* ORADataFactory interface */ + public ORAData create(Datum d, int sqlType) throws SQLException + { return create(null, d, sqlType); } + protected ORAData create(Cars o, Datum d, int sqlType) throws SQLException + { + if (d == null) return null; + if (o == null) o = new Cars(false); + o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory); + return o; + } + /* accessor methods */ + public java.math.BigDecimal getCarno() throws SQLException + { return (java.math.BigDecimal) _struct.getAttribute(0); } + + public void setCarno(java.math.BigDecimal carno) throws SQLException + { _struct.setAttribute(0, carno); } + + + public String getMake() throws SQLException + { return (String) _struct.getAttribute(1); } + + public void setMake(String make) throws SQLException + { _struct.setAttribute(1, make); } + + + public java.math.BigDecimal getYear() throws SQLException + { return (java.math.BigDecimal) _struct.getAttribute(2); } + + public void setYear(java.math.BigDecimal year) throws SQLException + { _struct.setAttribute(2, year); } + + + public java.math.BigDecimal getPrice() throws SQLException + { return (java.math.BigDecimal) _struct.getAttribute(3); } + + public void setPrice(java.math.BigDecimal price) throws SQLException + { _struct.setAttribute(3, price); } + + + public String getColor() throws SQLException + { return (String) _struct.getAttribute(4); } + + public void setColor(String color) throws SQLException + { _struct.setAttribute(4, color); } + +} diff --git a/Emp.java b/Emp.java new file mode 100644 index 0000000..629bc75 --- /dev/null +++ b/Emp.java @@ -0,0 +1,122 @@ +/* $Header: Emp.java 15-mar-00.09:08:33 rbhyrava Exp $ */ + +/* Copyright (c) Oracle Corporation 2000. All Rights Reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 03/15/00 - AQ jms demo -Jpub generated class for Emp Type + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: Emp.java 15-mar-00.09:08:33 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/**** + * Jpub generated class for for EMP object type + * Used in aqjmsdemo05.java + ***/ +import java.sql.SQLException; +import java.sql.Connection; +import oracle.jdbc.OracleTypes; +import oracle.sql.ORAData; +import oracle.sql.ORADataFactory; +import oracle.sql.Datum; +import oracle.sql.STRUCT; +import oracle.jpub.runtime.MutableStruct; + +public class Emp implements ORAData, ORADataFactory +{ + public static final String _SQL_NAME = "JMSUSER.EMP"; + public static final int _SQL_TYPECODE = OracleTypes.STRUCT; + + protected MutableStruct _struct; + + private static int[] _sqlType = { 2,12,2002,2,12 }; + private static ORADataFactory[] _factory = new ORADataFactory[5]; + static + { + _factory[2] = Cars.getORADataFactory(); + } +protected static final Emp _EmpFactory = new Emp(false); + + public static ORADataFactory getORADataFactory() + { return _EmpFactory; } + /* constructor */ + protected Emp(boolean init) + { if(init) _struct = new MutableStruct(new Object[5], _sqlType, _factory); } + public Emp() + { this(true); } + public Emp(java.math.BigDecimal id, String name, Cars carown, java.math.BigDecimal rank, String zip) throws SQLException + { this(true); + setId(id); + setName(name); + setCarown(carown); + setRank(rank); + setZip(zip); + } + + /* ORAData interface */ + public Datum toDatum(Connection c) throws SQLException + { + return _struct.toDatum(c, _SQL_NAME); + } + + + /* ORADataFactory interface */ + public ORAData create(Datum d, int sqlType) throws SQLException + { return create(null, d, sqlType); } + protected ORAData create(Emp o, Datum d, int sqlType) throws SQLException + { + if (d == null) return null; + if (o == null) o = new Emp(false); + o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory); + return o; + } + /* accessor methods */ + public java.math.BigDecimal getId() throws SQLException + { return (java.math.BigDecimal) _struct.getAttribute(0); } + + public void setId(java.math.BigDecimal id) throws SQLException + { _struct.setAttribute(0, id); } + + + public String getName() throws SQLException + { return (String) _struct.getAttribute(1); } + + public void setName(String name) throws SQLException + { _struct.setAttribute(1, name); } + + + public Cars getCarown() throws SQLException + { return (Cars) _struct.getAttribute(2); } + + public void setCarown(Cars carown) throws SQLException + { _struct.setAttribute(2, carown); } + + + public java.math.BigDecimal getRank() throws SQLException + { return (java.math.BigDecimal) _struct.getAttribute(3); } + + public void setRank(java.math.BigDecimal rank) throws SQLException + { _struct.setAttribute(3, rank); } + + + public String getZip() throws SQLException + { return (String) _struct.getAttribute(4); } + + public void setZip(String zip) throws SQLException + { _struct.setAttribute(4, zip); } + +} diff --git a/MesgListener.java b/MesgListener.java new file mode 100644 index 0000000..172dbbb --- /dev/null +++ b/MesgListener.java @@ -0,0 +1,68 @@ +/* $Header: MesgListener.java 16-mar-00.13:11:30 rbhyrava Exp $ */ + +/* Copyright (c) Oracle Corporation 2000. All Rights Reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 03/15/00 - AQ jms demo -Message Listener + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: MesgListener.java 16-mar-00.13:11:30 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ +/* + * Message Listener to listen messages asynchronously. + * Setup Message Listener for a Queue Receiver to receive the messages + * Refer to aqjmsdemo03.java + */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; +import java.math.*; +import java.util.*; + +public class MesgListener implements MessageListener +{ + int mesgno=0; + + Session mysess; + String myname; + + MesgListener(Session sess) { + mysess = sess; + } + public void onMessage(javax.jms.Message m) + { + MapMessage mm = (MapMessage) m ; + try { + mesgno++; + System.out.println("Retrieved message " + + mesgno + " with correlation: " + mm.getJMSCorrelationID()); + System.out.println (" "+ mm.getStringProperty ("color") + + " " + mm.getStringProperty("make") + + " " + mm.getIntProperty("year") + + " " + mm.getDoubleProperty("price")) ; + try { + mysess.commit() ; + } catch (Exception e) { + System.out.println("Exception on Message Listener Commit " + e) ; + } + + } catch (JMSException e) { + System.out.println("Exception onMessage:" + e) ; + } + } +} diff --git a/Message.java b/Message.java new file mode 100644 index 0000000..f27ce95 --- /dev/null +++ b/Message.java @@ -0,0 +1,95 @@ +/* $Header: Message.java 15-mar-00.09:10:14 rbhyrava Exp $ */ + +/* Copyright (c) Oracle Corporation 2000. All Rights Reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 03/15/00 - AQ jms demo -Message Object Type + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: Message.java 15-mar-00.09:10:14 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/* +** Definition of Serial Object for Object Message tests +** simple object definition, extends serializable +** Refer to aqjmsdemo01.java +*/ +import java.io.*; +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; +import java.math.*; +import java.util.*; + +class Message implements Serializable +{ + String name; + int id; + int num_entries; + int[] data_points; + + Message() + { + name = null; + id = -99; + num_entries = 0; + data_points = null; + } + + public String getName() + { + return name; + } + + public int getId() + { + return id; + } + + public int getNumEntries() + { + return num_entries; + } + + public int[] getData() + { + return data_points; + } + + public void setName(String nam) + { + name = nam; + } + + public void setId(int ID) + { + id = ID; + } + + public void setData(int n) + { + int i = 0; + data_points = new int[n]; + for ( i=0; i < n; i++ ) + { + data_points[i] = i; + } + num_entries = data_points.length; + } +} + diff --git a/PERSON.java b/PERSON.java new file mode 100644 index 0000000..3b42fac --- /dev/null +++ b/PERSON.java @@ -0,0 +1,99 @@ +/* $Header: PERSON.java 15-mar-00.09:06:53 rbhyrava Exp $ */ + +/* Copyright (c) Oracle Corporation 2000. All Rights Reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 03/15/00 - AQ API demo -Jpub generated class for PERSON Type + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: PERSON.java 15-mar-00.09:06:53 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/**** + * Jpub generated class for for ADDRESS object type + * Used in aqorademo02.java + ***/ + +import java.sql.SQLException; +import java.sql.Connection; +import oracle.jdbc.OracleTypes; +import oracle.sql.ORAData; +import oracle.sql.ORADataFactory; +import oracle.sql.Datum; +import oracle.sql.STRUCT; +import oracle.jpub.runtime.MutableStruct; + +public class PERSON implements ORAData, ORADataFactory +{ + public static final String _SQL_NAME = "AQJAVA.PERSON"; + public static final int _SQL_TYPECODE = OracleTypes.STRUCT; + + protected MutableStruct _struct; + + private static int[] _sqlType = { 12,2002 }; + private static ORADataFactory[] _factory = new ORADataFactory[2]; + static + { + _factory[1] = ADDRESS.getORADataFactory(); + } +protected static final PERSON _PERSONFactory = new PERSON(false); + + public static ORADataFactory getORADataFactory() + { return _PERSONFactory; } + /* constructor */ + protected PERSON(boolean init) + { if(init) _struct = new MutableStruct(new Object[2], _sqlType, _factory); } + public PERSON() + { this(true); } + public PERSON(String name, ADDRESS home) throws SQLException + { this(true); + setName(name); + setHome(home); + } + + /* ORAData interface */ + public Datum toDatum(Connection c) throws SQLException + { + return _struct.toDatum(c, _SQL_NAME); + } + + + /* ORADataFactory interface */ + public ORAData create(Datum d, int sqlType) throws SQLException + { return create(null, d, sqlType); } + protected ORAData create(PERSON o, Datum d, int sqlType) throws SQLException + { + if (d == null) return null; + if (o == null) o = new PERSON(false); + o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory); + return o; + } + /* accessor methods */ + public String getName() throws SQLException + { return (String) _struct.getAttribute(0); } + + public void setName(String name) throws SQLException + { _struct.setAttribute(0, name); } + + + public ADDRESS getHome() throws SQLException + { return (ADDRESS) _struct.getAttribute(1); } + + public void setHome(ADDRESS home) throws SQLException + { _struct.setAttribute(1, home); } + +} diff --git a/aadvdemo.sql b/aadvdemo.sql new file mode 100644 index 0000000..43fce14 --- /dev/null +++ b/aadvdemo.sql @@ -0,0 +1,1602 @@ +-- +-- $Header: aadvdemo.sql 29-may-2007.13:15:19 achoi Exp $ +-- +-- aadvdemo.sql +-- +-- Copyright (c) 2003, 2007, Oracle. All rights reserved. +-- +-- NAME +-- aadvdemo.sql - SQLAccess Advisor documentation examples +-- +-- DESCRIPTION +-- Runs documentation examples pertaining to the SQLAccess Advisor. +-- Chapter 17 in the Data Warehousing Guide. +-- +-- NOTES +-- Before running this script, the directories ADVISOR_RESULTS +-- and TUNE_RESULTS need to be defined as first described in +-- Section 17.2.23. If they are not setup, the dbms_advisor.create_file +-- calls will not succeed. +-- +-- MODIFIED (MM/DD/YY) +-- achoi 05/29/07 - fix order by +-- gssmith 02/09/07 - Remove Summary Advisor +-- gvincent 11/02/06 - downcase connects for secure verifiers +-- gssmith 05/09/06 - STS conversion +-- pabingha 02/02/05 - BUG 4148628 - disable search parameter +-- mmoy 09/01/04 - Add order by. +-- gssmith 07/20/04 - Add utlxaa to the script +-- lburgess 06/07/04 - add order by clause +-- gssmith 04/30/04 - Add demonstration of 10gR2 features +-- gssmith 04/20/04 - Adjust FAILED count +-- lburgess 11/04/03 - bug 3164691 fixed, uncomment testcase +-- lburgess 10/28/03 - lburgess_doc_examples +-- lburgess 09/17/03 - Created +--------------------------------------------------------------------------- +-- +-- RUNS_STANDALONE Yes +-- +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + + +---------------------------------------------------------------------- +-- Data Warehousing Guide Examples from Chapter 17 - SQLAccess Advisor +---------------------------------------------------------------------- + +-- Section 17.2.2 SQLAccess Advisor Privileges +---------------------------------------------- +-- Grant the ADVISOR privilege to the user. + +connect /as sysdba; +grant ADVISOR to sh; + +-- Connect to user +connect sh/sh; + + +-- Section 17.2.3 Creating Tasks +-------------------------------- + +VARIABLE task_id NUMBER; +VARIABLE task_name VARCHAR2(255); +EXECUTE :task_name := 'MYTASK'; +EXECUTE DBMS_ADVISOR.CREATE_TASK ('SQL Access Advisor', :task_id, :task_name); + + + +-- Section 17.2.5 Creating Templates +------------------------------------ + +-- 1. Create a template called MY_TEMPLATE + +VARIABLE template_id NUMBER; +VARIABLE template_name VARCHAR2(255); +EXECUTE :template_name := 'MY_TEMPLATE'; +EXECUTE DBMS_ADVISOR.CREATE_TASK('SQL Access Advisor',:template_id, - + :template_name, is_template => 'TRUE'); + + +-- 2. Set template parameters. + + +-- set naming conventions for recommended indexes/mvs +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'INDEX_NAME_TEMPLATE', 'SH_IDX$$_'); + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'MVIEW_NAME_TEMPLATE', 'SH_MV$$_'); + + +-- First create the tablespaces used in SET_TASK_PARAMETER +-- doc example. + +connect /as sysdba; + +create tablespace sh_indexes datafile 'shidx.f' size 2m reuse +autoextend on default storage (initial 2k next 2k pctincrease 0 +maxextents unlimited); + +create tablespace sh_mviews datafile 'shmv.f' size 2m reuse +autoextend on default storage (initial 2k next 2k pctincrease 0 +maxextents unlimited); + + +-- Now continue with the SET_TASK_PARAMETER example. + +connect sh/sh; + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'DEF_INDEX_TABLESPACE', 'SH_INDEXES'); + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'DEF_MVIEW_TABLESPACE', 'SH_MVIEWS'); + + + +-- 3. This template can now be used as a starting point +-- to create a task as follows: + + +EXECUTE DBMS_ADVISOR.DELETE_TASK('MYTASK'); + +VARIABLE task_id NUMBER; +VARIABLE task_name VARCHAR2(255); +EXECUTE :task_name := 'MYTASK'; +EXECUTE DBMS_ADVISOR.CREATE_TASK('SQL Access Advisor', :task_id, - + :task_name, template=>'MY_TEMPLATE'); + + + +-- Use pre-defined template SQLACCESS_WAREHOUSE + +EXECUTE DBMS_ADVISOR.DELETE_TASK('MYTASK'); + +EXECUTE DBMS_ADVISOR.CREATE_TASK('SQL Access Advisor', - + :task_id, :task_name, template=>'SQLACCESS_WAREHOUSE'); + + + + + +-- Example 17-1 Creating a Workload +----------------------------------- + +VARIABLE workload_name VARCHAR2(255); +EXECUTE :workload_name := 'MYWORKLOAD'; +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name,'This is my first workload'); + + +-- Example 17-2 Creating a Workload from a Template +--------------------------------------------------- + +-- 1. Create the variables. + +VARIABLE template_id NUMBER; +VARIABLE template_name VARCHAR2(255); + + +-- 2. Create a template called MY_WK_TEMPLATE. + +EXECUTE :template_name := 'MY_WK_TEMPLATE'; +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:template_name, is_template=>'TRUE'); + + +-- 3. Set template parameters. For example, the following sets the filter so only tables in the sh schema are tuned: + +-- set USERNAME_LIST filter to SH +EXECUTE DBMS_ADVISOR.SET_SQLWKLD_PARAMETER( - + :template_name, 'USERNAME_LIST', 'SH'); + + +-- 4. Now create a workload using the template: + +EXECUTE DBMS_ADVISOR.DELETE_SQLWKLD('MYWORKLOAD'); + +VARIABLE workload_name VARCHAR2(255); +EXECUTE :workload_name := 'MYWORKLOAD'; +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD ( - + :workload_name, 'This is my first workload', 'MY_WK_TEMPLATE'); + + + +-- Section 17.2.8 Linking a Task and a Workload +----------------------------------------------- + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF('MYTASK', 'MYWORKLOAD'); + + + + +-- Section 17.2.9.1 SQL Tuning Set +---------------------------------- + +-- First create a SQL Tuning Set called MY_STS_WORKLOAD + +declare + sql_stmt varchar2(1000); +begin + +sql_stmt := +'SELECT /* Query */ + t.week_ending_day, p.prod_subcategory, + sum(s.amount_sold) AS dollars, + s.channel_id, s.promo_id + FROM sales s, times t, products p + WHERE s.time_id = t.time_id + AND s.prod_id = p.prod_id + AND s.prod_id > 10 AND s.prod_id < 50 + GROUP BY t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id'; + + execute immediate sql_stmt; +end; +/ + + +-- Grant privilege to sh for using sql tuning set + +connect /as sysdba; +grant ADMINISTER SQL TUNING SET to sh; + +connect sh/sh; + + + +DECLARE + sqlsetname VARCHAR2(30); + sqlsetcur dbms_sqltune.sqlset_cursor; + refid NUMBER; +BEGIN + sqlsetname := 'MY_STS_WORKLOAD'; + + dbms_sqltune.create_sqlset(sqlsetname, 'Test loading from cursor cache'); + + OPEN sqlsetcur FOR + SELECT VALUE(P) + FROM TABLE( + dbms_sqltune.select_cursor_cache( + 'sql_text like ''SELECT /* Query%''', + NULL, + NULL, + NULL, + NULL, + NULL, + null) + ) P; + + dbms_sqltune.load_sqlset(sqlsetname, sqlsetcur); + +end; +/ + + +-- Now create a workload from the SQL Tuning Set. + +VARIABLE sqlsetname VARCHAR2(30); +VARIABLE workload_name VARCHAR2(30); +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; + +EXECUTE :sqlsetname := 'MY_STS_WORKLOAD'; +EXECUTE :workload_name := 'MY_WORKLOAD'; + +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD (:workload_name); +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_STS (:workload_name , - + :sqlsetname, 'NEW', 1, :saved_stmts, :failed_stmts); + + + + +-- Section 17.2.9.2 Loading a User-Defined Workload +--------------------------------------------------- + +-- +-- Create a user-workload table that will contain SQL statements. +-- + +set echo off + +@utlxaa + +CREATE INDEX aadv_uwk_idx_01 + ON user_workload (module); + +CREATE INDEX aadv_uwk_idx_02 + ON user_workload (username); + +-- +-- Clean up any prior activity data +-- + +truncate table user_workload; + +-- +-- Insert sample SQL statements into the user-workload table +-- + +-- +-- query 1: aggregation with selection +-- + +INSERT INTO user_workload +(username, module, action, priority, elapsed_time, cpu_time, buffer_gets, + disk_reads, rows_processed, executions, optimizer_cost, last_execution_date, + stat_period, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, 1, 1, 1, 1, 1, 1000, 1, SYSDATE, 1, +'SELECT t.week_ending_day, p.prod_subcategory, + sum(s.amount_sold) AS dollars, + s.channel_id, s.promo_id + FROM sales s, times t, products p + WHERE s.time_id = t.time_id + AND s.prod_id = p.prod_id + AND s.prod_id > 10 AND s.prod_id < 50 + GROUP BY t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id +'); + +-- +-- query 2: aggregation with selection +-- + +INSERT INTO user_workload +(username, module, action, priority, elapsed_time, cpu_time, buffer_gets, + disk_reads, rows_processed, executions, optimizer_cost, last_execution_date, + stat_period, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, 1, 1, 1, 1, 1, 1000, 1, SYSDATE, 1, +' SELECT t.calendar_month_desc, sum(s.amount_sold) AS dollars +FROM sales s , times t +WHERE s.time_id = t.time_id + AND s.time_id between TO_DATE(''01-JAN-2000'', ''DD-MON-YYYY'') + AND TO_DATE(''01-JUL-2000'', ''DD-MON-YYYY'') +GROUP BY t.calendar_month_desc +'); + +-- +-- query 3: star query +-- + +INSERT INTO user_workload +(username, module, action, priority, elapsed_time, cpu_time, buffer_gets, + disk_reads, rows_processed, executions, optimizer_cost, last_execution_date, + stat_period, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, 1, 1, 1, 1, 1, 1000, 1, SYSDATE, 1, +'SELECT ch.channel_class, c.cust_city, t.calendar_quarter_desc, + SUM(s.amount_sold) sales_amount +FROM sales s, times t, customers c, channels ch +WHERE s.time_id = t.time_id +AND s.cust_id = c.cust_id +AND s.channel_id = ch.channel_id +AND c.cust_state_province = ''CA'' +AND ch.channel_desc in (''Internet'',''Catalog'') +AND t.calendar_quarter_desc IN (''1999-Q1'',''1999-Q2'') +GROUP BY ch.channel_class, c.cust_city, t.calendar_quarter_desc +'); + +-- +-- query 4: order by +-- + +INSERT INTO user_workload +(username, module, action, priority, elapsed_time, cpu_time, buffer_gets, + disk_reads, rows_processed, executions, optimizer_cost, last_execution_date, + stat_period, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, 1, 1, 1, 1, 1, 1000, 1, SYSDATE, 1, +' SELECT c.country_id, c.cust_city, c.cust_last_name +FROM customers c +WHERE c.country_id in (''US'', ''UK'') +ORDER BY c.country_id, c.cust_city, c.cust_last_name +'); + +commit; + + +-- now load the user-defined workload + +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_USER( - + 'MYWORKLOAD', 'NEW', 'SH', 'USER_WORKLOAD', :saved_stmts, :failed_stmts); + + + +-- Section 17.2.9.3 Loading a SQL Cache Workload +------------------------------------------------ + +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; + +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_SQLCACHE (- + 'MYWORKLOAD', 'APPEND', 2, :saved_stmts, :failed_stmts); + + + +-- Section 17.2.9.4 Using a Hypothetical Workload +------------------------------------------------- + + +VARIABLE workload_name VARCHAR2(255); +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; +EXECUTE :workload_name := 'SCHEMA_WKLD'; +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name); +EXECUTE DBMS_ADVISOR.SET_SQLWKLD_PARAMETER (:workload_name, - + 'USERNAME_LIST', 'SH'); +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_SCHEMA ( - + :workload_name, 'NEW', 2, :saved_stmts, :failed_stmts); + + + + +-- Section 17.2.9.5 Using a 9i Workload +--------------------------------------- + + +-- Before the example in the documentation can be run, an Oracle9i +-- workload must first be created. + +-- Run some SQL statements so we have something in the cache + +set echo off +connect / as sysdba; +alter system flush shared_pool; +connect sh/sh; +set echo off +SELECT SUM(amount_sold), promo_id FROM sales where promo_id < 8 group by promo_id order by promo_id; +SELECT SUM(amount_sold), channel_id FROM sales group by channel_id order by channel_id; +set echo on + +-- load the SQL CACHE workload and check that it is there + +VARIABLE collection_id NUMBER; +VARIABLE no_recs NUMBER; + +-- The setup is complete, now the documentation example can be shown. + +-- 1. Create some variables. + +VARIABLE workload_name VARCHAR2(255); +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; + + +-- Section 17.2.9.6 SQLAccess Advisor Workload Parameters +--------------------------------------------------------- + +-- Order statements by OPTIMIZER_COST +EXECUTE DBMS_ADVISOR.SET_SQLWKLD_PARAMETER ( - + 'MYWORKLOAD', 'ORDER_LIST', 'OPTIMIZER_COST'); + +-- Max number of statements 3 +EXECUTE DBMS_ADVISOR.SET_SQLWKLD_PARAMETER('MYWORKLOAD', 'SQL_LIMIT', 3); + + + +-- Section 17.2.10 SQL Workload Journal +--------------------------------------- + +-- You can turn journaling off before importing workload as follows: + +EXECUTE DBMS_ADVISOR.SET_SQLWKLD_PARAMETER('MYWORKLOAD', 'JOURNALING', 0); + + +-- To view only fatal messages: + +EXECUTE DBMS_ADVISOR.SET_SQLWKLD_PARAMETER('MYWORKLOAD', 'JOURNALING', 4); + + + + +-- Section 17.2.11 Adding SQL Statements to a Workload +------------------------------------------------------ + +VARIABLE sql_text VARCHAR2(400); +EXECUTE :sql_text := 'SELECT AVG(amount_sold) FROM sales'; +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_STATEMENT ( - + 'MYWORKLOAD', 'MONTHLY', 'ROLLUP', priority=>1, executions=>10, - + username => 'SH', sql_text => :sql_text); + + + +-- Section 17.2.12 Deleting SQL Statements from a Workload +---------------------------------------------------------- + +-- Delete using sql_id + +EXECUTE DBMS_ADVISOR.DELETE_SQLWKLD_STATEMENT('MYWORKLOAD', 10); + + + +-- Section 17.2.13 Changing SQL Statements in a Workload +-------------------------------------------------------- + + +EXECUTE DBMS_ADVISOR.UPDATE_SQLWKLD_STATEMENT( - + 'MYWORKLOAD', 2, priority=>3); + + + + +-- Section 17.2.14.1 Setting Workload Attributes +------------------------------------------------ + +EXECUTE DBMS_ADVISOR.UPDATE_SQLWKLD_ATTRIBUTES ( - + 'MYWORKLOAD', read_only=> 'TRUE'); + + + + +-- Section 17.2.14.2 Resetting Workloads +---------------------------------------- + + +-- need to first set it to be readable +EXECUTE DBMS_ADVISOR.UPDATE_SQLWKLD_ATTRIBUTES ( - + 'MYWORKLOAD', read_only=> 'FALSE'); + + +EXECUTE DBMS_ADVISOR.RESET_SQLWKLD('MYWORKLOAD'); + + + + +-- Section 17.2.14.3 Removing a Link Between a Workload and a Task +------------------------------------------------------------------ + + +EXECUTE DBMS_ADVISOR.DELETE_SQLWKLD_REF('MYTASK', 'MYWORKLOAD'); + + + +-- Section 17.2.15 Removing Workloads +------------------------------------- + + +EXECUTE DBMS_ADVISOR.DELETE_SQLWKLD('MYWORKLOAD'); + + + +-- Section 17.2.16 Recommendation Options +----------------------------------------- + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER('MYTASK','STORAGE_CHANGE', 100); + + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + 'MYTASK', 'VALID_TABLE_LIST', 'SH.SALES, SH.CUSTOMERS'); + + +-- clean-up +EXECUTE dbms_advisor.delete_task('MYTASK'); + + + +-- Section 17.2.17 Generating Recommendations +--------------------------------------------- + + +-- Steps 1 through 6 are the required setup steps to be able to execute a +-- task and have some worthwhile data to view after its execution. + +-- Step 1 Prepare the USER_WORKLOAD table + +-- The USER_WORKLOAD table is loaded with SQL statements as follows: + +connect sh/sh; +-- aggregation with selection +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, +'SELECT t.week_ending_day, p.prod_subcategory, + SUM(s.amount_sold) AS dollars, s.channel_id, s.promo_id + FROM sales s, times t, products p WHERE s.time_id = t.time_id + AND s.prod_id = p.prod_id AND s.prod_id > 10 AND s.prod_id < 50 + GROUP BY t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id') +/ + +-- aggregation with selection +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, + 'SELECT t.calendar_month_desc, SUM(s.amount_sold) AS dollars + FROM sales s , times t + WHERE s.time_id = t.time_id + AND s.time_id between TO_DATE(''01-JAN-2000'', ''DD-MON-YYYY'') + AND TO_DATE(''01-JUL-2000'', ''DD-MON-YYYY'') +GROUP BY t.calendar_month_desc') +/ + +--Load all SQL queries. +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, +'SELECT ch.channel_class, c.cust_city, t.calendar_quarter_desc, + SUM(s.amount_sold) sales_amount +FROM sales s, times t, customers c, channels ch +WHERE s.time_id = t.time_id AND s.cust_id = c.cust_id +AND s.channel_id = ch.channel_id AND c.cust_state_province = ''CA'' +AND ch.channel_desc IN (''Internet'',''Catalog'') +AND t.calendar_quarter_desc IN (''1999-Q1'',''1999-Q2'') +GROUP BY ch.channel_class, c.cust_city, t.calendar_quarter_desc') +/ + + +-- order by +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, + 'SELECT c.country_id, c.cust_city, c.cust_last_name +FROM customers c WHERE c.country_id in (''US'', ''UK'') +ORDER BY c.country_id, c.cust_city, c.cust_last_name') +/ +COMMIT; + +connect sh/sh; +set serveroutput on; + +VARIABLE task_id NUMBER; +VARIABLE task_name VARCHAR2(255); +VARIABLE workload_name VARCHAR2(255); +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; + + +-- Step 2 Create a workload named MYWORKLOAD + +EXECUTE :workload_name := 'MYWORKLOAD'; + +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name); + +-- Step 3 Load the workload from user-defined table SH.USER_WORKLOAD + +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_USER (:workload_name, 'APPEND', 'SH', - + 'USER_WORKLOAD', :saved_stmts, :failed_stmts); +PRINT :saved_stmts; +PRINT :failed_stmts; + + +-- Step 4 Create a task named MYTASK + +EXECUTE :task_name := 'MYTASK'; + +EXECUTE DBMS_ADVISOR.CREATE_TASK('SQL Access Advisor', :task_id, :task_name); + +-- Step 5 Set task parameters + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER(:task_name, 'STORAGE_CHANGE', 100); + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :task_name, 'EXECUTION_TYPE', 'INDEX_ONLY'); + +-- Step 6 Create a link between workload and task + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF(:task_name, :workload_name); + + + + + +-- Now execute the task for section 17.2.17.1 + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK('MYTASK'); + + + + +-- Section 17.2.18 Viewing the Recommendations +---------------------------------------------- + + +VARIABLE workload_name VARCHAR2(255); +VARIABLE task_name VARCHAR2(255); +EXECUTE :task_name := 'MYTASK'; +EXECUTE :workload_name := 'MYWORKLOAD'; + +SELECT REC_ID, RANK, BENEFIT +FROM USER_ADVISOR_RECOMMENDATIONS WHERE TASK_NAME = :task_name; + + +SELECT sql_id, rec_id, precost, postcost, + (precost-postcost)*100/precost AS percent_benefit +FROM USER_ADVISOR_SQLA_WK_STMTS +WHERE TASK_NAME = :task_name +order by sql_id; + + + +SELECT 'Action Count', COUNT(DISTINCT action_id) cnt +FROM user_advisor_actions WHERE task_name = :task_name; + + +-- see the actions for each recommendations + +SELECT rec_id, action_id, SUBSTR(command,1,30) AS command +FROM user_advisor_actions WHERE task_name = :task_name +ORDER BY rec_id, action_id; + + +-- The following PL/SQL procedure can be used to print out some of +-- the attributes of the recommendations. + +connect sh/sh; +CREATE OR REPLACE PROCEDURE show_recm (in_task_name IN VARCHAR2) IS +CURSOR curs IS + SELECT DISTINCT action_id, command, attr1, attr2, attr3, attr4 + FROM user_advisor_actions + WHERE task_name = in_task_name + ORDER BY action_id; + v_action number; + v_command VARCHAR2(32); + v_attr1 VARCHAR2(4000); + v_attr2 VARCHAR2(4000); + v_attr3 VARCHAR2(4000); + v_attr4 VARCHAR2(4000); + v_attr5 VARCHAR2(4000); +BEGIN + OPEN curs; + DBMS_OUTPUT.PUT_LINE('========================================='); + DBMS_OUTPUT.PUT_LINE('Task_name = ' || in_task_name); + LOOP + FETCH curs INTO + v_action, v_command, v_attr1, v_attr2, v_attr3, v_attr4 ; + EXIT when curs%NOTFOUND; + DBMS_OUTPUT.PUT_LINE('Action ID: ' || v_action); + DBMS_OUTPUT.PUT_LINE('Command : ' || v_command); + DBMS_OUTPUT.PUT_LINE('Attr1 (name) : ' || SUBSTR(v_attr1,1,30)); + DBMS_OUTPUT.PUT_LINE('Attr2 (tablespace): ' || SUBSTR(v_attr2,1,30)); + DBMS_OUTPUT.PUT_LINE('Attr3 : ' || SUBSTR(v_attr3,1,30)); + DBMS_OUTPUT.PUT_LINE('Attr4 : ' || v_attr4); + DBMS_OUTPUT.PUT_LINE('Attr5 : ' || v_attr5); + DBMS_OUTPUT.PUT_LINE('----------------------------------------'); + END LOOP; + CLOSE curs; + DBMS_OUTPUT.PUT_LINE('=========END RECOMMENDATIONS============'); +END show_recm; +/ + + +-- see what the actions are using sample procedure + +set serveroutput on size 99999 +EXECUTE show_recm(:task_name); + + + +-- Section 17.2.19 Access Advisor Journal +----------------------------------------- + +-- This section moved to the end of section 17.2.28 since +-- it requires the task to be reset. + + + +-- Section 17.2.20 Stopping the recommendation Process +------------------------------------------------------ + + +-- Note, a task must be executing for this to succeed. This +-- testcase just proves the syntax is correct. Expect an error +-- such as "task must be executing to be cancelled". + +EXECUTE DBMS_ADVISOR.CANCEL_TASK('MYTASK'); + + + +-- Section 17.2.21 Marking Recommendations +------------------------------------------ + +EXECUTE DBMS_ADVISOR.MARK_RECOMMENDATION('MYTASK', 2, 'REJECT'); + + + +-- Section 17.2.22 Modifying Recommendations +-------------------------------------------- + +-- Before the TABLESPACE recommendation attribute can be updated, +-- recommendations of the CREATE type must exist. Steps 1 through 6 +-- do the required setup for this. + +-- 1. Create task + +VARIABLE task_id2 NUMBER; +VARIABLE task_name2 VARCHAR2(255); +EXECUTE :task_name2 := 'MYTASK2'; +EXECUTE DBMS_ADVISOR.CREATE_TASK ('SQL Access Advisor', :task_id2, - + :task_name2); + +-- 2. Create workload + +VARIABLE workload_name2 VARCHAR2(255); +EXECUTE :workload_name2 := 'MYWORKLOAD2'; +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name2,'This is my test workload'); + +-- 3. Link workload and task + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF(:task_name2, :workload_name2); + + +-- 4. Add a sql statement to the workload + +VARIABLE sql_text2 VARCHAR2(400); +EXECUTE :sql_text2 := 'SELECT AVG(amount_sold) FROM sales'; +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_STATEMENT ( - + :workload_name2, 'MONTHLY', 'ROLLUP', priority=>1, executions=>10, - + username => 'SH', sql_text => :sql_text2); + + +-- 5. Execute the task + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK(:task_name2); + +-- 6. See the actions recommended + +SELECT rec_id, action_id, SUBSTR(command,1,30) AS command +FROM user_advisor_actions WHERE task_name = :task_name2 +ORDER BY rec_id, action_id; + + + +-- The following example modifies the attribute TABLESPACE for recommendation +-- ID 1, action ID 1 to SH_MVIEWS. + +EXECUTE DBMS_ADVISOR.UPDATE_REC_ATTRIBUTES(:task_name2, 1, 2, 'TABLESPACE', - + 'SH_MVIEWS'); + + + + +-- Section 17.2.23 Generating SQL Scripts +----------------------------------------- + + +-- Define a directory "ADVISOR_RESULTS" and grant permissions to +-- read/write to it. +-- +-- connect sh/sh; +-- CREATE DIRECTORY ADVISOR_RESULTS AS '/mydir'; +-- GRANT READ ON DIRECTORY ADVISOR_RESULTS TO PUBLIC; +-- GRANT WRITE ON DIRECTORY ADVISOR_RESULTS TO PUBLIC; + + +-- save script CLOB to file + + +-- Note: When "get_task_script" passed in as a parameter you get the error +-- 'invalid file script'. This is a problem with how SQLPlus handles +-- CLOBs. Doc changed to call GET_TASK_SCRIPT directly in CREATE_FILE. + +-- generate script as a CLOB +--variable scriptbuf CLOB; +--EXECUTE :scriptbuf := 'DBMS_ADVISOR.GET_TASK_SCRIPT(''MYTASK'')'; + + +-- doesn't work +--EXECUTE DBMS_ADVISOR.CREATE_FILE(:scriptbuf, 'ADVISOR_RESULTS',- +-- 'advscript.sql'); + +-- works +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT('MYTASK'), 'ADVISOR_RESULTS','advscript.sql'); + + + +-- Section 17.2.24 When Recommendations are No Longer Required +-------------------------------------------------------------- + + +EXECUTE DBMS_ADVISOR.RESET_TASK('MYTASK'); + + + +-- Section 17.2.25 Performing a Quick Tune +------------------------------------------ + + +VARIABLE task_name VARCHAR2(255); +VARIABLE sql_stmt VARCHAR2(4000); +EXECUTE :sql_stmt := 'SELECT COUNT(*) FROM customers - + WHERE cust_state_province=''CA'''; +EXECUTE :task_name := 'MY_QUICKTUNE_TASK'; + +EXECUTE DBMS_ADVISOR.QUICK_TUNE(DBMS_ADVISOR.SQLACCESS_ADVISOR, - + :task_name, :sql_stmt); + + + +-- Section 17.2.26.1 Updating Task Attributes +--------------------------------------------- + +EXECUTE DBMS_ADVISOR.UPDATE_TASK_ATTRIBUTES('MYTASK', 'TUNING1'); + + +-- The following example marks the task TUNING1 to read only + +EXECUTE DBMS_ADVISOR.UPDATE_TASK_ATTRIBUTES('TUNING1', read_only => 'TRUE'); + + +-- The following example marks the task MYTASK as a template. + +EXECUTE DBMS_ADVISOR.UPDATE_TASK_ATTRIBUTES('TUNING1', is_template=>'TRUE'); + + + +-- Section 17.2.26.2 Deleting Tasks +----------------------------------- +-- need an existing task to delete, use TUNING1 instead of MYTASK +-- but first make it readable. + +EXECUTE DBMS_ADVISOR.UPDATE_TASK_ATTRIBUTES('TUNING1', read_only => 'FALSE'); + +EXECUTE DBMS_ADVISOR.DELETE_TASK('TUNING1'); + + +------------------------------------------------------------------------- +--Section 17.2.28 Examples of Using the SQLAccess Advisor +------------------------------------------------------------------------- + +-- cleanup from previous example + +EXECUTE DBMS_ADVISOR.DELETE_SQLWKLD('MYWORKLOAD'); + + +-- Section 17.2.28.1 Recommendations From a User-Defined Workload +----------------------------------------------------------------- + +-- The following example imports workload from a user-defined table, +-- SH.USER_WORKLOAD. It then creates a task called MYTASK, sets the +-- storage budget to 100 MB and runs the task. The recommendations +-- are printed out using a PL/SQL procedure. Finally, it generates a +-- script, which can be used to implement the recommendations. + +-- Step 1 Prepare the USER_WORKLOAD table + +-- The USER_WORKLOAD table is loaded with SQL statements as follows: + +connect sh/sh; +-- aggregation with selection +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, +'SELECT t.week_ending_day, p.prod_subcategory, + SUM(s.amount_sold) AS dollars, s.channel_id, s.promo_id + FROM sales s, times t, products p WHERE s.time_id = t.time_id + AND s.prod_id = p.prod_id AND s.prod_id > 10 AND s.prod_id < 50 + GROUP BY t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id') +/ + +-- aggregation with selection +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, + 'SELECT t.calendar_month_desc, SUM(s.amount_sold) AS dollars + FROM sales s , times t + WHERE s.time_id = t.time_id + AND s.time_id between TO_DATE(''01-JAN-2000'', ''DD-MON-YYYY'') + AND TO_DATE(''01-JUL-2000'', ''DD-MON-YYYY'') +GROUP BY t.calendar_month_desc') +/ + +--Load all SQL queries. +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, +'SELECT ch.channel_class, c.cust_city, t.calendar_quarter_desc, + SUM(s.amount_sold) sales_amount +FROM sales s, times t, customers c, channels ch +WHERE s.time_id = t.time_id AND s.cust_id = c.cust_id +AND s.channel_id = ch.channel_id AND c.cust_state_province = ''CA'' +AND ch.channel_desc IN (''Internet'',''Catalog'') +AND t.calendar_quarter_desc IN (''1999-Q1'',''1999-Q2'') +GROUP BY ch.channel_class, c.cust_city, t.calendar_quarter_desc') +/ + +-- order by +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, + 'SELECT c.country_id, c.cust_city, c.cust_last_name +FROM customers c WHERE c.country_id in (''US'', ''UK'') +ORDER BY c.country_id, c.cust_city, c.cust_last_name') +/ +COMMIT; + +connect sh/sh; +set serveroutput on; + +VARIABLE task_id NUMBER; +VARIABLE task_name VARCHAR2(255); +VARIABLE workload_name VARCHAR2(255); +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; + + +EXECUTE :workload_name := 'MYWORKLOAD'; + + +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name); + +-- Step 3 Load the workload from user-defined table SH.USER_WORKLOAD + +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_USER (:workload_name, 'APPEND', 'SH', - + 'USER_WORKLOAD', :saved_stmts, :failed_stmts); +PRINT :saved_stmts; +PRINT :failed_stmts; + +-- Step 4 Create a task named MYTASK + +EXECUTE :task_name := 'MYTASK'; + +EXECUTE DBMS_ADVISOR.CREATE_TASK('SQL Access Advisor', :task_id, :task_name); + +-- Step 5 Set task parameters + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER(:task_name, 'STORAGE_CHANGE', 100); + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :task_name, 'EXECUTION_TYPE', 'INDEX_ONLY'); + +-- Step 6 Create a link between workload and task + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF(:task_name, :workload_name); + +-- Step 7 Execute the task + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK(:task_name); + +-- Step 8 View the recommendations + +-- See the number of recommendations and the status of the task. + +SELECT rec_id, rank, benefit +FROM user_advisor_recommendations WHERE task_name = :task_name +order by rec_id; + + +-- See "Viewing the Recommendations" for further details. + +-- See recommendation for each query. +SELECT sql_id, rec_id, precost, postcost, + (precost-postcost)*100/precost AS percent_benefit +FROM user_advisor_sqla_wk_stmts +WHERE task_name = :task_name +order by sql_id; + +-- See the actions for each recommendations. +SELECT rec_id, action_id, substr(command,1,30) AS command +FROM user_advisor_actions +WHERE task_name = :task_name +ORDER BY rec_id, action_id; + +-- See what the actions are using sample procedure. +SET SERVEROUTPUT ON SIZE 99999 +EXECUTE show_recm(:task_name); + +-- Step 9 Generate a Script to Implement the Recommendations + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT(:task_name),- + 'ADVISOR_RESULTS', 'Example1_script.sql'); + + + +-- Cleanup +EXECUTE dbms_advisor.delete_task(:task_name); +EXECUTE dbms_advisor.delete_sqlwkld(:workload_name); +EXECUTE DBMS_ADVISOR.DELETE_TASK('MY_TEMPLATE'); + + + +-- Section 17.2.28.2 Generate Recommendations Using a Task Template +------------------------------------------------------------------- + +-- The following example creates a template and then uses it to create +-- a task. It then uses this task to generate recommendations from a +-- user-defined table, similar to "Recommendations From a User-Defined +-- Workload". + +connect sh/sh; +VARIABLE template_id NUMBER; +VARIABLE template_name VARCHAR2(255); + + +-- Step 1 Create a template called MY_TEMPLATE + +EXECUTE :template_name := 'MY_TEMPLATE'; + + + +EXECUTE DBMS_ADVISOR.CREATE_TASK ( - + 'SQL Access Advisor',:template_id, :template_name, is_template=>'TRUE'); + +-- Step 2 Set template parameters + +--Set naming conventions for recommended indexes/materialized views. +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'INDEX_NAME_TEMPLATE', 'SH_IDX$$_'); +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'MVIEW_NAME_TEMPLATE', 'SH_MV$$_'); + +--Set default owners for recommended indexes/materialized views. +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'DEF_INDEX_OWNER', 'SH'); +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'DEF_MVIEW_OWNER', 'SH'); + +--Set default tablespace for recommended indexes/materialized views. +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'DEF_INDEX_TABLESPACE', 'SH_INDEXES'); +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'DEF_MVIEW_TABLESPACE', 'SH_MVIEWS'); + +-- Step 3 Create a task using the template + +VARIABLE task_id NUMBER; + +VARIABLE task_name VARCHAR2(255); +EXECUTE :task_name := 'MYTASK'; +EXECUTE DBMS_ADVISOR.CREATE_TASK ( - + 'SQL Access Advisor', :task_id, :task_name, template => 'MY_TEMPLATE'); + +--See the parameter settings for task +SELECT parameter_name, parameter_value +FROM user_advisor_parameters +WHERE task_name = :task_name AND (parameter_name LIKE '%MVIEW%' + OR parameter_name LIKE '%INDEX%') order by 1,2; + +-- Step 4 Create a workload named MYWORKLOAD + +VARIABLE workload_name VARCHAR2(255); + +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; +EXECUTE :workload_name := 'MYWORKLOAD'; +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name); + +-- Step 5 Load the workload from user-defined table SH.USER_WORKLOAD + +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_USER ( - + :workload_name, 'APPEND', 'SH', 'USER_WORKLOAD', :saved_stmts,:failed_stmts); + +-- Step 6 Create a link between the workload and the task + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF(:task_name, :workload_name); + +-- Step 7 Execute the task + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK(:task_name); + + +-- Step 8 Generate a script + + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT(:task_name),- + 'ADVISOR_RESULTS', 'Example2_script.sql'); + + +-- Clean-up + +EXECUTE dbms_advisor.delete_task(:task_name); +EXECUTE dbms_advisor.delete_sqlwkld(:workload_name); + + + + +-- Section 17.2.28.3 Filter a Workload from the SQL Cache +--------------------------------------------------------- + +-- The following example illustrates collection of a workload from a +-- SQL cache. We first load the cache with a bunch of SQL statements. +-- We then setup some filters to pick only a subset of those statements +-- and import them into a SQLAccess Advisor workload. The workload is +-- then used to generate recommendations. + +-- Step 1 Loading the SQL cache + +--The following statements are executed so they will be in the SQL cache: + +CONNECT /AS SYSDBA; + +--Clear any prior contents of the cache. +ALTER SYSTEM FLUSH SHARED_POOL; +connect sh/sh; + + + +SELECT t.calendar_month_desc, SUM(s.amount_sold) AS dollars +FROM sales s, times t WHERE s.time_id = t.time_id +AND s.time_id between TO_DATE('01-JAN-2000', 'DD-MON-YYYY') + AND TO_DATE('01-JUL-2000', 'DD-MON-YYYY') +GROUP BY t.calendar_month_desc +ORDER BY t.calendar_month_desc; + + +-- Order by +SELECT c.country_id, c.cust_city, c.cust_last_name +FROM customers c WHERE c.country_id IN ('US', 'UK') AND ROWNUM<20 +ORDER BY c.country_id, c.cust_city, c.cust_last_name; + +-- Queries to illustrate filtering +connect scott/tiger; +SELECT e.ename, d.dname +FROM emp e, dept d WHERE e.deptno = d.deptno +order by e.ename; + +SELECT COUNT(*) FROM dept; + +connect sh/sh; + +VARIABLE task_id NUMBER; +VARIABLE task_name VARCHAR2(255); +VARIABLE workload_name VARCHAR2(255); +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; + +-- Step 2 Create a workload named MY_CACHE_WORKLOAD + +EXECUTE :workload_name := 'MY_CACHE_WORKLOAD'; + +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name); + +-- Step 3 Set up filters + +--Load only SQL statements containing SH tables + +EXECUTE DBMS_ADVISOR.SET_SQLWKLD_PARAMETER ( - + :workload_name, 'USERNAME_LIST', 'SH'); + +-- Step 4 Load the workload from SQL Cache +-- +-- NOTE: Because the SQL cache contains internal or recursive SQL +-- statements, the failed count is somewhat unpredictable in +-- this context. Therefore, we typically don't pay much +-- attention to its value. A more interesting view of the +-- results occurs in the journal, where detail statistics +-- describe the filtering results. + +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_SQLCACHE ( - + :workload_name, 'APPEND', 2, :saved_stmts, :failed_stmts); +PRINT :saved_stmts; + +--See the workload statements in catalog views +--Note, create_date removed from query since results would be non-deterministic +SELECT num_select_stmt +FROM user_advisor_sqlw_sum +WHERE workload_name = :workload_name; + +SELECT sql_id, username, optimizer_cost, SUBSTR(sql_text, 1, 30) +FROM user_advisor_sqlw_stmts +WHERE workload_name = :workload_name +ORDER BY sql_id; + +-- Step 5 Add a single statement to the workload + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_STATEMENT (:workload_name, username => 'SH', - + priority => 1, executions => 10, sql_text => - + 'select count(*) from customers where cust_state_province=''CA'''); + +--Note, create_date removed from query since results would be non-deterministic +SELECT num_select_stmt +FROM user_advisor_sqlw_sum +WHERE workload_name = :workload_name; + +-- Step 6 Update a statement in the workload + +--VARIABLE updated_stmts NUMBER; + +--EXECUTE DBMS_ADVISOR.UPDATE_SQLWKLD_STATEMENT ( - +-- :workload_name, 'executions < 10', :updated_stmts, priority => 3); + +--PRINT :updated_stmts; + +--See that the change has been made. +--SELECT sql_id, username, executions, priority +--FROM user_advisor_sqlw_stmts +--WHERE workload_name = :workload_name +--ORDER BY sql_id; + +-- Step 7 Create a task named MYTASK + +EXECUTE :task_name := 'MYTASK'; + +EXECUTE DBMS_ADVISOR.CREATE_TASK ('SQL Access Advisor', :task_id, :task_name); + +-- Step 8 Create a link between a workload and a task + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF(:task_name, :workload_name); + +-- Step 9 Execute the task + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK(:task_name); + +-- Step 10 Generate a script + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT(:task_name),- + 'ADVISOR_RESULTS', 'Example3_script.sql'); + + + + + +-- Section 17.2.28.4 Evaluate Current Usage of Indexes and Materialized Views +----------------------------------------------------------------------------- + +-- This example illustrates how SQLAccess Advisor may be used to evaluate +-- the utilization of existing indexes and materialized views. We assume +-- the workload is loaded into USER_WORKLOAD table as in "Recommendations +-- From a User-Defined Workload". The indexes and materialized views that +-- are being currently used (by the given workload) will appear as RETAIN +-- actions in the SQLAccess Advisor recommendations. + +connect sh/sh; +VARIABLE task_id NUMBER; +VARIABLE task_name VARCHAR2(255); +VARIABLE workload_name VARCHAR2(255); +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; + + +-- Step 1 Create a workload named WORKLOAD + +EXECUTE :workload_name := 'MYWORKLOAD'; + +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name); + +-- Step 2 Load the workload from user-defined table SH.USER_WORKLOAD + +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_USER ( - + :workload_name, 'APPEND', 'SH','USER_WORKLOAD', :saved_stmts, :failed_stmts); + +PRINT :saved_stmts; +PRINT :failed_stmts; + +-- Step 3 Create a task named MY_EVAL_TASK + +EXECUTE :task_name := 'MY_EVAL_TASK'; + +EXECUTE DBMS_ADVISOR.CREATE_TASK ('SQL Access Advisor', :task_id, :task_name); + +-- Step 4 Create a link between workload and task + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF(:task_name, :workload_name); + +-- Step 5 Set task parameters to indicate EVALUATION ONLY task + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER (:task_name, 'EVALUATION_ONLY', 'TRUE'); + +-- Step 6 Execute the task + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK(:task_name); + +-- Step 7 View evaluation results + +--See the number of recommendations and the status of the task. + +SELECT rec_id, rank, benefit +FROM user_advisor_recommendations WHERE task_name = :task_name; + +--See the actions for each recommendation. +SELECT rec_id, action_id, SUBSTR(command, 1, 30) AS command +FROM user_advisor_actions WHERE task_name = :task_name +ORDER BY rec_id, action_id; + + + + +-- Section 17.2.19 Access Advisor Journal +----------------------------------------- + +-- During the analysis process (execute_task), the Access Advisor will dump +-- useful information regarding the analysis to a journal. The journal can +-- be viewed using the view USER_ADVISOR_JOURNAL. The amount of information +-- output varies depending on the setting of task parameter journaling. + +-- setup, need to reset the task first + +EXECUTE DBMS_ADVISOR.RESET_TASK('MYTASK'); + +-- You can turn journaling off as follows: + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER('MYTASK', 'JOURNALING', 0); + + +-- To view only informational messages: + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER('MYTASK', 'JOURNALING', 4); + + + + +-- Section 17.3 Tuning Materialized Views for Fast Refresh and Query Rewrite +---------------------------------------------------------------------------- + +-- 17.3.1.4 Script Generation DBMS_ADVISOR Function and Procedure +----------------------------------------------------------------- + + +-- Define a directory "TUNE_RESULTS" and grant permissions to +-- read/write to it. + +-- CREATE DIRECTORY TUNE_RESULTS AS '/tmp/script_dir'; +-- GRANT READ, WRITE ON DIRECTORY TUNE_RESULTS TO PUBLIC; + + + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT(:task_name), - + 'TUNE_RESULTS', 'mv_create.sql'); + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT(:task_name, 'UNDO'), 'TUNE_RESULTS', 'mv_undo.sql'); + + + + +-- Example 17-3 Optimizing the Defining Query for Fast Refresh +-------------------------------------------------------------- + +VARIABLE task_cust_mv VARCHAR2(30); +VARIABLE create_mv_ddl VARCHAR2(4000); +EXECUTE :task_cust_mv := 'cust_mv'; +EXECUTE :create_mv_ddl := ' - +CREATE MATERIALIZED VIEW cust_mv - +REFRESH FAST - +DISABLE QUERY REWRITE AS - +SELECT s.prod_id, s.cust_id, SUM(s.amount_sold) sum_amount - +FROM sales s, customers cs - +WHERE s.cust_id = cs.cust_id - +GROUP BY s.prod_id, s.cust_id'; + +EXECUTE DBMS_ADVISOR.TUNE_MVIEW(:task_cust_mv, :create_mv_ddl); + + + +-- Example 17-4 Access IMPLEMENTATION Output Through USER_TUNE_MVIEW View +-------------------------------------------------------------------------- + +SELECT * FROM USER_TUNE_MVIEW +WHERE TASK_NAME= :task_cust_mv AND SCRIPT_TYPE='IMPLEMENTATION' +ORDER BY action_id; + + +-- Example 17-5 Save IMPLEMENTATION Output in a Script File +----------------------------------------------------------- + +-- Define a directory "TUNE_RESULTS" and grant permissions to +-- read/write to it. + +-- CREATE DIRECTORY TUNE_RESULTS AS '/myscript'; +-- GRANT READ, WRITE ON DIRECTORY TUNE_RESULTS TO PUBLIC; + + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT(:task_cust_mv), - + 'TUNE_RESULTS', 'mv_create.sql'); + + + +-- Example 17-6 Enable Query Rewrite by Creating Multiple Materialized Views +---------------------------------------------------------------------------- + + +EXECUTE :task_cust_mv := 'cust_mv2'; + +EXECUTE :create_mv_ddl := ' - +CREATE MATERIALIZED VIEW cust_mv - +ENABLE QUERY REWRITE AS - +SELECT s.prod_id, s.cust_id, COUNT(*) cnt, SUM(s.amount_sold) sum_amount - +FROM sales s, customers cs, countries cn - +WHERE s.cust_id = cs.cust_id AND cs.country_id = cn.country_id - +AND cn.country_name IN (''USA'',''Canada'') - +GROUP BY s.prod_id, s.cust_id - +UNION - +SELECT s.prod_id, s.cust_id, COUNT(*) cnt, SUM(s.amount_sold) sum_amount - +FROM sales s, customers cs - +WHERE s.cust_id = cs.cust_id AND s.cust_id IN (1005,1010,1012) - +GROUP BY s.prod_id, s.cust_id'; + +EXECUTE DBMS_ADVISOR.TUNE_MVIEW(:task_cust_mv, :create_mv_ddl); + + +-- Example 17-7 Access IMPLEMENTATION Output Through USER_TUNE_MVIEW View +------------------------------------------------------------------------- + +SELECT * FROM USER_TUNE_MVIEW +WHERE TASK_NAME='cust_mv2' AND SCRIPT_TYPE='IMPLEMENTATION' +ORDER BY action_id; + + + +-- Example 17-8 Save IMPLEMENTATION Output in a Script File +----------------------------------------------------------- + +--save CREATE output in a script file + +-- Define a directory "TUNE_RESULTS" and grant permissions to +-- read/write to it. + +-- CREATE DIRECTORY TUNE_RESULTS AS '/tmp/script_dir'; +-- GRANT READ, WRITE ON DIRECTORY TUNE_RESULTS TO PUBLIC; + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT('cust_mv2'),- +'TUNE_RESULTS', 'mv_create2.sql'); + + + +-- Example 17-9 Optimized Sub-Materialized View for Fast Refresh +---------------------------------------------------------------- +EXECUTE :task_cust_mv := 'cust_mv3'; + +EXECUTE :create_mv_ddl := '- +CREATE MATERIALIZED VIEW cust_mv - +REFRESH FAST ON DEMAND - +ENABLE QUERY REWRITE AS - +SELECT s.prod_id, s.cust_id, COUNT(*) cnt, SUM(s.amount_sold) sum_amount - +FROM sales s, customers cs - +WHERE s.cust_id = cs.cust_id AND s.cust_id IN (2005,1020) - +GROUP BY s.prod_id, s.cust_id UNION - +SELECT s.prod_id, s.cust_id, COUNT(*) cnt, SUM(s.amount_sold) sum_amount - +FROM sales s, customers cs - +WHERE s.cust_id = cs.cust_id AND s.cust_id IN (1005,1010,1012) - +GROUP BY s.prod_id, s.cust_id'; + +EXECUTE DBMS_ADVISOR.TUNE_MVIEW(:task_cust_mv, :create_mv_ddl); + + + + +-- Example 17-10 Access IMPLEMENTATION Output Through USER_TUNE_MVIEW View +-------------------------------------------------------------------------- + +-- The following query accesses the IMPLEMENTATION output through +-- USER_TUNE_MVIEW: + +SELECT * FROM USER_TUNE_MVIEW +WHERE TASK_NAME= 'cust_mv3' AND SCRIPT_TYPE='IMPLEMENTATION' +ORDER BY action_id; + + + +-- Example 17-11 Save IMPLEMENTATION Output in a Script File +------------------------------------------------------------ + +-- The following statements save the CREATE output in a script file +-- located at /myscript/mv_create3.sql: + + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT('cust_mv3'), - + 'TUNE_RESULTS', 'mv_create3.sql'); + + +-- 10gR2 enhancements +------------------------------------------------------------ + +variable name varchar2(30); + +EXECUTE :name := 'MYWORKLOAD'; + +-- setup, need to recreate the task first + +EXECUTE DBMS_ADVISOR.DELETE_TASK('%'); +EXECUTE DBMS_ADVISOR.DELETE_SQLWKLD('%'); + +EXECUTE DBMS_ADVISOR.CREATE_TASK('SQL Access Advisor','MYTASK'); +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:name); +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF('MYTASK','MYWORKLOAD'); + +-- Add a special SQL statement that currently produces an +-- exact-text match materialized view + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_STATEMENT ( - + 'MYWORKLOAD', 'MONTHLY', 'ROLLUP', 0,0,0,0,1,0,10,1,SYSDATE,1, - + 'SH', 'SELECT count(count(*)) FROM sales GROUP BY prod_id'); + +-- Disable exact-text match materialized views + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER('MYTASK', 'RECOMMEND_MV_EXACT_TEXT_MATCH', 'TRUE'); + +-- Execute task + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK('MYTASK'); + +-- We should have an exact-text-match MV that matches the special workload +-- statement that we added to the workload. +-- +-- Notice that ATTR5 contains the SELECT statement for the materialized view. +-- For exact-text match situations, ATTR5 will match the original SQL +-- statement from the workload. + +select task_name,command,attr5 from user_advisor_actions; + +-- setup, need to reset the task first + +EXECUTE DBMS_ADVISOR.RESET_TASK('MYTASK'); + +-- Disable exact-text match materialized views + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER('MYTASK', 'RECOMMEND_MV_EXACT_TEXT_MATCH', 'FALSE'); + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK('MYTASK'); + +-- There should be no exact-text-match MV that matches the special workload +-- statement that we added to the workload + +select task_name,command,attr5 from user_advisor_actions; + + + + + diff --git a/anydata.sql b/anydata.sql new file mode 100644 index 0000000..4df76eb --- /dev/null +++ b/anydata.sql @@ -0,0 +1,317 @@ +Rem +Rem $Header: anydata.sql 31-oct-2006.13:41:28 ytsai Exp $ +Rem +Rem anydata.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem anydata.sql - Demonstrates Sys.AnyData feature. +Rem +Rem DESCRIPTION +Rem Sys.AnyData stores contains Type description as wells as +Rem a value . This demo shows its usage . +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ytsai 10/31/06 - fix connect +Rem sjanardh 05/02/01 - Merged sjanardh_trans_adddemo +Rem sjanardh 04/30/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +CONNECT system/manager; +GRANT CONNECT,RESOURCE,DBA TO ANYDATA_USER IDENTIFIED BY ANYDATA_USER ; +GRANT READ ON DIRECTORY GPFSD1 TO ANYDATA_USER WITH GRANT OPTION ; +CONNECT ANYDATA_USER/ANYDATA_USER + +SET ECHO ON +SET SERVEROUTPUT ON SIZE 200000 + +--*********************************************************** +-- This demonstrates the usage of Sys.AnyData +--*********************************************************** + +create type person_type as object ( +ssn number , +name varchar2(20), +job char(10) , +salary number(10,4) +); +/ +create type phone_list as varray(100) of number ; +/ +create type date_list as table of date; +/ +create table anydata_tab (col1 number , col2 Sys.AnyData ) ; + +--*********************************************************** +-- Creating AnyData type at one go using Convert functions +--*********************************************************** + +insert into anydata_tab values (10,Sys.AnyData.ConvertNumber(100.101)) ; +insert into anydata_tab values (20,Sys.AnyData.ConvertDate('01-JAN-1901')); +insert into anydata_tab values (30,Sys.AnyData.ConvertChar('thirty')) ; +insert into anydata_tab values (40,Sys.AnyData.ConvertVarchar('forty')) ; +insert into anydata_tab values (50,Sys.AnyData.ConvertVarchar2('fifty')); +insert into anydata_tab values (60,Sys.AnyData.ConvertRaw(utl_raw.cast_to_raw('0908FFGGA')) ); + +--Cannot insert an AnyData of lob type into a table . +insert into anydata_tab values (70,Sys.AnyData.ConvertBlob(to_blob('AABB98076'))) ; +insert into anydata_tab values (80,Sys.AnyData.ConvertClob('eighty') ) ; + + +insert into anydata_tab values (90,Sys.AnyData.ConvertBfile(BFILENAME('GPFSD1', 'gpfdf1.dat'))); +insert into anydata_tab values (100, + Sys.AnyData.ConvertObject(Person_Type(123456767,'Harry','Manager',1500.0909))); + +insert into anydata_tab values (110, + Sys.AnyData.ConvertCollection(phone_list(9774567878,4075689000,1238761020))); + +insert into anydata_tab values (120, + Sys.AnyData.ConvertCollection(date_list('01-JAN-1910','02-FEB-1920','03-MAR-1930')) ); + +commit ; + +--*********************************************************** +-- Procedures to display AnyData information. +--*********************************************************** + +--Procedure takes in two parameters , first is an AnyData , second +--is a number to indicate whether it has to be described piecewise +--or not . + +create or replace procedure display_anydata_value( ad in sys.AnyData,piece_wise in number ) as +an sys.AnyType ; +ad2 sys.AnyData ; +type_code pls_integer ; +type_name varchar2(30); +rtn_val pls_integer ; +n1 number ; +fl1 number(10,4) ; +vc1 varchar(10) ; +vc2 varchar2(30); +ch1 char(10) ; +d1 date ; +rw1 raw(10) ; +bl1 blob ; +cl1 clob ; +bf1 bfile ; +ob1 person_type ; +vry1 phone_list ; +nstd1 date_list ; +begin + +type_code := ad.GetType(an) ; +type_name := ad.GetTypeName() ; + +if (type_code = DBMS_TYPES.TYPECODE_NUMBER) then +begin + rtn_val := ad.GetNumber(n1) ; + dbms_output.put_line (' NUMBER : ' || n1) ; +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_VARCHAR) then +begin + rtn_val := ad.GetVarchar(vc1) ; + dbms_output.put_line (' VARCHAR : ' || vc1) ; +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_VARCHAR2) then +begin + rtn_val := ad.GetVarchar2(vc2) ; + dbms_output.put_line (' VARCHAR2 : ' || vc2) ; +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_CHAR) then +begin + rtn_val := ad.GetChar(ch1) ; + dbms_output.put_line (' CHAR : ' || ch1) ; +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_DATE) then +begin + rtn_val := ad.GetDate(d1) ; + dbms_output.put_line (' DATE : ' || d1 ) ; +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_RAW) then +begin + rtn_val := ad.GetRaw(rw1); + dbms_output.put_line (' RAW : ' || rw1 ) ; +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_BLOB) then +begin + rtn_val := ad.GetBlob(bl1); + dbms_output.put_line (' BLOB : ' || dbms_lob.substr(bl1) ); +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_CLOB) then +begin + rtn_val := ad.GetClob(cl1); + dbms_output.put_line (' CLOB : ' || dbms_lob.substr(cl1) ); +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_BFILE) then +declare + amt pls_integer ; + offset pls_integer := 1 ; + bff raw(100) ; +begin + + rtn_val := ad.GetBfile(bf1); + dbms_lob.fileopen(bf1,dbms_lob.file_readonly); + amt := dbms_lob.getlength(bf1) ; + dbms_lob.read(bf1,amt,offset,bff); + dbms_output.put_line (' BFILE : ' || utl_raw.cast_to_varchar2(bff) ); + dbms_lob.filecloseall; +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_OBJECT) then +begin + type_name := ad.GetTypeName() ; + if(type_name like '%PERSON_TYPE%' ) then + begin + if(piece_wise = 0 ) then + begin + dbms_output.put_line(' Accessing the whole ADT1 ' ) ; + rtn_val := ad.GetObject(ob1) ; + dbms_output.put_line('ADT1: ' || ob1.ssn || ' ' || ob1.name || + ' ' || ob1.job || ' ' || ob1.salary ) ; + end ; + elsif (piece_wise =1 ) then + begin + dbms_output.put_line(' Accessing ADT1 Piecewise ' ); + ad2 := ad ; + ad2.PieceWise(); + rtn_val := ad2.GetNumber(n1); + rtn_val := ad2.GetVarChar2(vc2); + rtn_val := ad2.GetChar(ch1); + rtn_val := ad2.GetNumber(fl1); + dbms_output.put_line('ADT1: ' || n1 || ' ' || vc2 || ' ' || + ch1 || ' ' || n1 ); + end ; + end if ; + end ; + end if ; +end ; +elsif (type_code = DBMS_TYPES.TYPECODE_NAMEDCOLLECTION) then +begin + type_name := ad.GetTypeName() ; + if(type_name like '%PHONE_LIST%') then + begin + dbms_output.put_line(' Accessing the whole VARRAY ' ); + rtn_val := ad.GetCollection(vry1); + for i in 1..vry1.count loop + dbms_output.put_line('phone_list(' || i || ') ' || vry1(i) ) ; + end loop ; + end ; + elsif (type_name like '%DATE_LIST%' ) then + begin + dbms_output.put_line(' Accessing the whole Nested Table ' ); + rtn_val := ad.GetCollection(nstd1) ; + for i in 1..nstd1.count loop + dbms_output.put_line(' NSTD1(' || i || ') ' || nstd1(i) ) ; + end loop ; + end ; + end if ; +end ; +end if ; +end ; +/ + +--*********************************************************** +-- Dsiplay AnyData stored in table +--*********************************************************** + +declare +ad Sys.AnyData ; +begin +for i in 1..12 loop + begin + select col2 into ad from anydata_tab where col1=i*10 ; + dbms_output.put_line('************************************') ; + dbms_output.put_line(' Display row ' || i*10 ) ; + dbms_output.put_line('************************************') ; + display_anydata_value(ad,0) ; + exception when others then + dbms_output.put_line(SQLERRM) ; + end ; +end loop ; +end ; +/ + +declare +ad Sys.AnyData ; +begin +select col2 into ad from anydata_tab where col1=100 ; +dbms_output.put_line('************************************') ; +dbms_output.put_line(' Display ADT piecewise ') ; +dbms_output.put_line('************************************') ; +display_anydata_value(ad,1) ; +end ; +/ +--*********************************************************** +-- Create AnyData of LOBs in PL/SQL blocks and display data +--*********************************************************** + +declare +ad sys.anydata ; +begin +ad := Sys.AnyData.ConvertBlob(to_blob('AABB98076')) ; +display_anydata_value(ad,0) ; +end ; +/ + +declare +ad sys.anydata ; +begin +ad := Sys.AnyData.ConvertClob('eighty') ; +display_anydata_value(ad,0) ; +end ; +/ + +--*********************************************************** +-- Create transient AnyData and display its value +--*********************************************************** + +declare +a1 SYS.AnyType; +a2 SYS.AnyType; +ad1 Sys.AnyData; +ad2 Sys.AnyData; +begin +a1 := SYS.AnyType.GetPersistent('ANYDATA_USER','PERSON_TYPE') ; +Sys.AnyData.BeginCreate(a1,ad1) ; +ad1.SetNumber(678905435,FALSE); +ad1.SetVarChar2('Emily',FALSE); +ad1.SetChar('DIRECTOR',FALSE) ; +ad1.SetNumber(1020.20,FALSE); +ad1.EndCreate(); +begin + --Inserting transient type into table not supported. + --This will raise an error . + insert into anydata_tab values (130,ad1) ; +exception when others then + dbms_output.put_line(SQLERRM); +end ; +display_anydata_value(ad1,1) ; +end ; +/ + +CONNECT system/manager; +DROP USER ANYDATA_USER CASCADE ; + +SET SERVEROUTPUT OFF +SET ECHO OFF + diff --git a/anydset.sql b/anydset.sql new file mode 100644 index 0000000..5d9b305 --- /dev/null +++ b/anydset.sql @@ -0,0 +1,246 @@ +Rem +Rem $Header: anydset.sql 31-oct-2006.13:41:39 ytsai Exp $ +Rem +Rem anydset.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem anydset.sql - Demonstrates Sys.AnyDataSet feature . +Rem +Rem DESCRIPTION +Rem Sys.AnyDataSet contains Type description as well as a +Rem set of values . This demo shows its usage. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ytsai 10/31/06 - fix connect +Rem sjanardh 05/02/01 - Merged sjanardh_trans_adddemo +Rem sjanardh 04/30/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +CONNECT system/manager; +DROP USER ANYDSET_USER CASCADE ; +GRANT CONNECT,RESOURCE,DBA TO ANYDSET_USER IDENTIFIED BY ANYDSET_USER ; +CONNECT ANYDSET_USER/ANYDSET_USER + +SET ECHO ON +SET SERVEROUTPUT ON SIZE 200000 + +--*********************************************************** +-- This demonstrates the usage of Sys.AnyDataSet +--*********************************************************** + +create type person_type as object ( +ssn number , +name varchar2(20), +job clob , +salary number(10,4) +); +/ +create type phone_list as varray(100) of number ; +/ +create type address_type as object ( +apt integer , +street char(30) , +state char(2) , +zip number(5) +); +/ +create type address_list as table of address_type ; +/ + +--*********************************************************** +-- Creates Procedure to display AnyDataSet value +--*********************************************************** + +create or replace procedure anydataset_display_value +(anyset in Sys.AnyDataSet ) as +as1 Sys.AnyDataSet ; +tn varchar2(30) ; +tp varchar2(30) ; +ct number ; +rtn_val pls_integer ; +rw1 raw(30); +cl1 clob ; +o1 person_type ; +o2 address_type ; +vr phone_list ; +nt address_list ; +begin + +as1 := anyset ; +tn := as1.GetTypeName() ; +ct := as1.GetCount() ; + +if (tn = 'SYS.RAW' ) then +begin + for i in 1..ct loop + rtn_val := as1.GetInstance(); + rtn_val := as1.GetRaw(rw1); + dbms_output.put_line(rw1); + end loop ; +end ; +elsif (tn = 'SYS.CLOB' ) then +begin + for i in 1..ct loop + rtn_val := as1.GetInstance(); + rtn_val := as1.GetClob(cl1); + if (cl1 is null) then + dbms_output.put_line(' CLOB is NULL ' ); + else + dbms_output.put_line(dbms_lob.substr(cl1)); + end if ; + end loop ; +end ; +elsif (tn like '%PERSON_TYPE%' ) then +begin + for i in 1..ct loop + rtn_val := as1.GetInstance(); + rtn_val := as1.GetObject(o1); + dbms_output.put_line ('PERSON_TYPE ' || o1.ssn || ' ' || o1.name + || ' ' || dbms_lob.substr(o1.job) || ' ' || o1.salary ) ; + end loop ; +end ; +elsif (tn like '%PHONE_LIST%' ) then +begin + for i in 1..ct loop + rtn_val := as1.GetInstance(); + rtn_val := as1.GetCollection(vr); + for j in 1..vr.count loop + dbms_output.put_line ('PHONE_LIST(' || j || ') ' || vr(j) ) ; + end loop ; + end loop ; +end ; +elsif (tn like '%ADDRESS_LIST%' ) then +begin + for i in 1..ct loop + rtn_val := as1.GetInstance(); + rtn_val := as1.GetCollection(nt); + for j in 1..nt.count loop + dbms_output.put_line ('ADDRESS_TYPE(' || j || ') ' || nt(j).apt || ' ' || + dbms_lob.substr(nt(j).street) || ' ' || nt(j).state || ' ' || nt(j).zip ) ; + end loop ; + end loop ; +end ; + +end if ; +end ; +/ +show errors + +--*********************************************************** +-- Creates AnyDataSet,sets value and displays the value +--*********************************************************** + +declare +as1 Sys.AnyDataSet; +at1 Sys.AnyType ; +rw1 raw(200) ; +begin +Sys.AnyDataSet.BeginCreate(DBMS_TYPES.TYPECODE_RAW,at1,as1); +for i in 1..30 loop + as1.AddInstance(); + rw1 := utl_raw.cast_to_raw(rpad('0123',i,'0123')) ; + as1.SetRaw(rw1); +end loop ; +as1.EndCreate(); +anydataset_display_value(as1); +end ; +/ + +declare +as1 Sys.AnyDataSet; +at1 Sys.AnyType ; +cl1 clob ; +begin +Sys.AnyDataSet.BeginCreate(DBMS_TYPES.TYPECODE_CLOB,at1,as1); +for i in 1..10 loop + as1.AddInstance(); + cl1 := to_clob(rpad('Clob',i*10,'Clob')) ; + as1.SetClob(cl1) ; +end loop ; +as1.EndCreate(); +anydataset_display_value(as1); +end ; +/ + +declare +as1 Sys.AnyDataSet; +at1 Sys.AnyType ; +begin +at1 := Sys.AnyType.GetPersistent('ANYDSET_USER','PERSON_TYPE') ; +Sys.AnyDataSet.BeginCreate(DBMS_TYPES.TYPECODE_OBJECT,at1,as1); +as1.AddInstance(); +as1.SetObject(Person_type(1237659012,'Betty','HR Manager',80999.00)); +as1.AddInstance(); +as1.SetObject(Person_type(8097659100,'Clark',null,null)); +as1.AddInstance(); +as1.PieceWise() ; +as1.SetNumber(1023040078); +as1.SetVarchar2('James'); +as1.SetClob('ADMINISTRAIVE ASSIST'); +as1.SetNumber(60000.00); +as1.EndCreate(); +anydataset_display_value(as1); +end ; +/ + +declare +as1 Sys.AnyDataSet; +at1 Sys.AnyType ; +begin +at1 := Sys.AnyType.GetPersistent('ANYDSET_USER','PHONE_LIST'); +Sys.AnyDataSet.BeginCreate(DBMS_TYPES.TYPECODE_NAMEDCOLLECTION,at1,as1); +as1.AddInstance(); +as1.SetCollection(PHONE_LIST(8095067000,0012034511,null)); +as1.AddInstance(); +as1.SetCollection(PHONE_LIST(3014556780,9012331099,1003073087,1105067890)); +as1.EndCreate(); +anydataset_display_value(as1); +end ; +/ + +declare +as1 Sys.AnyDataSet; +at1 Sys.AnyType ; +begin +at1 := Sys.AnyType.GetPersistent('ANYDSET_USER','ADDRESS_LIST'); +Sys.AnyDataSet.BeginCreate(DBMS_TYPES.TYPECODE_NAMEDCOLLECTION,at1,as1); +as1.AddInstance(); +as1.SetCollection(ADDRESS_LIST(ADDRESS_TYPE(113,'ABC','MA',90878),ADDRESS_TYPE(45,'DFG','MI',80912)) ); +as1.AddInstance(); +as1.PieceWise(); +as1.SetObject(ADDRESS_TYPE(12,'NBC','TX',10764)); +as1.SetObject(ADDRESS_TYPE(70,'MNS','CA',94067),TRUE) ; +as1.EndCreate(); +anydataset_display_value(as1); +end ; +/ + + +--*********************************************************** +-- Drop objects created , user etc. +--*********************************************************** + +drop type address_list ; +drop type phone_list ; +drop type address_type ; +drop type person_type ; + +CONNECT system/manager; +DROP USER ANYDSET_USER CASCADE ; + +SET SERVEROUTPUT OFF +SET ECHO OFF + diff --git a/anytype.sql b/anytype.sql new file mode 100644 index 0000000..ca34a50 --- /dev/null +++ b/anytype.sql @@ -0,0 +1,421 @@ +Rem +Rem $Header: anytype.sql 31-oct-2006.13:41:17 ytsai Exp $ +Rem +Rem anytype.sql +Rem +Rem Copyright (c) 2001, 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem anytype.sql - Demonstrates Sys.AnyType feature . +Rem +Rem DESCRIPTION +Rem Sys.AnyType stores Type descriptions and this demo +Rem shows its usage . +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ytsai 10/31/06 - fix connect +Rem sjanardh 08/03/01 - Fix CSID part. +Rem sjanardh 05/02/01 - Merged sjanardh_trans_adddemo +Rem sjanardh 05/02/01 - +Rem sjanardh 04/30/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +CONNECT system/manager; +DROP USER ANYTYPE_USER CASCADE ; + +GRANT CONNECT,RESOURCE,DBA TO ANYTYPE_USER IDENTIFIED BY ANYTYPE_USER ; +CONNECT ANYTYPE_USER/ANYTYPE_USER + +SET ECHO ON +SET SERVEROUTPUT ON SIZE 20000 + +--*********************************************************** +-- This demonstrates the usage of Sys.AnyType +--*********************************************************** + +--Creating types required for the demo. + +create type object_type1 as object ( +col1 number , +col2 varchar2(30) , +col3 clob , +col4 raw(10) +); +/ + +create type object_type2 as object ( +col1 number , +col2 blob +); +/ + +create type object_type3 as object ( +col1 char(20), +col2 date +); +/ + +create type object_type4 as object ( +number_col number , +object_col object_type1 +); +/ + +create type varray_type1 as varray(5) of date ; +/ +create type varray_type2 as varray(5) of object_type2 ; +/ + +create type nstd_type1 as table of number ; +/ +create type nstd_type2 as table of object_type4 ; +/ + +--*********************************************************** +--Procedures to display AnyType information. +--*********************************************************** + +create procedure display_anytype_info(an in sys.anytype) as +rtn number ; +pr pls_integer ; +sc pls_integer ; +ln pls_integer ; +cs pls_integer ; +cf pls_integer ; +sch varchar2(30) ; +tn varchar2(30) ; +vr varchar2(30) ; +cn pls_integer ; +csid pls_integer ; +begin + --Get the character set id of database character set . + select nls_charset_id(value) into csid from nls_database_parameters + where parameter='NLS_CHARACTERSET' ; + + rtn := an.GetInfo(pr,sc,ln,cs,cf,sch,tn,vr,cn) ; + + dbms_output.put_line('- Precision ' || pr ) ; + dbms_output.put_line('- Scale ' || sc ) ; + dbms_output.put_line('- Length ' || ln ) ; + if (cs is not null ) then + begin + if (cs = csid ) then + dbms_output.put_line('- CSID is same as db charset id' ) ; + else + dbms_output.put_line('- CSID is not same as db charset id') ; + end if ; + end ; + else + dbms_output.put_line('- CSID is null ' ) ; + end if ; + dbms_output.put_line('- CSFRM ' || cf ) ; + dbms_output.put_line('- Schema ' || sch) ; + dbms_output.put_line('- Type name ' || tn ) ; + dbms_output.put_line('- Version ' || vr ) ; + dbms_output.put_line('- Count ' || cn ) ; +end ; +/ + +create or replace procedure display_attribute_element_info(an1 in sys.anytype) as +an sys.anytype ; +rtn number ; +pos pls_integer ; +pr pls_integer ; +sc pls_integer ; +ln pls_integer ; +cs pls_integer ; +cf pls_integer ; +sch varchar2(20) ; +tn varchar2(20) ; +vr varchar2(30) ; +cn pls_integer ; +name varchar2(30) ; +j number ; +csid pls_integer ; +begin + --Get the character set id of database character set . + select nls_charset_id(value) into csid from nls_database_parameters + where parameter='NLS_CHARACTERSET' ; + + --Get the count , number of elements. + rtn := an1.GetInfo(pr,sc,ln,cs,cf,sch,tn,vr,cn) ; + + --For nested table type count is null. + if (cn is null ) then + cn := 1 ; + end if ; + + for j in 1..cn loop + begin + + --Get attribute element information. + rtn := an1.GetAttreleminfo(j,pr,sc,ln,cs,cf,an,name) ; + + dbms_output.put_line(' -------------------- '); + dbms_output.put_line(' COLUMN ' || name ); + + --Attribute is returned as an AnyType in variable an. + --If it is not null then we want to describe it . + if (an is not null) then + dbms_output.put_line(' - '); + dbms_output.put_line(' desc ' || name ); + --Display information of attribute + display_anytype_info(an) ; + dbms_output.put_line(' - '); + end if ; + + --Rest of the information . + dbms_output.put_line(' Precision ' || pr ) ; + dbms_output.put_line(' Scale ' || sc ) ; + dbms_output.put_line(' Length ' || ln ) ; + if (cs is not null ) then + begin + if (cs = csid ) then + dbms_output.put_line('- CSID is same as db charset id' ) ; + else + dbms_output.put_line('- CSID is not same as db charset id') ; + end if ; + end ; + else + dbms_output.put_line('- CSID is null ' ) ; + end if ; + dbms_output.put_line(' CSFRM ' || cf ) ; + dbms_output.put_line(' -------------------- '); + + exception + when others then + dbms_output.put_line(SQLERRM); + end ; + end loop ; +end ; +/ + + +--*********************************************************** +-- The following blocks show how to create AnyTypes from +-- from persistent database types . +--*********************************************************** + +--For object_type1 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE1'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE1'); + display_attribute_element_info(any_type1); +end ; +/ + +--For object_type2 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE2'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE2'); + display_attribute_element_info(any_type1); +end ; +/ + +--For object_type3 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE3'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE3'); + display_attribute_element_info(any_type1); +end ; +/ + +--For object_type4 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE4'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE4'); + display_attribute_element_info(any_type1); +end ; +/ + +--For varray_type1 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','VARRAY_TYPE1'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','VARRAY_TYPE1'); + display_attribute_element_info(any_type1); +end ; +/ + +--For varray_type2 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','VARRAY_TYPE2'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','VARRAY_TYPE2'); + display_attribute_element_info(any_type1); +end ; +/ + +--For nstd_type1 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','NSTD_TYPE1'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','NSTD_TYPE1'); + display_attribute_element_info(any_type1); +end ; +/ + +--For nstd_type1 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','NSTD_TYPE2'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','NSTD_TYPE2'); + display_attribute_element_info(any_type1); +end ; +/ + +--*********************************************************** +-- Create Transient AnyTypes in PL/SQL blocks . +--*********************************************************** + +--Transient AnytType of Date . +declare +an1 sys.anytype ; +begin + Sys.AnyType.BeginCreate(DBMS_TYPES.TYPECODE_DATE,an1) ; + an1.SetInfo(null,null,null,null,null,null,null); + an1.EndCreate() ; + display_anytype_info(an1); +end ; +/ + +--Transient AnytType of Varchar. +declare +an1 sys.anytype ; +begin + Sys.AnyType.BeginCreate(DBMS_TYPES.TYPECODE_VARCHAR,an1) ; + an1.SetInfo(null,null,20,null,null,null,null); + an1.EndCreate() ; + display_anytype_info(an1); +end ; +/ + +--Transient AnytType of Object type. +declare +an2 Sys.AnyType ; +begin + Sys.AnyType.BeginCreate(DBMS_TYPES.TYPECODE_OBJECT,an2) ; + an2.AddAttr('COL1',DBMS_TYPES.TYPECODE_NUMBER,null,null,null,null,null); + an2.AddAttr('COL2',DBMS_TYPES.TYPECODE_CLOB,null,null,null,null,null); + an2.AddAttr('COL3',DBMS_TYPES.TYPECODE_DATE,null,null,null,null,null); + an2.EndCreate() ; + display_anytype_info(an2); + display_attribute_element_info(an2); +end ; +/ + +--Transient AnytType of Collection type. +declare +an1 Sys.AnyType ; +begin + Sys.AnyType.BeginCreate(DBMS_TYPES.TYPECODE_NAMEDCOLLECTION,an1); + an1.SetInfo(null,null,null,null,null,null,DBMS_TYPES.TYPECODE_RAW,0) ; + an1.EndCreate() ; + display_anytype_info(an1); +end ; +/ + +--Transient AnytType of Persistent types. +declare +an1 Sys.AnyType ; +an2 Sys.AnyType ; +begin + an1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE1'); + Sys.AnyType.BeginCreate(DBMS_TYPES.TYPECODE_NAMEDCOLLECTION,an2); + an2.SetInfo(null,null,null,null,null,an1,DBMS_TYPES.TYPECODE_OBJECT,0); + an2.EndCreate() ; + display_anytype_info(an2); +end ; +/ + +--*********************************************************** +-- Drop all objects created for the demo. +--*********************************************************** + +drop type varray_type1 ; +drop type varray_type2 ; +drop type nstd_type1 ; +drop type nstd_type2 ; +drop type object_type4 ; +drop type object_type3 ; +drop type object_type2 ; +drop type object_type1 ; + +CONNECT system/manager; +DROP USER ANYTYPE_USER CASCADE ; + +set serveroutput off +set echo off + + diff --git a/aqbzdemo.tar b/aqbzdemo.tar new file mode 100644 index 0000000000000000000000000000000000000000..77bcf2f9d5510cc6c86619c00f9f13144b411051 GIT binary patch literal 72704 zcmeHwd0!hx)^7f#KShl)H{b-cu}y4XMu2Q90|+BIiRZrer(a8IpdBq(ErH3*eE0i2 zr>c6<3PSd4C(=x?)LrYTsu-OBFnZhw=_?r!IE{5PB1&2RBv z`}rojo8R5s+{Sx8&uwP6v)^og!ZC$S4}!kiLzlh!^?lF1b;B1!U#@=qTXyJC;-{I3 znN%+E?hF3$%B+9zq4ml3z&z`}v$eZi|Ie^*;_F}kz2-KXwO~*W8a==6_0rfC3m8K- zm(A{M@m!BR|M}fqR?dG8h4Nc@l*?zco4IeMp0@>zOPctTpZ|;Esp4wi^i{`gd(YL_ zP2jLt_1X_?S?rTQxhmQ!s^3M`hTCg)drhww)IP9|)Vsw`zuS4Pe)JuAus`2N>NZ-Q z+Zo)bz-#o;=#$#>K6;Ho-&4(cJE*xI+-5u7^V;28FLngfn%Zzyl=?96240OIQu_yL z_3&Rug^T0z#c}bXQhT$yt_#J$fkMH3kaj=(wdP)Vo&MTt<#p-&ymaYl$N9YDI4qr%@RBPU+dN7}Hy2|>itE)ggKqB*!!y)?L=+)Z66?#|@>6c;6p#Qmi zc2m>;O>hDtC**dsJKzK6oz!FME$P3d=^_13YywSnd!F0(0@c6v;#6L?V!8evv{+%! zcq}XBzgUv*9AA{rRrTF@ad;j;n@>eqN0XuCrPW&;;y?`ozjFmRf|Vk~)LnPbYD&)? z4@l0k0yjPX)^B-Np6Yg@(oY(pb97NGREw&7p)QK&CxxTpSU9LcMU@YKDjrqUnzQ1y zZ(7}Z&#U>(m9w{}hsBGvooDOL%B9~6`oa#a{9L#=dR@54ujR9R({e{&Z1V+B7iPR- z%dh3K&z`+laWZqGuE(76W!VW37{&h|7K!?$*BSUfze8LP{ZDRlYX_Pi$bY#V2!Koc zKVi)l`ItCwSpIADJnjL(HWsIe{G-5(w7g(lOGAO$h$B%W@~H~+X?;y9q!OEvrs70_ z&z^+MIPOKtf``Rdr87sxWx=4|y{X9*)`q0Nq@cSB_A61b*|QaaLY4W%ny`=LUrLh? zZm%W_Fw&}iI@(g7Lo1#gzW|nfGPLzh&`UqO5iYwu$Wn!4z0mW@Zca%4ViGwvBUlf; z4tn})D=Xl6Ef6(aCqsbzv@P4{w%d@!wFFN}>;-{3g3dyfMQIVA-0J!Y1poG+)%R~& zUaisX1cNpyIKbTR4ZL`}dJH%2eXHvVf38{g*s_vST3ttjAna|ocVF{6&^vb;QZR=X zc8JhxbUV%A5_zf#7PW$|ndXz))8}QvI*n{l(VN&Q%DelV~-9e!4+PS+}!MZ*?2LQHY9loG3i!565YGjh5T_7^m0ICV`eo^&Qmvg9E0w~lVpRCf_4_QAg}fDx z*~|(;-iluCP`MqWTVU#dmsi-UD8LN}NCfpj_;Pgid@m5 zW940Upc-yR0f=BJ+RBn&MdcUOfQs;yX$Q)uWbCPcI{ALj?F6ni32baAX-EX>PPeZ} z_5pxvujhf#t9#Q4v})?s5B$2{^85G72XD~y!E115>ne`3qQAUwyiU_{QFHFEL^Zvk zv7-;eW9?}vb)KFZf0o~0{av!clnpJ%dyRmHU3a{e*fAcZt~Pk z-&*k!$79YPUor}xchh5o8|14Do()vD1rsZfA24NN&kNZixr#tbw7&{VBoL?vc^#y^ z*7t!h4^T7nx1FtQc9o}4TR<(PThfHb(1h`PWjt zL+?lTu7Ruj@duW{3_aokqvDBdFBl;jm<4I>UVVy*>v|ihg!x&oqhs)Ba_;sBiqay%M1;Fya8gV7! z*udBk=31BVRUNfF&R6Byg@wA)?728(r+#oPU;Y@UZBc|opS6+02AcWt#@BibwLEi+ zqgwVX#lRaKJb4Hw7Wc9b=_xvfw$j%{>mpJYQaW)6`^xFuRAzPga^Vn|DF5XbX8@WZ z|82q9Py9dfoB7S%ti=E9=680N_Me5X_Gp8oP+yV!cLu9~+X{KtuZwnCE00mO8CG~H zHGM*J&B8XwQflgd7QKUI#+Fi(=;}pb@wMnEmQs_bGrn3)#ZqcAE(zfZek~_&l&^c} zlOg`U?fRX?G5%%{Gx-0Vo$bi~TgU&x|2wyg|9R*dKBe3^{@-o_GEYkT-$HAG*vXsj z&7c(q0v-MflEbyvcBP#BaRWNZ()ru%tMB@CUG2L*!bptE@Qn+fSMMXN9)W`Ei`#06 z(pj`%s?>)A2VO9~_dY-^I1KgR-UEFNoz35O>&6clepU^*Tv3^WVY#qrx9NMOpUFtz z+|yL`dsTR|uKY_yHz2nKSK{V9yGX~T25&5cy|<;M`tJzPL1$?WmVMDi^bukubw7Bq?dXWFx0T|BUFf4i z<*0BB_c)0KGjCM*)Tx}8%O_^lY8bTHYDf~b{NQmD!kWZ#~>ICfbp+7 z*t6ov9`Kmx&HZ7}?Ys1K3p^f%zSvn+;iQTQ$=KmqjFSQzD1!65`sC3qF4mh0i%7S3 zuoNOby3vq;vs@zPtVI2g^PE|MsNm9(Bflz zHGM_BzmVk}ZDwlEuPzE_RkIT-a5*iZ*=pIGvKNkiZMNaj$=eEd?4lP%4hG8%3?x&S)_??e=Ze&nfP+n3`=Ln#a|`xbW-Q# z^WsIJitx-y1SBEk>%}x~+i+iVARa)Mc;RR=0l*`Al^uZsOV( zUagK{Iq5G6g1Oc~5(aqUfN;Wdf5irFM_%NsZi{wC10^t>WBJ#8m1l#nqk{_L%N%1I zVt?l!-%vxCUt(;=1)e+L;pZVyQr6YP5q2eQ0NHxu)@q_kh5s?%pR^C0qw?7q!`L+; z&cq3|^N)YvX)@1&eI)VE8qd6<1OO*9q*dvGH4B6CCHO_~2LuLeBO9)OLlMO%=ssA7 z0<{8Sm^GecjuzH(oZzP0ZK>|%nwj_2+`R8KotW4e?JP){nm0w<$ zPKs(Roc}X*QZAo6D>~X3VQ52f3RRW` zL&f2swUsbHOk(5+;ql-*1M?pX%tIVr@zK0`zQrn&m^{J9#+20G;=2GCF9uA6Ui4AU?cCEWs5jJrp4?%Y9A= z4AFnft}Jv2Gw46EgNFM5?Jb-Ch53OOI*JL6E$ROV{kNMy2)WUMCwX7vx*|GrgKNnL z81WSNX^ikVX}R#MNB5et>bR_I-+WvK~ZCfk_ zn`N?$3fhAX(w+F7Mr+XIEYV3{jBcbrOiyu%Xc*{qhbuN=f|{e6nBZpjCWGY~Vp>M9 z?Rap*Rep;NV8Tq%^yfH^pS_O~c5$!c^$Rcu2f?Sg0%DH)AGWp-6R^DhjXP5ur5(V-E-==|NPYSd}jA~v% zk09!Un;M*IZi00GBhox~N#{x9S;X!h`d$EizzYY+TsvSiZ<*e(DN+~cW!iBH=-?Kv zOJ49i{Bf^JumCZ;0A$H9tV4`)wr$6MrjD+=;6T(FNZa9P-o|Li;AFb+{AhOXI#BX; z29A%)MWQ&&#%ncI(d0Asn|OtH!v2DCs9#S{9RK#29!lxBaE?YA@MVMj$7s3ld@ula zX?+a_J$5>T);6H!&!k+McG%~j&iqu8gVMRhsN|*%anpgv9bxSv z;Q@Qsc@GHro);iBWm;9-TR5Z9-HywZRwv!=ZwkNo$k9tE$)=faT35S)DqH;5_}dIP z4fB*)9;`^TB%x?MX+h+!R<%}z*jdt?^cq~nW0Zw#{^6l z1X6t_(pXzrp$RZG3Xy2X6QqP`l}XB&*G%Va!zvjq2Df;L2|=-UIY-H678Z;h$tLWO z4fr5}tx2?%mW}>|Q!?S0lyFS2K@+D0ze_svn%R>uTgs@Be!`P|pV~{#^x*JcHIS9G zzHLK$2JU5&GdM``#Nepy!5Y&XG~lyf%qRzPBu37N+4%M(*h40#05y1ux^$8BF99r` zk7R#1K=eIT*Y3>?uD}8dAIoJZa>ET$UjS(|&A5mHRsRm?t%?;AY!axKOoOh@n1POB zzzMt$^)ETRb=fa1G;UBx94YjGSiyKT6WioxvrEFY=TSE5Ep8G_3FF1EhbDtkRt-0@ z8Y;DyEd8+Mkd@?mSOZbG9;)tPd^DE%IuRq}fcWyn#+?3RGR*heg%-Z3m(c;h&GCzQaMjx+SgwA&l}bVGVTX@`rQcuu}(yEKJ%L!G?bwIy^Kuyz`+*- zzJt$x`gFE)=5k{TyNP8Td3q~Wic7BpYcPgGmt zByPGsq+2xfo+X9uBjIu3<|qC(I^VSk5a=Gtz04Q3W=MAhu)JlIDoXOp{@T~gr3oW%3Sv$x(6AS zZPw)cSNIZ<>5i1DyLx~7iHcw~R<325b!wOVG!VS2y&p{;1f za>_!!M=I+_bf)XzLdSeT%WCA6ciMI+iq3M4^<5fUVGWM5)bKOO%wm(Hg@J`ekePc1VZ ztTW0^gkqxUap!z|!?BWyV?DEUc#3D13=i%2l8H?`t%%;U<4cS==u-+t=X!FX*fE}5 zD0ynfm(%leZ{3d@LD1UB)dUTVFUx6A0EQDha|`o~&M3%Xf-XowXG>ULs_j9kDu%l8 zc=5l8pX7cu)5G3{22Wen1JnYtH1)u@#eNCReBb;nm(Ha>+96T#7%!C1+G0xfJ!08m z^w7q6gwkJk$;SBowP$!??v~V#4FOl zew1Dopx3k>XzFDf^gg=ma~%T{Vf;M+A5Io(bIVT=Yv4K#oNRi8AT-}^+FPKmyFq^) z83%A96Yzl??m4>zClZ7;)1I=fdpdEqDDp-ZOZ^d1+tBM5-fCy2M0oduw!C~k4uMJ zfL+6v!U@HN_3pV`R06ij$NhYW+xijymRTB8uKg=;FlM0GeaTD-D482mYD~}@W5GsC zvRyz<0s`ZrUbpA}u9ZQAS;(x#Vh>^A#Qqj7+i3r`Sv`(KbQtvVx=FG7LGc6sdZk0y z^v$=N5I$j5i6V>F(%p+Yj10@%!j|kaoco3nH&<)48wo&joE_eVbSL&P(oLP(LO=$5 zAcjeD%{aFlF=E%ujXHos#4~GnjjY3=|2r?m6MG~mXght~Z?|+SI>$!5K>B^4CDFQv zKuCaK^lX!A<7C0=Na-2l5qV#>YX7>|9b8>=8ogoB`y7!ksKc45i$O;a2~E)4QwfVT zB?f>3lZR|1XISjepIMVOm-^*@y^=kgq5e-0=3@PT=J5a7fj)5Q|MMAk$AtBd(e0-X zg8JXxZP;`07r~zRmlu3c&nq9?`eF3Hn_Dmd@qHd!203A$-u3Jj{^b5YneWwKUjxH> zz2~5jF~(C^wp@PW{h+gvMGm6f=lSgOt-Pvtz;L)7Ull*zsK2W3akDJiIO^Wq_rPoP z)mq~jJXwT39(Cb3Z1j~_(JYu*I5=FeSfDOI55P1x)20cMj^kqG=%S>9;z&&^!bQfI zF2`YiK7Bh8P7h8l?RV4P!#6Yb=wsS&XnZmDIeGioOAHazJdNw~q6*P7YDuE!(kBA5 zhac%-WHP2dQ=PJ9ngQG_4lsT1sP9A95irEz^g?bQOg(0JGXSsM&?+j!Nruuva%Ax( z%V(W`gA)fJGnq%|>ZcZEV;HrW#lfg%l#u&by!Us46TsBq4qkXoeH#1Qx8{u8Z`lY$k= zCzkelJy*&dNBjH|uZ__aV@w5G5nExx-%<&R!w&%Ii{vNotBl z{K5;(YKCCYRkf!Ub+t?-kr6{cx7S=35eMu_DBNJVIgx1G@NpXg%v!4cdum;ozlX2N z?+Pc!hw?-WksHCFlVad2B14r*A)G!Jj$FH$nC1zO|LPgx+d_AVS<>4sE_D>~(t!0y ztQN+2@eIA{b(_6%0u@+rdiUnrznztHu3V)LfVbiAQXgE2HXCaVn8n|%@d4kJ2Ym=* zy2e^6({JBE<0>^<-K*3yEH8qdO*_%PcxeUABe)28O~Nu(?6NfouGjc17*H83v(?5K zJmd=SqnD6v10D6NKr!Blck8v*wkH-kX6ZHFEzQQ04V-kZ%q*r(4YMMPEi(&;5^gQc znaAa3PJ=l|k`lkJAg>;CY=ZthgreZu^ZK&=R>qwgZ1+rtJyuw{!oq8*K2#r>k3mbe zv=%+Xj}8rDJYGe#H|)x$%1jLrKvy(`@{tNj(Hn(!j|A8mV``^X`bHPvd{(=i8$q+ry zWbW?n(s!HCE?s4+7nxs(RaBYfBZ4?Yvm-vjR7y?DJ5`}w8twh_l1`W^$0X~ z?!88sfwp@}|9;30Mnyjs29{y9%I#NFD5D z^kdzw6x5|TLz9A%oC#St)4-)g^z2TnHgty|+n{39<8j>VIMJsm8$TpNL(p}qrRquX zAmOnd(9lgsS<$Y*9je#f%jj~bvzM`u**h#Bzf<+AMz_`N?W@$c4SX&yQ?c2h_)FYv zrp^kd#r>4g_N3HlvHH4vyq}^cRZ10(m||j|nleUqqW;RBRzlUmj(ENOtZH~I*yfsy zYBRr>ep3Is^PBza{nTzY%bMu1-;;m&?HW|Qg`%DPt#F{JZ#{e(4P9CQcL^P(x&-~> zS|M*KSRibQ4S?9cOi6SZ>g#EyzTK2hY6NB+ssR?;vt!8gul2CtO*}HbrYVK7R*EOg z1VvY}5K=UjbC@f8Wsx|PE>t`|m=tFal|6vUbCTnGywn9e(cq+!*a61RUwAbPEu*_N zV})C^9ya}>r_JaAP~C*<3ux?qie)$MJjz|q56dUVGHV+N0T=IZC^67tWcmQ$Zap+X z3Y}79W%pBvmuq$JJ+IU>%a_X|0PrL30=vRq*`c$*0LAPU2&cq76I+uf&p@A`Zy!5+ z+4g7Mabw@kP8|FvUysO@{IL_dq!T)~_P8m*8uYo=`>DgX)oS@HrG74)yv5IW2tx{yt4DNR-%lA#PS2PU@%`E}Y+Ir& zo=jp_^K0+*h5Ds*Tz$O{UDp3mmD0b8`#F%D*B6F79NI52lq|+sXsg?kkg}ni+MSeA z-1A+0BBv{Sqt-ixd_PBeR+>|86OYRnt4J$UK+v8c0@5SApT^Zt7v*0n`;ZP(>Zp8z zZ+`<$2k=Y_(LB^%IGH#=D{l{xsdjA32FCFq06V~V3l~LXhPE#Zbm96+N=Fyi*VWUL z&+Y!YU~cN`YiyC^VECKJVkiLJ5Nfo=naMZ613|A69qe@9iDsUFBDolX7y z;D0)3Ww@YiL7_q?*iRYU*a>LurhXRAZor3N@_FSzkb$$2^q3mo++nwQuixnLzC`?_ z@b*Ift<5%*fpvXSR4K#;3G=(_4iGsCKVOgO*I@^>QIoN}>I4Za;gh+-jg4__*`O`) zORZDUiP%Tv$rBL6jy;)wd_a3W&3sCGXb`GT7*6-Winjt}N(}!?3p5Et)Vn)1sN5Oj;{mv?g?P<7J|)k{s&lUdC?91KF@4utLI) z8@u(LIJL!Y&$Y%a2Twse8A71 z4zes?92YNY;2G@c(95mXEc0H2o_0TsaUQe$wqU7=)tA{lQ-9&I%aRU3O7|`OBUk-N z`CYMCD;*!K{$N{ScRv6fWa6(49>CU&R$swKz_7E^#}^i}!z0A`vE1bJ>bBHyZ5|4> z7B4Ld#n0RYZ5jKXloE581Gz+p~aR!yr&_)_#0*Qct8pZ_v ztN(^Olz3miCKEkzKbppDH8v@>iSQ5%p$awaEX0w}1Oz<<`@O=OU+HFtb14)D+hr!r z(T*!2#TjZ5v&HdF#x93j+)h)4(Ah)S8}cQIpOg*BO(qA}%fyRJYHAN*X%Fmm&&1W& zpns1L!^qIWVsf9xL2fT&>*)uRMgjnsf>Rog3e|La_IUf|$>a`VwXel$J+&v4ZghJ+ z+_FwLMRpYbIjtAe46rp2h3+?Jbb+E0tRh)xf%4QUbZx5|+r?hY=nZaw59uyiiU&;J zt_JQVxo>sd*hJ*m+QS_(1j+quX^;S4*H%yAL;Rgr*C8JSHvJzw@Z2cG$5qq?{ zYMHy_!3&9}o@IE7fr*G#Yzx9pS;QR2QVDK)deZ<>6B&7c8&yctBi?7~q{Cv#X~+1l z=|HnA$#8YcF#>-~?LR6v+yWsVy^Zr^$)|unjlaNilx<0uVHio%Wur!CjBiH*s|ABd6CclW1+!}Jth#$O^BqRF|;YwL?gv(6MO4hALbiB_w zrB-PR4;NEE0jtMJ*(HjDF#e1a8ewYfc>fNN6_B5N^|>ewhFR6*pxEm0n8Kc9kQmZ` zjmwSt?*#TVL5_+-j=He4LF_7qCJPd!vRIS8>Nidgl;HJK3eq7&5*$a&x*Hujl%!IAvM26a+9%#;qVDe!Hh$5)!4`2phQ)jxqni7 zi4zqy62r(gu}?UJNmXW3*m(O7FKy_uA&n8fA4`}2JC|R@V{~x;n`I~Hf9sJK&eKOX zUH^-lUUnt_ACmvUL3k6nfZ_j(|1I^uPY3r(k zGrnu17?(hgenX z@{r1>#yLG$d<4%7+>JQh>mjv?-o?Em@_RV>rz(n`*5Ib*UucFrGwE<-5Si+0W0d5O z;He|i)PLbr1Am4&`xc^3aJQ-^fyAy}{##HWp|L|_l^ zp{Mo)&&d8D`0RVBDHF`lRxk)^$eba$F75Bnx5@Mo{@f>N!t6z7Q+wd#=jdXf4xNs$q|~KF1o1Yw*}1#Rwb6 zX7S#Gx(Df-=vk)6QEE;a0Rej)QBDMm^y!6X2Kta)Hm&#ZNH$k)gow9F53;MtZUR_e=fa~bCUKeQGb`$-0Lj`+`Q_<}FvKWB39PcJZL z{c$rY!tmP&^IOneFf-&oBmmU%-!9@mvw0K$$vmJ>pWf^iV7hR7*rL7q^?eVn;gf1y z{rI=3<1xXkXo;WPq-MUf=Og#OBv)UqOeytEXr4|-;3tzYK=?wmlTGu+Tmy0oRiLCU z0%dLyk#xlbJ#y(5i-#>}gQ_km#R~yV3c4S${~`<$#!4nrG5r{)dt^n%y(&x;#=HZ% zg(kFpa@`3hh48%qitXo;3nM3uBkxg%T!;jy!4ut<3F}M^g`E6SH_m%HG0Z^cM3HBc zt4w|4IPjBHI#0GLzkG??XuM0t3}9^-NT^BIzWOd_U%(*>#y9g4FSgOddAWST8a^(+ zk-LrKxixqhvNZKwtZMwWVRQOr8q4*cx?K8NI=OK3>s$Yc_@4*&GvWVjegE^0;D6rx z%=mxa3HCXVVFd0~SXhZ7Rj5&6Xne07> z$cD;VKOtq0lryPrVoB!UCpU#`)HK;(U8(>r3n2%H}tSBWW&=rSR5MCJsB!5e}JQp!*^G3Ny8)_3J6 zESJoA7>w&j$No+k-Z~sOn7FS-$6MSIY2uK_40&o(GU$i5W%@+Kv7XtQfC?8BAO4F| zAJhA24b!EmqQTV;GX+X&HC*=TwseXlvJ6-xG4tZG7=3XALxW{GkxIy{XteIQK@P%P zCQd1%i{)N8Zi{{|Y!CZh^F9#u^$m13y;1%5FZKRodo~OD{x5_GW_klK{?`k{z2yI= z;i4>#5bPXN28_af@4lW6>KP>MlB`hCWzb6IOemZQv>f`1RowF#sg206S z2U5}dc;lP7YJRrm-m~I46EOwX8ALWRWkB6SiXF@c6S8#EUXc)=4JH@mSd4BivsKuz z{f>yC#-Qi-@7XFZc(Mr-1n@HU#1jiOzR~QpaDG^*_|0OW3q2^QG=Zbq;bGFI*uY>Eotd4oJ)$c-AMShd?kXS6g~FRA!JBA&1^_MhWa!Tz$PH0Osc zgWDLw3`{yi%t#w#{Qw0`p7iBi=DndE`K*g)7#Y_5wPI6ARX3xjXF-{L5wu zc#O~7=;jzeVT5nV4}SPPOl6-GXvPUo;SG0&tM@xjVxUOYSrl)G54hkkya!I$Su4S5 z&Ml49Y?_;8CS3E5Gsh2|jtkRuFng=wRqiEOSP*-;zd0d?xjnaymzdGS&Y5vY#oJ30 z+F|1j^cJWtr;864vGAnH5lOWZvsL>?CS-kCspqRt{v$YNXujT!} zpME0^t^X%s2WRkq+1=c(&i}NzvxOU=DF1Ea>r(&s>6iZ-&{6OQ7B2^qM;Tajn4vJt z9DS*gCsWgs82NpDVQH06u>coL03~ZwjLhmLk+Wd{bY~!WR~wQi?oPTZ2kngseU;`#9T|KIfg$!B-6@Bk6|k8F@j z{_ivFkTL5ITGEe>_X5T+ga1Ryci?*F|J>Zl?~oUS{WnKD@B;dt*~HTRYq&qj?kD!& z*y@YzQ7f9pFeVXq1UVeyz2%WMMtCG?2h3wE!GSyq|Hzle8gl99Gu<^~;#=wOGx=;l z)eyPnO!V2wTW227)`XYOruEB_gXtWV&(4_4a)wz_Tz;^U){jGdXW9)LKyw(G*tG2k zwWE-%zi9mE0AhRZUS9s`wIwsL$yZlkBL27gW&tyrf&a5xyTJ7t|8HhDY5xWO=d%U$ zJ+p}={vU_`?dl7fH2yi(8N>QW^o{OYJ9b7TA=xut4>n^3@!kf_i&-bq!~)|;jqs0r z86p72?a?Acano_c8wu&ulMWjkOh8S%9u2%^tPjR@FB76ZU3c2}UYPc$l_A<>-uyoT zI-Gd^jnZKeE`T%6e|}TP|04f8_#2RUF-V1+fv-gIxvSu`c z@ZmfBSFLb-y1Gs`N%+U%_fg^ESbJ%Un;x48^ZBWlou5Tyn30zCu+ALBS3vBna3~>zH6T(zMP@ zLhzzHGyJq<1`&{pW;sDnJZI&O_j604op`(4r;@b~a0dM1ulBw8FC@}f;YKEuWBm`; zk4A=^G+wMA6Uf-=(MX4Sk6y5H_=}#MHtmR=?hB`QcKpJ@9ao}>m(a}s<;|EUBdhIuDf*FlK6 zizd89{h?v&adD{WmuLD|#Wwa@rTq5dsF;3RL0-$_LbdQr&RhaaBb>pwBZaN_<$7Z- z0;4~!jcQ`=Wa$6dM_$53ko|BVGw45be)j&C9ccb}|4VLXcWM6%;rA)OG(B8V+yf@< z0tG^a6FYKD9}7I+8GV6c{Q_pSE4ZlGdSl23uJEyRgUFaPL-1F)<(SeLIrqIG1h!`4 zb%|E=sDw@=(ZyJ#1Zpx=$`I=jj2AEIHEXdR^>pcb-a(qL%pZZrpSFL(#SoT9&j084 z|ITUqAN;>}xxF54Xk0iJ&fedFFO z>e)Q_AHhIN{J*FLn9`12e{gd+@}X1Llp2qJH3R?Wc8T+i{clI(|LxtS|HtD2Jx2}d z=8Z!xWo7aIh;IZ@-iHn#qjW(#bf8AJ_Cag{mUbB9ppIi=FVa%@N4^Z1`&epXjuz`3 zVZ;t?3;d!i3&TlUkXWwUqL>8eMA77W{MPG2z%bECW%>)Ldj#gKS|r6bL0Lk4!%!^h zU!zd0r+`blhHz^%;2aiQp&#uX@{~qd*Un%#ii|@ycRoA`N{NAgSn!yW>ZaiUxfml< z#dH=ljhJQj>ApE5_&@afnFE#+su943|$P4%~JOwK+e@RNkBn z#Yachc8aG%xY+E|Ckk}gAUo~0hBV$DnllEaS^~fF_=y<&D$bk znUC4vEAJ{byn9tVqapj*kinhInWjw5f!l%=#<&fL(HYf5{xkf4g0?RT&qnxvC%4VK z4nXj^E&6%O2dX~N|L;QShg6U{{%33VGvj}K3G?JBUt#Q%-y+C$+RNp;B?OibSVG{- HgTVg><>h8i literal 0 HcmV?d00001 diff --git a/aqdemo00.sql b/aqdemo00.sql new file mode 100644 index 0000000..2be58ad --- /dev/null +++ b/aqdemo00.sql @@ -0,0 +1,216 @@ +Rem +Rem $Header: aqdemo00.sql 16-nov-2004.15:59:53 rbhyrava Exp $ +Rem +Rem aqdemo01.sql +Rem +Rem Copyright (c) 2000, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqdemo01.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/16/04 - create user +Rem lzhao 06/26/01 - set echo off for aqdemo01, aqdemo03 +Rem rbhyrava 04/29/01 - add comments for aqdemo08, aqdemo09 +Rem rbhyrava 01/26/01 - obselete job_queue_interval +Rem rbhyrava 07/10/00 - Bug - 1319922 +Rem rbhyrava 07/10/00 - Created +Rem +Rem +Rem aqdemo00.sql +Rem +Rem Copyright (c) 2000, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqdemo00.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem +rem NAME +rem aqdemo00.sql +rem +rem DESCRIPTION +rem This set of scripts serve as an example for building an +rem application, using Oracle Advanced Queues, to perform +rem asynchronous database operations. +rem +rem The scripts do the following: +rem +rem aqdemo00 +rem 1) Create aquser as an user of AQ +rem 2) Create tables prog1_processed_data, prog2_processed_data and +rem prog3_processed_data +rem +rem aqdemo01 +rem 1) Create two queue tables - input_queue_table, prop_queue_table +rem 2) Create two queues - input_queue belonging to input_queue_table, +rem prop_queue belonging to prop_queue_table +rem 3) Create two subscribers to input_queue - prog1, prog2 +rem 4) Create one subscribers to input_queue - prog3 at prop_queue +rem 5) Schedule propagation between input_queue and other queues in +rem the database +rem +rem aqdemo02 +rem 1) Enqueue 100 messages into the input_queue +rem +rem aqdemo03 +rem 1) Installs the dequeue procedures +rem +rem aqdemo04 +rem 1) prog3 performs a blocking dequeue from prop_queue. Messages +rem in prop_table were propagated from input_queue. +rem +rem aqdemo05 +rem 1) A listener program listens on input_table and calls +rem prog1 or prog2 to dequeue from input_queue based on the +rem kind of message received. +rem +rem aqdemo06 +rem 1) This script cleans up all the tables, types, queues, +rem queue_tables, users etc. created by +rem aqdemo00 - aqdemo05 +rem +rem aqdemo07 +rem 1) This script demonstates using XMLType queues and +rem dequeue, subscribe using XPATH expressions on XMLType datatype +rem aqdemo07 +rem +rem aqdemo08 +rem 1) This script demonstrates using Server to Server , Email +rem notifications with default presentation of XML presentation +rem Modify email host and sender info before running the demo. +rem aqdemo08 +rem +rem NOTES +rem This file contains the sql script that drives the demo. +rem Before running the demo, add the following lines to +rem your init.ora file: +rem ## compatible can be 8.1.0 or higher +rem compatible = 8.1.0 +rem aq_tm_processes = 1 +rem job_queue_processes = 2 +rem shutdown and restart the database. +rem +rem Run this demo as SYS using SQLPLUS. Just login as SYS +rem in SQLPLUS and type '@aqdemo00'. +rem aqdemo00 calls aqdemo01 and aqdemo03. +rem +rem Log into another SQLPUS session and type '@aqdemo02'. +rem This enqueus 100 messages into input_queue +rem +rem Log into another SQLPLUS session and type '@aqdemo04'. +rem This program blocks on prop_queue for approxmately 2 minutes and +rem dequeues messages. +rem +rem Log into another SQLPLUS session and type '@aqdemo05'. +rem This program listens for approxmately 2 minutes on input_queue +rem and calls the dequeue for prog1 and prog2 appropriately. +rem +rem aqdemo02(enqueue), aqdemo04(blocking dequeue) and +rem aqdemo05(listen) can be run concurrently +rem +rem aqdemo06(cleanup script) has to be run by SYS. +rem Login as SYS in SQLPLUS and type '@aqdemo06'. +rem + +set serveroutput on +set echo on +spool aqdemo00.log +rem ==================================================================== +rem create a queue user +rem ==================================================================== + +drop user aquser cascade ; +create user aquser identified by aquser; +grant connect, resource, aq_administrator_role to aquser; + +grant execute on dbms_aq to aquser +/ +grant execute on dbms_aqadm to aquser +/ +grant execute on dbms_lock to aquser +/ + + +connect aquser/aquser +set serveroutput on +set echo on + +rem ==================================================================== +rem +rem Create a type +rem +rem ==================================================================== + +create type message as object ( + id NUMBER, + city VARCHAR2(30), + priority NUMBER) +/ + +rem ==================================================================== +rem +rem Create the table to store the dequeued data +rem +rem ==================================================================== +drop table prog1_processed_data +/ +drop table prog2_processed_data +/ +drop table prog3_processed_data +/ + +create table prog1_processed_data +( + id NUMBER, + city VARCHAR2(30), + priority NUMBER +) +/ + +create table prog2_processed_data +( + id NUMBER, + city VARCHAR2(30), + priority NUMBER +) +/ + +create table prog3_processed_data +( + id NUMBER, + city VARCHAR2(30), + priority NUMBER +) +/ + +rem ==================================================================== +rem Setup complete +rem ==================================================================== + + +rem Set up queue tables, queues, subscribers etc. +set echo off +@@aqdemo01.sql +rem Load dequeue procedures +set echo off +@@aqdemo03.sql + + + +rem ==================================================================== +rem Setup complete +rem ==================================================================== + +spool off diff --git a/aqdemo01.sql b/aqdemo01.sql new file mode 100644 index 0000000..6c5f5a2 --- /dev/null +++ b/aqdemo01.sql @@ -0,0 +1,374 @@ +Rem +Rem $Header: template.sql 06-feb-96.13:23:14 kosinski Exp $ +Rem +Rem aqdemo01.sql +Rem +Rem Copyright (c) Oracle Corporation 2000. All Rights Reserved. +Rem +Rem NAME +Rem aqdemo01.sql - +Rem +Rem DESCRIPTION +rem This file creates queue tables, queues, subscribers needed for +rem the demo. Propagation is scheduled between input_queue and other +rem queues in the same database +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 07/10/00 - Created - bug :1319922 +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem kmeiyyap 09/15/98 - Created +Rem + +rem Create Queue table, Queues, Subscribers + +connect aquser/aquser +set serveroutput on +set echo on + +rem ============================== +rem Error Handling Routine +rem ============================== + +CREATE or REPLACE PROCEDURE catch_error ( error_code in number, + error_string in varchar2) +AS +BEGIN + dbms_output.put_line('Oracle Server Error = '|| to_char (error_code)); + dbms_output.put_line('Oracle Server Message = '|| error_string); +END; +/ + + + +rem ========================================== +rem Stop Queue input_queue +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Stopping Queue input_queue...'); + dbms_aqadm.stop_queue + ( + queue_name => 'input_queue', + wait => TRUE + ); + + dbms_output.put_line ('Stopped Queue input_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Stop Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + +rem ========================================== +rem Stop Queue prop_queue +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Stopping Queue prop_queue...'); + dbms_aqadm.stop_queue + ( + queue_name => 'prop_queue', + wait => TRUE + ); + + dbms_output.put_line ('Stopped Queue prop_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Stop Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + +rem ========================================== +rem Drop Queue input_queue +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Dropping Queue input_queue...'); + dbms_aqadm.drop_queue + ( + queue_name => 'input_queue' + ); + + dbms_output.put_line ('Dropped Queue input_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Drop Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + + +rem ========================================== +rem Drop Queue prop_queue +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Dropping Queue prop_queue...'); + dbms_aqadm.drop_queue + ( + queue_name => 'prop_queue' + ); + + dbms_output.put_line ('Dropped Queue prop_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Drop Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + +rem ========================================== +rem Drop Input Queue Table +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Dropping Queue Table input_queue_table...'); + dbms_aqadm.drop_queue_table + ( + queue_table => 'input_queue_table', + force => TRUE + ); + + dbms_output.put_line ('Dropped Queue Table input_queue_table.'); + +exception + when others then + catch_error(SQLCODE, 'Drop Queue Table ' || substr(SQLERRM, 1, 256)); + +END; +/ + + +rem ========================================== +rem Drop Prop Queue Table +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Dropping Queue Table prop_queue_table...'); + dbms_aqadm.drop_queue_table + ( + queue_table => 'prop_queue_table', + force => TRUE + ); + + dbms_output.put_line ('Dropped Queue Table prop_queue_table.'); + +exception + when others then + catch_error(SQLCODE, 'Drop Queue Table ' || substr(SQLERRM, 1, 256)); + +END; +/ +rem ========================================== +rem Create a queue table input_queue_table +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Creating Queue Table input_queue_table...'); + + dbms_aqadm.CREATE_queue_table( + queue_table => 'input_queue_table', + multiple_consumers => TRUE, + queue_payload_type => 'message', + compatible => '8.1.3', + comment => 'Creating input queue table'); + + + dbms_output.put_line ('Created Queue Table input_queue_table.'); + +exception + when others then + catch_error(SQLCODE, 'Create Queue Table ' || substr(SQLERRM, 1, 256)); + +END; +/ + +rem ========================================== +rem Create a queue table prop_queue_table +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Creating Queue Table prop_queue_table...'); + + dbms_aqadm.CREATE_queue_table( + queue_table => 'prop_queue_table', + multiple_consumers => TRUE, + queue_payload_type => 'message', + compatible => '8.1.3', + comment => 'Creating prop queue table'); + + dbms_output.put_line ('Created Queue Table prop_queue_table.'); + +exception + when others then + catch_error(SQLCODE, 'Create Queue Table ' || substr(SQLERRM, 1, 256)); + +END; +/ + + +rem ========================================== +rem Create a queue input_queue +rem ========================================== + +DECLARE +BEGIN + + dbms_output.put_line ('Creating Queue input_queue...'); + + dbms_aqadm.CREATE_queue( + queue_name => 'input_queue', + queue_table => 'input_queue_table', + comment => 'Demo Queue'); + + dbms_output.put_line ('Created Queue input_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Create Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + + +rem ========================================== +rem Create a queue prop_queue +rem ========================================== + +DECLARE +BEGIN + + dbms_output.put_line ('Creating Queue prop_queue...'); + + dbms_aqadm.CREATE_queue( + queue_name => 'prop_queue', + queue_table => 'prop_queue_table', + comment => 'Propagation Queue'); + + dbms_output.put_line ('Created Queue prop_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Create Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + +rem ==================================== +rem Start input queue input_queue +rem ==================================== + +DECLARE +BEGIN + + dbms_output.put_line('starting queue input_queue...'); + + dbms_aqadm.start_queue( + queue_name => 'input_queue'); + + dbms_output.put_line ('Started Queue input_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Start Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + + +rem ==================================== +rem Start input queue prop_queue +rem ==================================== + +DECLARE +BEGIN + + dbms_output.put_line('starting Prop queue prop_queue...'); + + dbms_aqadm.start_queue( + queue_name => 'prop_queue'); + + dbms_output.put_line ('Started Queue prop_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Start Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + + +rem ======================================== +rem Create queue subscribers +rem ======================================== + +DECLARE + subscriber sys.aq$_agent; +BEGIN + subscriber := sys.aq$_agent('prog1', NULL, NULL); + dbms_aqadm.add_subscriber( + queue_name => 'input_queue', + subscriber => subscriber); + dbms_output.put_line ('Added subscriber prog1 to input_queue.'); +END; +/ + +DECLARE + subscriber1 sys.aq$_agent; +BEGIN + subscriber1 := sys.aq$_agent('prog2', NULL, NULL); + dbms_aqadm.add_subscriber( + queue_name => 'input_queue', + subscriber => subscriber1, + rule => 'priority > 2'); + dbms_output.put_line ('Added subscriber prog2 to input_queue.'); +END; +/ + +DECLARE + subscriber sys.aq$_agent; +BEGIN + subscriber := sys.aq$_agent('prog3', 'prop_queue', NULL); + dbms_aqadm.add_subscriber( + queue_name => 'input_queue', + subscriber => subscriber, + rule => 'priority = 2'); + dbms_output.put_line ('Added subscriber prog3@prop_queue to input_queue.'); +END; +/ + +rem ======================================== +rem Schedule propagation +rem ======================================== + +DECLARE +BEGIN + + dbms_aqadm.schedule_propagation( + queue_name => 'input_queue', + latency => '10'); + dbms_output.put_line ( + 'Scheduled propagation from input_queue to other queues.'); +END; +/ + +rem ======================================== +rem Setup complete +rem ======================================== diff --git a/aqdemo02.sql b/aqdemo02.sql new file mode 100644 index 0000000..d91f4e0 --- /dev/null +++ b/aqdemo02.sql @@ -0,0 +1,84 @@ +Rem +Rem $Header: template.sql 06-feb-96.13:23:14 kosinski Exp $ +Rem +Rem aqdemo02.sql +Rem +Rem Copyright (c) Oracle Corporation 2000. All Rights Reserved. +Rem +Rem NAME +Rem aqdemo02.sql - +Rem +Rem DESCRIPTION +rem This file loads the enqueue package and enqueues 100 messages +rem (10 messages are enqueued every 3 seconds to a maximum of 100 +rem messages). +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 07/10/00 - Created - bug: 1319922 +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem kmeiyyap 01/27/99 - spool to aqdemo02.log +rem kmeiyyap 09/15/98 - Created +rem +rem +rem + +connect aquser/aquser +set serveroutput on +set echo on +spool aqdemo02.log + +CREATE OR REPLACE PROCEDURE DEMO_ENQUEUE (userinfo message, + priority number) AS + + enq_msgid RAW(16); + eopt dbms_aq.enqueue_options_t; + mprop dbms_aq.message_properties_t; + +BEGIN + mprop.priority := priority; + dbms_aq.enqueue( + queue_name => 'input_queue', + enqueue_options => eopt, + message_properties => mprop, + payload => userinfo, + msgid => enq_msgid); + + commit; + +END demo_enqueue; +/ + +DECLARE + payload message; + city1 varchar2(30) := 'BELMONT'; + city2 varchar2(30) := 'REDWOOD SHORES'; + city3 varchar2(30) := 'SUNNYVALE'; + city4 varchar2(30) := 'BURLINGAME'; + +BEGIN + for i in 1..100 LOOP + IF mod (i, 3) = 0 THEN + payload := message(i, city1, mod(i, 3) + 1); + ELSIF mod(i, 4) = 0 THEN + payload := message(i, city2, mod(i, 3) + 1); + ELSIF mod(i, 2) = 0 THEN + payload := message(i, city3, mod(i, 3) + 1); + ELSE + payload := message(i, city4, mod(i, 3) + 1); + END IF; + + demo_enqueue(payload, (mod(i, 3) + 1)); + + IF mod (i, 10) = 0 THEN + dbms_lock.sleep(3); + END IF; + + END LOOP; +END; +/ + + +spool off diff --git a/aqdemo03.sql b/aqdemo03.sql new file mode 100644 index 0000000..5d76072 --- /dev/null +++ b/aqdemo03.sql @@ -0,0 +1,117 @@ +Rem +Rem $Header: template.sql 06-feb-96.13:23:14 kosinski Exp $ +Rem +Rem aqdemo03.sql +Rem +Rem Copyright (c) Oracle Corporation 2000. All Rights Reserved. +Rem +Rem NAME +Rem aqdemo03.sql - +Rem +Rem DESCRIPTION +rem This file loads the dequeue packages demo_dequeue and +rem demo_prop_dequeue +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 07/10/00 - bug: 1319922 +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem kmeiyyap 10/07/98 - added wait time for dequeue +rem kmeiyyap 09/15/98 - Created +rem + +connect aquser/aquser +set echo on +set serveroutput on + + +CREATE OR REPLACE PROCEDURE DEMO_DEQUEUE(appname varchar2) AS + deq_msgid RAW(16); + dopt dbms_aq.dequeue_options_t; + mprop dbms_aq.message_properties_t; + payload message; + no_messages exception; + pragma exception_init(no_messages, -25228); + +BEGIN + + dopt.consumer_name := appname; + dopt.wait := 30; + dopt.navigation := DBMS_AQ.FIRST_MESSAGE; + + + dbms_aq.dequeue( + queue_name => 'input_queue', + dequeue_options => dopt, + message_properties => mprop, + payload => payload, + msgid => deq_msgid); + + IF appname = 'prog1' THEN + insert into prog1_processed_data + values (payload.id, payload.city, payload.priority); + ELSIF appname = 'prog2' THEN + insert into prog2_processed_data + values (payload.id, payload.city, payload.priority); + END IF; + + commit; + +EXCEPTION + WHEN no_messages THEN + dbms_output.put_line('No more messages in queue '); + commit; + +END demo_dequeue; +/ + +CREATE OR REPLACE PROCEDURE DEMO_PROP_DEQUEUE (appname varchar2) AS + deq_msgid RAW(16); + dopt dbms_aq.dequeue_options_t; + mprop dbms_aq.message_properties_t; + payload message; + no_messages exception; + pragma exception_init(no_messages, -25228); + start_tx NUMBER; + finish_tx NUMBER; + +BEGIN + + dopt.consumer_name := appname; + dopt.wait := DBMS_AQ.NO_WAIT; + dopt.navigation := DBMS_AQ.FIRST_MESSAGE; + + start_tx := dbms_utility.get_time; + LOOP + + BEGIN + finish_tx := dbms_utility.get_time; + IF finish_tx - start_tx > 12000 THEN + exit; + END IF; + + dbms_aq.dequeue( + queue_name => 'prop_queue', + dequeue_options => dopt, + message_properties => mprop, + payload => payload, + msgid => deq_msgid); + + IF appname = 'prog3' THEN + insert into prog3_processed_data + values (payload.id, payload.city, payload.priority); + END IF; + + commit; + + EXCEPTION + WHEN no_messages THEN + null; + END; + + END LOOP; +END demo_prop_dequeue; +/ + diff --git a/aqdemo04.sql b/aqdemo04.sql new file mode 100644 index 0000000..a721222 --- /dev/null +++ b/aqdemo04.sql @@ -0,0 +1,40 @@ +Rem +Rem $Header: aqdemo04.sql 25-sep-2001.11:19:27 lzhao Exp $ +Rem +Rem aqdemo04.sql +Rem +Rem Copyright (c) 2000, 2001, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem aqdemo04.sql - +Rem +Rem DESCRIPTION +rem Dequeue messages by blocking on prop_queue for prog3 for +rem approximately 2 minutes +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem lzhao 09/25/01 - set feedback on +Rem rbhyrava 07/10/00 - bug 1319922 +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem kmeiyyap 01/27/99 - spool to aqdemo04.log +rem kmeiyyap 09/15/98 - Created +rem +set feedback on +connect aquser/aquser +set serveroutput on +set echo on +spool aqdemo04.log + +DECLARE +BEGIN + demo_prop_dequeue('prog3'); +END; +/ + +rem Show the number of messages in prog3_processed_data table +select count(*) from prog3_processed_data; + +spool off diff --git a/aqdemo05.sql b/aqdemo05.sql new file mode 100644 index 0000000..4cd629e --- /dev/null +++ b/aqdemo05.sql @@ -0,0 +1,89 @@ +Rem +Rem $Header: aqdemo05.sql 25-sep-2001.11:19:28 lzhao Exp $ +Rem +Rem aqdemo05.sql +Rem +Rem Copyright (c) 2000, 2001, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem aqdemo05.sql - +Rem +Rem DESCRIPTION +rem Listening on input_queue for messages for +rem agents "prog1" and "prog2" for approximately 2 minutes; +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem lzhao 09/25/01 - set feedback on +Rem rbhyrava 07/10/00 - Bug 1319922 +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem kmeiyyap 01/27/99 - type agent_list_t changed to aq$_agent_list_t +rem kmeiyyap 10/07/98 - Added waiting time for listen +rem kmeiyyap 09/15/98 - Created +rem +set feedback on +connect aquser/aquser +set serveroutput on +set echo on +spool aqdemo05.log + +DECLARE + qlist dbms_aq.aq$_agent_list_t; + agent_w_msg sys.aq$_agent; + start_tx number; + finish_tx number; + listen_timeout exception; + pragma exception_init(listen_timeout, -25254); + +BEGIN + + qlist(0) := sys.aq$_agent('prog1', 'input_queue', NULL); + qlist(1) := sys.aq$_agent('prog2', 'input_queue', NULL); + + dbms_output.put_line ('Listening on input_queue.'); + + start_tx := dbms_utility.get_time; + LOOP + BEGIN + + finish_tx := dbms_utility.get_time; + IF finish_tx - start_tx > 12000 THEN + exit; + END IF; + + DBMS_AQ.LISTEN( + agent_list => qlist, + wait => 30, + agent => agent_w_msg); + + IF agent_w_msg.name = 'PROG1' THEN + demo_dequeue('prog1'); + ELSIF agent_w_msg.name = 'PROG2' THEN + demo_dequeue('prog2'); + END IF; + + EXCEPTION + when listen_timeout THEN + null; + END; + + END LOOP; +END; +/ + +rem show the number of messages in prog1_processed_data table +select count(*) from prog1_processed_data; + +rem show the number of messages in prog2_processed_data table +select count(*) from prog2_processed_data; + + +spool off + + + + + + diff --git a/aqdemo06.sql b/aqdemo06.sql new file mode 100644 index 0000000..c204e50 --- /dev/null +++ b/aqdemo06.sql @@ -0,0 +1,73 @@ +Rem +Rem $Header: template.sql 06-feb-96.13:23:14 kosinski Exp $ +Rem +Rem aqdemo06.sql +Rem +Rem Copyright (c) Oracle Corporation 2000. All Rights Reserved. +Rem +Rem NAME +rem aqdemo06.sql - This script cleans up all the tables, types +rem queues, queue_tables, users etc. created by +rem aqdemo00 - aqdemo05. +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +rem Run this script as SYS using SQLPLUS and type '@aqdemo06'. +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 07/10/00 - Bug 1319922 +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem kmeiyyap 01/27/99 - clean up script for aqdemo +rem kmeiyyap 01/27/99 - Created +rem + +set serveroutput on +set echo on +spool aqdemo06.log + +rem ========================================== +rem Drop Input Queue Table +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Dropping Queue Table input_queue_table...'); + dbms_aqadm.drop_queue_table + ( + queue_table => 'aquser.input_queue_table', + force => TRUE + ); + + dbms_output.put_line ('Dropped Queue Table input_queue_table.'); + +END; +/ + + +rem ========================================== +rem Drop Prop Queue Table +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Dropping Queue Table prop_queue_table...'); + dbms_aqadm.drop_queue_table + ( + queue_table => 'aquser.prop_queue_table', + force => TRUE + ); + + dbms_output.put_line ('Dropped Queue Table prop_queue_table.'); + +END; +/ + +revoke execute on dbms_lock from aquser +/ + +drop user aquser cascade +/ + +spool off diff --git a/aqdemo07.sql b/aqdemo07.sql new file mode 100644 index 0000000..109e234 --- /dev/null +++ b/aqdemo07.sql @@ -0,0 +1,246 @@ +Rem +Rem $Header: aqdemo07.sql 16-nov-2004.16:33:26 rbhyrava Exp $ +Rem +Rem aqdemo07.sql +Rem +Rem Copyright (c) 2001, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqdemo07.sql - +Rem +Rem DESCRIPTION +Rem Demonstrate Enqueue/Dequeue to queues using XMLType +Rem +Rem +Rem NOTES +Rem To create Queue table with ADT containing XmlType : +Rem the database compatility should be 9.0.0 or higher +Rem +Rem Restart the database after adding the following line to init.ora +Rem compatible=9.0.0 +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/16/04 - user +Rem rbhyrava 10/15/03 - +Rem rbhyrava 10/15/03 - sys user +Rem rbhyrava 04/29/01 - Merged rbhyrava_aqxmltype_demos +Rem rbhyrava 04/26/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +set serveroutput on +spool aqdemo07.log + +rem ==================================================================== +rem create a queue user +rem ==================================================================== +CONNECT system/manager; + +CREATE USER aqadmn IDENTIFIED by aqadmn; +CREATE USER aquser IDENTIFIED by aquser; +GRANT CONNECT, RESOURCE, AQ_USER_ROLE TO aquser; +GRANT CONNECT, RESOURCE, AQ_ADMINISTRATOR_ROLE TO aqadmn; + +GRANT EXECUTE ON dbms_aq TO aquser; +GRANT EXECUTE ON dbms_aqadm TO aqadmn ; + +CONNECT aqadmn/aqadmn; +set serveroutput on; + +rem ==================================================================== +rem create a type +rem ==================================================================== + +/* create a message type */ +CREATE OR REPLACE TYPE message AS OBJECT ( + id NUMBER, + data VARCHAR2(30), + myxmldata sys.XMLType) ; +/ + +GRANT EXECUTE ON message TO aquser ; + +rem ==================================================================== +rem create queue table and queue +rem ==================================================================== + +/* create and start a multiple consumer queue */ +BEGIN + DBMS_AQADM.CREATE_QUEUE_TABLE ( + QUEUE_TABLE => 'xmltypemsgqtab', + MULTIPLE_CONSUMERS => TRUE, + QUEUE_PAYLOAD_TYPE => 'message') ; + + DBMS_AQADM.CREATE_QUEUE( + QUEUE_NAME=>'msg_queue', + QUEUE_TABLE =>'xmltypemsgqtab'); + + DBMS_AQADM.START_QUEUE ( QUEUE_NAME => 'msg_queue'); +END; +/ + + +rem ==================================================================== +REM Add rule based subscribers using message selectors +rem ==================================================================== + +BEGIN + -- subscriber - get first three Ranks from each class from the XML message + -- rule based subscription + DBMS_AQADM.ADD_SUBSCRIBER('msg_queue', + SYS.AQ$_AGENT('SUB1', null, null ), + 'XMLType.extract(tab.user_data.myxmldata, + ''/STUDENT/RANK/text()'').getNumberVal() between 1 and 3') ; + + -- another subscriber + DBMS_AQADM.ADD_SUBSCRIBER('msg_queue', + SYS.AQ$_AGENT('SUB2', null, null )) ; + +END; +/ + +REM GRANT ENQUEUE/DEQUEUE privileges to AQUSER on Queue +BEGIN + + dbms_aqadm.grant_queue_privilege('ENQUEUE','msg_queue', 'aquser',FALSE); + dbms_aqadm.grant_queue_privilege('DEQUEUE','msg_queue', 'aquser',FALSE); +END; +/ + +CONNECT aquser/aquser ; +set serveroutput on size 200000; + +REM Do enqueues using XMLType + +CREATE OR REPLACE PROCEDURE MSGENQ(qnm VARCHAR2, + txnno NUMBER, + nmesgs NUMBER) +AS +enq_msgid RAW(16); +eopt dbms_aq.enqueue_options_t; +mprop dbms_aq.message_properties_t; +enq_userdata aqadmn.message; +xd sys.XMLType ; +begin + +FOR i in 1..nmesgs LOOP + mprop.priority := 10*txnno + i; + xd := sys.XMLType.createXML('' || txnno || '' + || i || ''); + + enq_userdata := aqadmn.message( + txnno, 'Class: ' || txnno || ' Rank#: ' || i,xd ); + dbms_aq.enqueue( + queue_name => qnm, + enqueue_options => eopt, + message_properties => mprop, + payload => enq_userdata, + msgid => enq_msgid); +END LOOP; +commit; +END; +/ +SHOW ERRORS + +rem ==================================================================== +REM Enqueue messages +rem ==================================================================== +Rem Now Enqueue some messages +execute MSGENQ('AQADMN.msg_queue', 1, 5); +execute MSGENQ('AQADMN.msg_queue', 2, 6); +execute MSGENQ('AQADMN.msg_queue', 3, 7); +execute MSGENQ('AQADMN.msg_queue', 4, 8); +execute MSGENQ('AQADMN.msg_queue', 5, 9); + + +REM Now dequeue messages for the subscribers + +CREATE OR REPLACE PROCEDURE MSGDEQ(appname varchar2, + qname varchar2, + cond varchar2) AS +dequeue_options dbms_aq.dequeue_options_t; +message_properties dbms_aq.message_properties_t; +message_handle RAW(16); +payload aqadmn.message; + +no_messages exception; + +pragma exception_init (no_messages, -25228); + +BEGIN +dequeue_options.wait := 30; +dequeue_options.navigation := DBMS_AQ.FIRST_MESSAGE; +dequeue_options.consumer_name := appname; + +dbms_output.put_line('\nDequeue from : ' || qname || ' subscriber ' || appname); +if ( cond is not null) then + dbms_output.put_line (' ->Using Dequeue Condition: ' || cond) ; + dequeue_options.deq_condition := cond ; + +dbms_output.put_line('') ; +end if ; + +LOOP + BEGIN + dbms_aq.dequeue(queue_name => qname, + dequeue_options => dequeue_options, + message_properties => message_properties, + payload => payload, + msgid => message_handle); + + dbms_output.put('Id:' || payload.id || ' Data:' || payload.data || ' '); + dbms_output.put_line(' Myxmldata:' || payload.myxmldata.getStringVal()); + dequeue_options.navigation := DBMS_AQ.NEXT_MESSAGE; + END; +END LOOP; +EXCEPTION + WHEN no_messages THEN + dbms_output.put_line ('No more messages'); +END; +/ + +SHOW ERRORS + +rem ==================================================================== +REM Dequeue messages +rem ==================================================================== + +BEGIN + + MSGDEQ('SUB1', 'AQADMN.MSG_QUEUE' , null) ; + + -- Dequeue for messages which has XMLType data matching the condition + -- XML should contain CLASS tag AND CLASS should be in 4 or 5 + -- Specify rule during dequeue + + MSGDEQ('SUB2', 'AQADMN.MSG_QUEUE', + 'XMLType.existsNode(tab.user_data.myxmldata,''/STUDENT/CLASS'')=1 AND ' || + ' XMLType.extract(tab.user_data.myxmldata, ''/STUDENT/CLASS/text()'').getNumberVal() in ( 4, 5)') ; + +END; +/ + +REM =============================================================== +REM CLEANUP QUEUES/USERS +REM =============================================================== + +connect aqadmn/aqadmn +execute dbms_aqadm.stop_queue ('msg_queue') ; +execute dbms_aqadm.drop_queue ('msg_queue') ; +execute dbms_aqadm.drop_queue_table ('xmltypemsgqtab' , TRUE) ; + +DROP TYPE message ; + +CONNECT sys/change_on_install AS SYSDBA; + +drop user aquser cascade ; +drop user aqadmn cascade ; + +spool off diff --git a/aqdemo08.sql b/aqdemo08.sql new file mode 100644 index 0000000..08a5c24 --- /dev/null +++ b/aqdemo08.sql @@ -0,0 +1,575 @@ +Rem +Rem $Header: aqdemo08.sql 16-nov-2004.16:35:23 rbhyrava Exp $ +Rem +Rem aqdemo08.sql +Rem +Rem Copyright (c) 2001, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqdemo08.sql - AQ Notifications Demo +Rem +Rem DESCRIPTION +Rem Make sure the database is started with following parameters +Rem aq_tm_processes =2 +Rem job_queue_processes=2 +Rem compatible=8.1.0 # or above +Rem Modify the email host , port and sendfrom . +Rem Modify the email you@company.com to valid email address +Rem NOTES +Rem This demo does the following +Rem - setup mail server - change mailhost and sender email address +Rem - setup users/queues/queue tables +Rem - Create callback functions used in registration +Rem - Register for event notification for the subscriber ADMIN +Rem - Registrations are added using default presentation +Rem and xml presentation +Rem - Do enqueues +Rem - Verify notifications +Rem - Cleanup +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/16/04 - user +Rem ksurlake 06/10/04 - 3229354: Wait before unregistering +Rem rbhyrava 05/16/01 - fix typo / +Rem rbhyrava 04/29/01 - Merged rbhyrava_aqxmltype_demos +Rem rbhyrava 04/27/01 - Created +Rem + +spool aqdemo08.log +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +CONNECT sys/change_on_install as sysdba; +SET SERVEROUTPUT ON +SET ECHO ON + +Rem set the mailserver etc. +call dbms_aqelm.set_mailhost('youmailhost.company.com'); +call dbms_aqelm.set_mailport(25); +call dbms_aqelm.set_sendfrom('you@company.com'); + +Rem user pubsub1 is used for registering on a queue +DROP USER pubsub1 CASCADE; +CREATE USER pubsub1 IDENTIFIED BY pubsub1; + +Rem grant all the roles to pubsub1 +GRANT connect, resource, dba TO pubsub1; +GRANT aq_administrator_role, aq_user_role TO pubsub1; +GRANT EXECUTE ON dbms_aq TO pubsub1; +GRANT EXECUTE ON dbms_aqadm TO pubsub1; +EXECUTE dbms_aqadm.grant_type_access('pubsub1'); +EXECUTE dbms_aqadm.grant_system_privilege('ENQUEUE_ANY','pubsub1',FALSE); +EXECUTE dbms_aqadm.grant_system_privilege('DEQUEUE_ANY','pubsub1',FALSE); + +CONNECT pubsub1/pubsub1; + +rem stop the adt queue +BEGIN +DBMS_AQADM.STOP_QUEUE('pubsub1.adtevents'); +END; +/ + +rem drop the adt queue +BEGIN +DBMS_AQADM.DROP_QUEUE(QUEUE_NAME=>'pubsub1.adtevents'); +END; +/ + +rem drop the adt queue table +BEGIN +DBMS_AQADM.DROP_QUEUE_TABLE(QUEUE_TABLE => 'pubsub1.adt_msg_table', force => TRUE); +END; +/ + +rem create the adt +CREATE OR REPLACE TYPE adtmsg AS OBJECT (id NUMBER, data VARCHAR2(4000)) ; +/ + +rem create the raw queue table +BEGIN +DBMS_AQADM.CREATE_QUEUE_TABLE( + QUEUE_TABLE=>'pubsub1.raw_msg_table', + MULTIPLE_CONSUMERS => TRUE, + QUEUE_PAYLOAD_TYPE =>'RAW', + COMPATIBLE => '8.1.3'); +END; +/ + +rem creat the adt queue table +BEGIN +DBMS_AQADM.CREATE_QUEUE_TABLE( + QUEUE_TABLE=>'pubsub1.adt_msg_table', + MULTIPLE_CONSUMERS => TRUE, + QUEUE_PAYLOAD_TYPE =>'ADTMSG', + COMPATIBLE => '8.1.3'); +END; +/ +rem Create a queue for raw events +BEGIN +DBMS_AQADM.CREATE_QUEUE(QUEUE_NAME=>'pubsub1.events', + QUEUE_TABLE=>'pubsub1.raw_msg_table', + COMMENT=>'Q for events triggers'); +END; +/ + +rem Create a queue for adt events +BEGIN +DBMS_AQADM.CREATE_QUEUE(QUEUE_NAME=>'pubsub1.adtevents', + QUEUE_TABLE=>'pubsub1.adt_msg_table', + COMMENT=>'Q for adt events triggers'); +END; +/ + +rem start the queues +BEGIN +DBMS_AQADM.START_QUEUE('pubsub1.events'); +END; +/ + +BEGIN +DBMS_AQADM.START_QUEUE('pubsub1.adtevents'); +END; +/ +rem Create a non-persistent queue for events +BEGIN + DBMS_AQADM.CREATE_NP_QUEUE(QUEUE_NAME=>'pubsub1.nonperevents', + MULTIPLE_CONSUMERS => TRUE); +END; +/ + +rem start the np queue +BEGIN +DBMS_AQADM.START_QUEUE('pubsub1.nonperevents'); +END; +/ + +rem procedure to enqueue raw into persistent queue +CREATE OR REPLACE PROCEDURE new_rawenqueue(queue_name IN VARCHAR2, + correlation IN VARCHAR2 := NULL, + exception_queue IN VARCHAR2 := NULL) +AS + +enq_ct dbms_aq.enqueue_options_t; +msg_prop dbms_aq.message_properties_t; +enq_msgid RAW(16); +userdata RAW(1000); + +BEGIN + msg_prop.exception_queue := exception_queue; + msg_prop.correlation := correlation; + userdata := hextoraw('666'); + + DBMS_AQ.ENQUEUE(queue_name, enq_ct, msg_prop, userdata, enq_msgid); +END; +/ +GRANT EXECUTE ON new_rawenqueue TO PUBLIC; + +rem procedure to enqueue adt into persistent queue +CREATE OR REPLACE PROCEDURE new_adtenqueue(queue_name IN VARCHAR2, + correlation IN VARCHAR2 := NULL, + exception_queue IN VARCHAR2 := NULL) +AS + +enq_ct dbms_aq.enqueue_options_t; +msg_prop dbms_aq.message_properties_t; +enq_msgid raw(16); +payload adtmsg; + +BEGIN + msg_prop.exception_queue := exception_queue; + msg_prop.correlation := correlation; + payload := adtmsg(1, 'p queue Hello World!'); + + DBMS_AQ.ENQUEUE(queue_name, enq_ct, msg_prop, payload, enq_msgid); +END; +/ +GRANT EXECUTE ON new_adtenqueue TO PUBLIC; + +rem create procedure to enqueue raw into np queue +CREATE OR REPLACE PROCEDURE new_np_rawenqueue(queue VARCHAR2, + id INTEGER, + correlation VARCHAR2) +AS + +msgprop dbms_aq.message_properties_t; +enqopt dbms_aq.enqueue_options_t; +enq_msgid RAW(16); +payload RAW(10); + +BEGIN + payload := hextoraw('999'); + enqopt.visibility:=dbms_aq.IMMEDIATE; + msgprop.correlation:=correlation; + DBMS_AQ.ENQUEUE( queue, enqopt, msgprop, payload, enq_msgid); +END; +/ +GRANT EXECUTE ON new_np_rawenqueue TO PUBLIC; + +rem create procedure to enqueue adt into np queue +CREATE OR REPLACE PROCEDURE new_np_adtenqueue(queue VARCHAR2, + id INTEGER, + correlation VARCHAR2) +AS + +msgprop dbms_aq.message_properties_t; +enqopt dbms_aq.enqueue_options_t; +enq_msgid raw(16); +payload adtmsg; + +BEGIN + payload := adtmsg(1, 'np queue Hello World!'); + enqopt.visibility:=dbms_aq.IMMEDIATE; + msgprop.correlation:=correlation; + DBMS_AQ.ENQUEUE( queue, enqopt, msgprop, payload, enq_msgid); +END; +/ +GRANT EXECUTE ON new_np_adtenqueue TO PUBLIC; + +DECLARE + subscriber sys.aq$_agent; + +BEGIN + + subscriber := sys.aq$_agent('admin', null, null); + + dbms_aqadm.add_subscriber(queue_name => 'pubsub1.events', + subscriber => subscriber); + + dbms_aqadm.add_subscriber(queue_name => 'pubsub1.adtevents', + subscriber => subscriber); + + dbms_aqadm.add_subscriber(queue_name => 'pubsub1.nonperevents', + subscriber => subscriber); + +END; +/ + +SET ECHO ON; +CONNECT / as sysdba; +set serveroutput on; + +DROP TABLE plsqlregtr; +CREATE TABLE plsqlregtr +( + descr sys.aq$_descriptor, + reginfo sys.aq$_reg_info, + payload RAW(2000), + payloadl NUMBER +); + +GRANT ALL ON plsqlregtr TO PUBLIC; + +DROP TABLE plsqlregta; +CREATE TABLE plsqlregta +( + descr sys.aq$_descriptor, + reginfo sys.aq$_reg_info, + payload VARCHAR2(4000), + payloadl NUMBER +); + +GRANT ALL ON plsqlregta TO PUBLIC; + +CONNECT pubsub1/pubsub1 + +CREATE OR REPLACE PROCEDURE plsqlregproc1( + context RAW , reginfo sys.aq$_reg_info, descr sys.aq$_descriptor, + payload RAW, payloadl NUMBER) +AS +BEGIN + INSERT INTO sys.plsqlregtr (descr, reginfo, payload, payloadl) + VALUES (descr, reginfo, payload, payloadl); +END; +/ + +CREATE OR REPLACE PROCEDURE plsqlregproc2( + context RAW , reginfo sys.aq$_reg_info, descr sys.aq$_descriptor, + payload VARCHAR2, payloadl NUMBER) +AS +BEGIN + INSERT INTO sys.plsqlregta (descr, reginfo, payload, payloadl) + VALUES (descr, reginfo, payload, payloadl); +END; +/ +rem Do all the registerations +SET ECHO ON; +CONNECT pubsub1/pubsub1; +SET SERVEROUTPUT ON; + +DECLARE + + reginfo1 sys.aq$_reg_info; + reginfo2 sys.aq$_reg_info; + reginfo3 sys.aq$_reg_info; + reginfo4 sys.aq$_reg_info; + reginfo5 sys.aq$_reg_info; + reginfo6 sys.aq$_reg_info; + reginfolist sys.aq$_reg_info_list; + +BEGIN +-- register for p raw q default pres + reginfo1 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'plsql://plsqlregproc1',HEXTORAW('FF')); + +-- register for p raw q xml pres + reginfo2 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'plsql://plsqlregproc1?PR=1',HEXTORAW('FF')); + +-- register for p adt q default pres + reginfo3 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'plsql://plsqlregproc2',HEXTORAW('FF')); + +-- register for p adt q xml pres + reginfo4 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'plsql://plsqlregproc2?PR=1',HEXTORAW('FF')); + +-- for np q raw and adt can be enqueued into the same queue +-- register for np raw and adt q default pres + reginfo5 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'plsql://plsqlregproc1',HEXTORAW('FF')); + +-- register for np raw and adt q xml pres + reginfo6 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'plsql://plsqlregproc2?PR=1',HEXTORAW('FF')); + + reginfolist := sys.aq$_reg_info_list(reginfo1); + reginfolist.EXTEND; + reginfolist(2) := reginfo2; + reginfolist.EXTEND; + reginfolist(3) := reginfo3; + reginfolist.EXTEND; + reginfolist(4) := reginfo4; + reginfolist.EXTEND; + reginfolist(5) := reginfo5; + reginfolist.EXTEND; + reginfolist(6) := reginfo6; + + sys.dbms_aq.register(reginfolist, 6); + + commit; + +-- registerations are done + +END; +/ + +Rem Do all the registerations +CONNECT pubsub1/pubsub1; +SET ECHO ON; +SET SERVEROUTPUT ON; + +DECLARE + + reginfo1 sys.aq$_reg_info; + reginfo2 sys.aq$_reg_info; + reginfo3 sys.aq$_reg_info; + reginfo4 sys.aq$_reg_info; + reginfo5 sys.aq$_reg_info; + reginfo6 sys.aq$_reg_info; + reginfolist sys.aq$_reg_info_list; + +BEGIN +-- register for p raw q default pres + reginfo1 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'mailto://you@company.com',HEXTORAW('FF')); + +-- register for p raw q xml pres + reginfo2 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'mailto://you@company.com?PR=1',HEXTORAW('FF')); + +-- register for p adt q default pres + reginfo3 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'mailto://you@company.com',HEXTORAW('FF')); + +-- register for p adt q xml pres + reginfo4 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'mailto://you@company.com?PR=1',HEXTORAW('FF')); + +-- for np q raw and adt can be enqueued into the same queue +-- register for np raw and adt q default pres + reginfo5 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'mailto://you@company.com',HEXTORAW('FF')); + +-- register for np raw and adt q xml pres + reginfo6 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'mailto://you@company.com?PR=1',HEXTORAW('FF')); + + reginfolist := sys.aq$_reg_info_list(reginfo1); + reginfolist.EXTEND; + reginfolist(2) := reginfo2; + reginfolist.EXTEND; + reginfolist(3) := reginfo3; + reginfolist.EXTEND; + reginfolist(4) := reginfo4; + reginfolist.EXTEND; + reginfolist(5) := reginfo5; + reginfolist.EXTEND; + reginfolist(6) := reginfo6; + + sys.dbms_aq.register(reginfolist, 6); + + COMMIT; + +-- registrations are done + +END; +/ +CONNECT pubsub1/pubsub1; +SET ECHO ON; +SET SERVEROUTPUT ON; + +DECLARE +BEGIN +-- wait for registerations to happen +-- dbms_lock.sleep(90); + +-- now start enqueing + +-- raw into p queue + new_rawenqueue('PUBSUB1.EVENTS', 'PR CORRELATION STRING', 'PREQ'); + commit; + +-- adt into p queue + new_adtenqueue('PUBSUB1.ADTEVENTS', 'PA CORRELATION STRING', 'PAEQ'); + commit; + +-- raw into np queue + new_np_rawenqueue('PUBSUB1.NONPEREVENTS', 1, 'NPR CORRELATION STRING'); + commit; + +-- adt into np queue + new_np_adtenqueue('PUBSUB1.NONPEREVENTS', 1, 'NPA CORRELATION STRING'); + commit; + +END; +/ + +DECLARE +BEGIN +-- wait for PL/SQL callbacks to be invoked + dbms_lock.sleep(120); +END; +/ + +set echo on; +CONNECT pubsub1/pubsub1; +SET SERVEROUTPUT ON; + +SELECT count(*) FROM sys.plsqlregtr t; + +SELECT count(*) FROM sys.plsqlregta t; + +REM Do all the unregisterations +CONNECT pubsub1/pubsub1; +SET ECHO ON; +SET SERVEROUTPUT ON; + +DECLARE + + reginfo1 sys.aq$_reg_info; + reginfo2 sys.aq$_reg_info; + reginfo3 sys.aq$_reg_info; + reginfo4 sys.aq$_reg_info; + reginfo5 sys.aq$_reg_info; + reginfo6 sys.aq$_reg_info; + reginfolist sys.aq$_reg_info_list; + +BEGIN +-- register for p raw q default pres + reginfo1 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'plsql://plsqlregproc1',HEXTORAW('FF')); + +-- register for p raw q xml pres + reginfo2 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'plsql://plsqlregproc1?PR=1',HEXTORAW('FF')); + +-- register for p adt q default pres + reginfo3 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'plsql://plsqlregproc2',HEXTORAW('FF')); + +-- register for p adt q xml pres + reginfo4 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'plsql://plsqlregproc2?PR=1',HEXTORAW('FF')); + +-- for np q raw and adt can be enqueued into the same queue +-- register for np raw and adt q default pres + reginfo5 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'plsql://plsqlregproc1',HEXTORAW('FF')); + +-- register for np raw and adt q xml pres + reginfo6 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'plsql://plsqlregproc2?PR=1',HEXTORAW('FF')); + + reginfolist := sys.aq$_reg_info_list(reginfo1); + reginfolist.EXTEND; + reginfolist(2) := reginfo2; + reginfolist.EXTEND; + reginfolist(3) := reginfo3; + reginfolist.EXTEND; + reginfolist(4) := reginfo4; + reginfolist.EXTEND; + reginfolist(5) := reginfo5; + reginfolist.EXTEND; + reginfolist(6) := reginfo6; + + sys.dbms_aq.unregister(reginfolist, 6); + + COMMIT; + +-- unregisterations are done + +END; +/ +REM Do all the unregisterations +CONNECT pubsub1/pubsub1; +SET ECHO ON; +SET SERVEROUTPUT ON; + +DECLARE + + reginfo1 sys.aq$_reg_info; + reginfo2 sys.aq$_reg_info; + reginfo3 sys.aq$_reg_info; + reginfo4 sys.aq$_reg_info; + reginfo5 sys.aq$_reg_info; + reginfo6 sys.aq$_reg_info; + reginfolist sys.aq$_reg_info_list; + +BEGIN +-- register for p raw q default pres + reginfo1 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'mailto://you@company.com',HEXTORAW('FF')); + +-- register for p raw q xml pres + reginfo2 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'mailto://you@company.com?PR=1',HEXTORAW('FF')); + +-- register for p adt q default pres + reginfo3 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'mailto://you@company.com',HEXTORAW('FF')); + +-- register for p adt q xml pres + reginfo4 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'mailto://you@company.com?PR=1',HEXTORAW('FF')); + +-- for np q raw and adt can be enqueued into the same queue +-- register for np raw and adt q default pres + reginfo5 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'mailto://you@company.com',HEXTORAW('FF')); + +-- register for np raw and adt q xml pres + reginfo6 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'mailto://you@company.com?PR=1',HEXTORAW('FF')); + + reginfolist := sys.aq$_reg_info_list(reginfo1); + reginfolist.EXTEND; + reginfolist(2) := reginfo2; + reginfolist.EXTEND; + reginfolist(3) := reginfo3; + reginfolist.EXTEND; + reginfolist(4) := reginfo4; + reginfolist.EXTEND; + reginfolist(5) := reginfo5; + reginfolist.EXTEND; + reginfolist(6) := reginfo6; + + sys.dbms_aq.unregister(reginfolist, 6); + + COMMIT; + +-- unregisterations are done + +END; +/ + + +CONNECT sys/change_on_install as sysdba; + +drop user pubsub1 cascade ; +drop table plsqlregtr ; +drop table plsqlregta ; + +spool off +exit ; diff --git a/aqdemo09.sql b/aqdemo09.sql new file mode 100644 index 0000000..f965be7 --- /dev/null +++ b/aqdemo09.sql @@ -0,0 +1,147 @@ +Rem +Rem $Header: aqdemo09.sql 16-nov-2004.16:37:16 rbhyrava Exp $ +Rem +Rem aqdemo10.sql +Rem +Rem Copyright (c) 2003, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqdemo09.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/16/04 - user +Rem aahluwal 10/17/03 - aahluwal_create_arrenqdeq_demos +Rem aahluwal 10/07/03 - Created +Rem +rem NAME +rem aqdemo09.sql, aqdemo10.sql, aqdemo11.sql, aqdemo12.sql, +rem ociaqarrayenq.c, ociaqarraydeq.c +rem +rem DESCRIPTION +rem This set of scripts serve as an example for building an +rem application, using Oracle Advanced Queues, to perform +rem asynchronous database operations. These examples specifically +rem make use of the array enq/deq interfaces for applications +rem requiring high throughput. +rem +rem The scripts do the following: +rem +rem aqdemo09.sql (Login as SYS, and type '@aqdemo09') +rem 1) Create aquser as an user of AQ +rem 2) Create my_queue AQ queue within my_queue_tab AQ Queue Tab in +rem AQUSER's schema +rem 3) Add a subscriber to my_queue +rem +rem aqdemo10.sql +rem 1) Performs an array enq of a batch of messages into my_queue +rem +rem aqdemo11.sql +rem 1) Performs an array deq of a batch of messages from my_queue +rem +rem ociaqarrayenq.c, ociaqarraydeq.c +rem 1) Perform an array enq and array deq (respectively) on my_queue +rem from the OCI AQ array operations interfaces. +rem +rem aqdemo12.sql (Login as SYS, and type '@aqdemo09') +rem 1) Cleans up all objects +rem +rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + + +set serveroutput on +set echo on +spool aqdemo09.log + +rem ==================================================================== +rem create a queue user +rem ==================================================================== +create user aquser identified by aquser; +grant connect, resource , aq_administrator_role to aquser +/ +grant execute on dbms_aq to aquser +/ +grant execute on dbms_aqadm to aquser +/ + +connect aquser/aquser; + +rem ==================================================================== +rem +rem Create a type message for the payload of the queue. Also create types +rem message_tbl and message_arr which are used for subsequent array +rem operations. +rem +rem ==================================================================== +CREATE OR REPLACE TYPE message as OBJECT ( +data VARCHAR2(10)) ; +/ + +CREATE OR REPLACE TYPE message_tbl AS TABLE OF message; +/ + +CREATE OR REPLACE TYPE message_arr AS VARRAY(2000) OF message; +/ + +rem ========================================== +rem Create a queue table my_queue_tab +rem ========================================== +begin +dbms_aqadm.create_queue_table( + queue_table => 'my_queue_tab', + multiple_consumers => TRUE, + queue_payload_type => 'message', + compatible => '9.2.0.0.0'); +end; +/ + +rem ========================================== +rem Create a queue my_queue +rem ========================================== +begin +dbms_aqadm.create_queue( + queue_name => 'my_queue', + queue_table => 'my_queue_tab'); +end; +/ + +rem ==================================== +rem Start queue my_queue +rem ==================================== +begin +dbms_aqadm.start_queue( + queue_name => 'my_queue', + dequeue => TRUE, + enqueue => TRUE); +end; +/ + +rem ======================================== +rem Create queue subscriber +rem ======================================== +declare +app1 sys.aq$_agent; +begin +app1 := sys.aq$_agent('sub1', NULL, NULL); +dbms_aqadm.add_subscriber('my_queue',app1); +end; +/ + +rem ==================================================================== +rem Setup complete +rem ==================================================================== + +spool off diff --git a/aqdemo10.sql b/aqdemo10.sql new file mode 100644 index 0000000..ff6a115 --- /dev/null +++ b/aqdemo10.sql @@ -0,0 +1,83 @@ +Rem +Rem $Header: aqdemo10.sql 17-oct-2003.16:57:16 aahluwal Exp $ +Rem +Rem aqdemo10.sql +Rem +Rem Copyright (c) 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem aqdemo10.sql - +Rem +Rem DESCRIPTION +Rem Performs an array enq of a batch of messages into my_queue +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem aahluwal 10/17/03 - aahluwal_create_arrenqdeq_demos +Rem aahluwal 10/07/03 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +Rem perform array enqueue into AQ queue my_queue + +connect aquser/aquser +set serveroutput on +set echo on + +DECLARE + enqopt dbms_aq.enqueue_options_t; + msgproparr dbms_aq.message_properties_array_t; + msgprop dbms_aq.message_properties_t; + payloadarr message_tbl; + msgidarr dbms_aq.msgid_array_t; + retval pls_integer; + +BEGIN + payloadarr := message_tbl(message('00000'), + message('11111'), + message('22222'), + message('33333'), + message('44444'), + message('55555'), + message('66666'), + message('77777'), + message('88888'), + message('99999')) ; + msgproparr := dbms_aq.message_properties_array_t(msgprop, + msgprop, + msgprop, + msgprop, + msgprop, + msgprop, + msgprop, + msgprop, + msgprop, + msgprop); + + retval := dbms_aq.enqueue_array( queue_name => 'AQUSER.MY_QUEUE', + enqueue_options => enqopt , + array_size => 10, + message_properties_array => msgproparr, + payload_array => payloadarr, + msgid_array => msgidarr ) ; + commit; + + dbms_output.put_line('Enqueued ' || retval || ' messages') ; + for i in 1..retval loop + dbms_output.put_line ('Message ' || i || ' payload: ' || payloadarr(i).data) ; + end loop ; + + +END; +/ + + diff --git a/aqdemo11.sql b/aqdemo11.sql new file mode 100644 index 0000000..d0821ec --- /dev/null +++ b/aqdemo11.sql @@ -0,0 +1,65 @@ +Rem +Rem $Header: aqdemo11.sql 17-oct-2003.16:57:17 aahluwal Exp $ +Rem +Rem aqdemo11.sql +Rem +Rem Copyright (c) 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem aqdemo11.sql - +Rem +Rem DESCRIPTION +Rem Performs an array deq of a batch of messages from my_queue +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem aahluwal 10/17/03 - aahluwal_create_arrenqdeq_demos +Rem aahluwal 10/07/03 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +Rem perform array dequeue from AQ queue my_queue + +connect aquser/aquser +set serveroutput on +set echo on + +DECLARE + deqopt dbms_aq.dequeue_options_t ; + msgproparr dbms_aq.message_properties_array_t := + dbms_aq.message_properties_array_t(); + payloadarr message_arr := message_arr() ; + msgidarr dbms_aq.msgid_array_t ; + retval pls_integer ; +BEGIN + payloadarr.extend(10); + msgproparr.extend(10); + deqopt.consumer_name := 'SUB1'; + retval := dbms_aq.dequeue_array( queue_name => 'AQUSER.MY_QUEUE', + dequeue_options => deqopt , + array_size => payloadarr.count, + message_properties_array => msgproparr, + payload_array => payloadarr, + msgid_array => msgidarr ) ; + commit; + dbms_output.put_line('Dequeued ' || retval || ' messages') ; + for i in 1..retval loop + dbms_output.put_line ('Message ' || i || ' payload: ' || payloadarr(i).data) ; + end loop ; + +END; +/ + + + + + diff --git a/aqdemo12.sql b/aqdemo12.sql new file mode 100644 index 0000000..eb2dfc6 --- /dev/null +++ b/aqdemo12.sql @@ -0,0 +1,54 @@ +Rem +Rem $Header: aqdemo12.sql 17-oct-2003.16:57:18 aahluwal Exp $ +Rem +Rem aqdemo12.sql +Rem +Rem Copyright (c) 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem aqdemo12.sql - +Rem +Rem DESCRIPTION +Rem Removes objects and users created by aqdemo09.sql. +Rem +Rem NOTES +Rem Run this script as SYS using SQLPLUS and type '@aqdemo12'. +Rem +Rem MODIFIED (MM/DD/YY) +Rem aahluwal 10/17/03 - aahluwal_create_arrenqdeq_demos +Rem aahluwal 10/07/03 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +set serveroutput on +set echo on +spool aqdemo12.log + +rem ========================================== +rem Drop My_Queue_Tab Queue Table +rem ========================================== +DECLARE +BEGIN + dbms_output.put_line ('Dropping Queue Table my_queue_tab...'); + dbms_aqadm.drop_queue_table + ( + queue_table => 'aquser.my_queue_tab', + force => TRUE + ); + + dbms_output.put_line ('Dropped Queue Table my_queue_tab.'); + +END; +/ + +drop user aquser cascade +/ + +spool off diff --git a/aqjmsREADME.txt b/aqjmsREADME.txt new file mode 100644 index 0000000..8014d62 --- /dev/null +++ b/aqjmsREADME.txt @@ -0,0 +1,205 @@ +/ $Header: aqjmsREADME.txt 05-jun-2007.15:02:54 aatam Exp $ +/ +/ aqjmsREADME.txt +/ +/ Copyright (c) Oracle Corporation 2000. All Rights Reserved. +/ +/ NAME +/ aqjmsREADME.txt - +/ +/ DESCRIPTION +/ +/ +/ NOTES +/ +/ +/ MODIFIED (MM/DD/YY) +/ aatam 06/05/07 - password need to be consistent +/ qialiu 02/02/07 - ojdbc5.jar +/ qialiu 04/07/06 - jta.jar is in /ade/qialiu_linux_db4/oracle/jlib +/ qialiu 03/09/06 - move jdk1.4 +/ rbhyrava 09/17/04 - orai18n +/ qialiu 07/14/04 - update jta.jar location +/ jleinawe 10/28/03 - update for 10g +/ jleinawe 05/09/03 - update compatibility +/ jleinawe 03/11/03 - add aqjmsdemo10 +/ jleinawe 12/20/02 - update classpath info +/ jleinawe 11/19/02 - add aqjmsdemo09 +/ vmaganty 10/04/02 - add JMS 1.1 domain unification demo info +/ jleinawe 09/10/02 - add aqjmsdemo07 and kprb +/ jleinawe 05/14/02 - udpate nls_charset.zip +/ rbhyrava 03/01/02 - ORAData +/ rbhyrava 07/16/01 - port specific +/ rbhyrava 06/19/01 - jndi location +/ rbhyrava 03/12/01 - jndi.jar +/ rbhyrava 03/06/01 - jndi +/ rbhyrava 01/26/01 - classes111 +/ rbhyrava 11/14/00 - jdbc path +/ rbhyrava 07/10/00 - fix bug 1319922 +/ rbhyrava 07/11/00 - aqjmsdemo.tar +/ rbhyrava 04/14/00 - demo drop +/ rbhyrava 03/20/00 - required init.ora setup +/ rbhyrava 03/15/00 - AQ JMS demo README +/ rbhyrava 03/15/00 - Creation +/ +The following files are required for running JMS samples + + aqjmsdmo.sql - Setup file for AQ JMS demos + aqjmsdemo01.java - Enqueue Text Message and Dequeue based on Message Properties + aqjmsdemo02.java - Message Listener demo- enqueue messages - run aqjmsdemo04 + aqjmsdemo03.java - depends on aqjmsdemo03 - setup Message Listener and dequeue + aqjmsdemo04.java - Oracle Type Payload - Dequeue on Payload content + aqjmsdemo05.java - Queue Browser Example + aqjmsdemo06.java - Schedule Propagation between queues in the database + aqjmsdemo07.java - Send and receive an ADT message containing XML data. + aqjmsdemo08.java - JMS 1.1 domain unification demo + aqjmsdemo09.java - JMS Bulk Array Enqueue/Dequeue + aqjmsdemo10.java - ANYDATA Messaging with JMS Message types and AdtMessage. + Cars.java - Jpublisher generated class ; used in aqjmsdemo04.java + Emp.java - Jpublisher generated class ; used in aqjmsdemo04.java + MesgListener.java - Message Listener - used in aqjmsdemo03.java + Message.java - Definition of Serializable Object - aqjmsdemo06.java + aqjmsdrp.sql - Cleanup for AQ JMS demos + +The following files are required for running AQ Java API samples + + aqoradmo.sql - Setup file for AQ java API demos + aqorademo01.java - Enqueue and Dequeue RAW messages + aqorademo02.java - Enqueue and Dequeue Object Type messages using + ORAData interface + Address.java - Jpublisher generated class ; used in aqorademo02.java + Person.java - Jpublisher generated class ; used in aqorademo02.java + aqoradrp.sql - Cleanup for AQ java API demos + +The following files are required for running the AQ Java KPRB driver samples + + aqjmskprb01.java - Enqueues and dequeues a message within the database. + aqjmskprb01a.sql - Setup file for kprb driver demo. + aqjmskprb01b.sql - Defines java program aqjmskprb01.java as a stored procedure. + aqjmskprb01c.sql - Executes aqjmskprb01.java as a stored procedure. + aqjmskprb01d.sql - Cleanup for AQ kprb driver demo. + + +Setup: +------ + +The CLASSPATH and PATH need to be set appropriately. The JDK need to be at +least JDK 1.5. + +the CLASSPATH need to have the following: + $ORACLE_HOME/rdbms/jlib/aqapi.jar + $ORACLE_HOME/rdbms/jlib/jmscommon.jar + $ORACLE_HOME/rdbms/jlib/xdb.jar + $ORACLE_HOME/lib/xmlparserv2.jar + $ORACLE_HOME/jdbc/lib/ojdbc5.jar + $ORACLE_HOME/jlib/orai18n.jar + $ORACLE_HOME/jlib/jndi.jar + $ORACLE_HOME/jlib/jta.jar + +Make sure LD_LIBRARY_PATH contain the directory of OCI JDBC driver shared + library objects (libocijdbc*.so). + +Eg: + for Solaris, add ORACLE_HOME/lib to LD_LIBRARY_PATH + In C-Shell + %setenv LD_LIBRARY_PATH ${ORACLE_HOME}/lib:${LD_LIBRARY_PATH} + + Refer to platform specific documentation for setting up the above. + +Database Setup: +-------------- + Before running the demo, add the following lines to your init.ora file: + compatible = 9.0.0.0.0 # or higher + aq_tm_processes = 1 + job_queue_processes = 2 + + shutdown and restart the database. + +Compilation: +------------ + + 2. The Jpublisher classes can be optionally generated using the following + syntax. + + jpub -user=aqjava/aqjava -sql=ADDRESS,PERSON -case=mixed -methods=false + jpub -user=jmsuser/JMSUSER -sql=Emp -case=mixed -methods=false + jpub -user=jmsuser/JMSUSER -sql=Cars -case=mixed -methods=false + + +How to Run the JMS API demos: +----------------------------- + +1. Verify the CLASSPATH and PATH setup based on platform and jdk version. + +2. Compile the demos + + %javac aqjmsdemo*.java aqorademo*.java + + Refer to the individual demos files for more information. + +3. Run the setup scripts + + % sqlplus system/manager @aqjmsdmo.sql + creates jmsuser user + + % sqlplus system/manager @aqoradmo.sql + creates aqjava user + +4. Run the demos + + %java aqjmsdemo01 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo02 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo03 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo04 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo05 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo06 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo07 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo08 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo09 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo10 [SID] [HOST] [PORT] + + %java aqorademo01 [SID] [HOST] [PORT] [DRIVER] + %java aqorademo02 [SID] [HOST] [PORT] [DRIVER] + + Example: + java aqjmsdemo01 orcl dlsun673 1521 thin + +5. Drop demo scripts + + % sqlplus system/manager @aqjmsdrp.sql + drops jmsuser user + + % sqlplus system/manager @aqoradrp.sql + drops aqjava user + + +How to Run the JMS KPRB Driver demos: +------------------------------------- + +1) Compile the demo + + % javac aqjmskprb01.java + +2) Create the test user and JMS Queue + (this creates jmsuser1 user and Queue jmsuser1.queue1) + + % sqlplus system/manager @aqjmskprb01a.sql + +3) Load the java demo class file into the database + + % loadjava -user jmsuser1/JMSUSER1 -v aqjmskprb01.class + +4) Define the java demo as a PL/SQL Java stored procedure + + % sqlplus jmsuser1/JMSUSER1 @aqjmskprb01b.sql + +5) Execute the demo program by calling it's PL/SQL procedure + + % sqlplus jmsuser1/JMSUSER1 @aqjmskprb01c.sql + +6) Drop demo scripts + (this drops user jmsuser1 and user's stored procedures) + + % sqlplus system/manager @aqjmskprb01d.sql + + diff --git a/aqjmsdemo01.java b/aqjmsdemo01.java new file mode 100644 index 0000000..3a9b469 --- /dev/null +++ b/aqjmsdemo01.java @@ -0,0 +1,222 @@ +/* $Header: aqjmsdemo01.java 05-jun-2007.15:10:19 aatam Exp $ */ + +/* Copyright (c) 2000, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - jdk 1.5 + jleinawe 12/20/02 - update instructions + rbhyrava 01/09/01 - bug 1419924 + rbhyrava 11/14/00 - remove pwd at the end + rbhyrava 07/13/00 - fix compilation error + rbhyrava 03/16/00 - AQ jms demos + rbhyrava 03/15/00 - AQ JMS demo - Enqueue,Dequeue Text Message + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqjmsdemo01.java 05-jun-2007.15:10:19 aatam Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ +/*** + * This is a sample java file which uses Oracle JMS - Java Messaging Service + * API to Enqueue/Dequeue text Message. Rule-based subscription on message properties and/or the message content of a topic. + * + * This demo does the following: + * -- Setup a topic + * -- Create two Durable Subscribers.Specify a selector that represents + * a specification (selects) for the messages that the subscriber wishes + * to receive. + * -- Publish sereral Messages to the Topic + * -- Receive the Messages for each subscriber + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + * + ***/ +/* import useful packages */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; + +public class aqjmsdemo01 +{ + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + TopicSession tsess = null; + TopicConnectionFactory tcfact =null; + TopicConnection tconn =null; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + tcfact = AQjmsFactory.getTopicConnectionFactory( + args[1], args[0], Integer.parseInt(args[2]), args[3]); + + tconn = tcfact.createTopicConnection( "jmsuser","JMSUSER"); + + /* Create a Topic Session */ + tsess = tconn.createTopicSession(true, Session.CLIENT_ACKNOWLEDGE); + + tconn.start() ; + setupTopic(tsess) ; + performJmsOperations(tsess); + tsess.close() ; + tconn.close() ; + System.out.println("End of Demo") ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void setupTopic(TopicSession tsess) throws Exception + { + AQQueueTableProperty qtprop ; + AQQueueTable qtable; + AQjmsDestinationProperty dprop; + Topic topic; + try { + /* Create Queue Tables */ + System.out.println("Creating Input Queue Table...") ; + + /* Drop the queue if already exists */ + try { + qtable=((AQjmsSession)tsess).getQueueTable("jmsuser", "jmsqtable" ); + qtable.drop(true); + } catch (Exception e) {} ; + + qtprop = new AQQueueTableProperty ("SYS.AQ$_JMS_TEXT_MESSAGE") ; + qtprop.setMultiConsumer(true) ; + qtprop.setCompatible("8.1") ; + qtprop.setPayloadType("SYS.AQ$_JMS_TEXT_MESSAGE") ; + qtable = ((AQjmsSession)tsess).createQueueTable("JMSUSER", + "jmsqtable", qtprop) ; + + System.out.println ("Creating Topic input_queue..."); + dprop = new AQjmsDestinationProperty() ; + topic=((AQjmsSession)tsess).createTopic( qtable,"jmstopic",dprop) ; + + /* Start the topic */ + ((AQjmsDestination)topic).start(tsess, true, true); + System.out.println("Successfully setup Topic"); + } catch (Exception ex) { + System.out.println("Error in setupTopic: " + ex); + throw ex; + } + } + + public static void performJmsOperations(TopicSession tsess) + { + Topic topic =null; + TopicSubscriber tsub1,tsub2; + TopicPublisher publisher; + TextMessage txtmsg, dtxtmsg; + + try + { + System.out.println ("Get the Topic..."); + topic = ((AQjmsSession)tsess).getTopic("JMSUSER","jmstopic") ; + + System.out.println("Creating Topic Subscribers...") ; + + tsub1 = tsess.createDurableSubscriber(topic, "dallas", + "(year = 1998 OR color NOT IN ('GREEN','RED','WHITE')) "+ + " AND make IN ('ACURA ', 'BMW', 'MERCEDES')", false); + + tsub2 = tsess.createDurableSubscriber(topic, "atlanta", + "price < 20000", false ); + + System.out.println("Publish messages...") ; + publisher = tsess.createPublisher(topic); + + + txtmsg = tsess.createTextMessage() ; + txtmsg.setText("Cars Distribution") ; + txtmsg.setObjectProperty("carno", new Integer(12345)) ; + txtmsg.setStringProperty("color", "BLUE") ; + txtmsg.setIntProperty("year", 1999) ; + txtmsg.setStringProperty("make", "BMW") ; + txtmsg.setDoubleProperty("price", 25995) ; + txtmsg.setJMSCorrelationID("dallas") ; + + publisher.publish(topic, txtmsg) ; + + txtmsg.clearProperties() ; + txtmsg.setObjectProperty("carno", new Integer(55)) ; + txtmsg.setStringProperty("color", "CYAN") ; + txtmsg.setIntProperty("year", 2000) ; + txtmsg.setStringProperty("make", "MERCEDES") ; + txtmsg.setDoubleProperty("price", 19000) ; + txtmsg.setJMSCorrelationID("atlanta") ; + publisher.publish(topic, txtmsg) ; + + txtmsg.clearProperties() ; + txtmsg.setObjectProperty("carno", new Integer(99099)) ; + txtmsg.setStringProperty("color", "RED") ; + txtmsg.setIntProperty("year", 1998) ; + txtmsg.setStringProperty("make", "ACURA") ; + txtmsg.setDoubleProperty("price", 19995) ; + txtmsg.setJMSCorrelationID("atlanta") ; + publisher.publish(topic, txtmsg) ; + + tsess.commit() ; + + /* Receive the text Message for two subscribers */ + boolean done=false ; + System.out.println ("Dequeue Message for Subscriber 1") ; + while (!done) { + dtxtmsg = (TextMessage) (tsub1.receiveNoWait() ) ; + + if (dtxtmsg == null) { + done=true; + } else + { + System.out.print(" Color: " + dtxtmsg.getStringProperty("color")); + System.out.print(" Make: " + dtxtmsg.getStringProperty("make")); + System.out.print(" Year: " + dtxtmsg.getStringProperty("year")); + System.out.print(" Price: " + dtxtmsg.getStringProperty("price")); + System.out.println(" Carno: " + dtxtmsg.getStringProperty("carno")); + } + } + + System.out.println ("Dequeue Message for Subscriber 2") ; + + done=false ; + while (!done) { + dtxtmsg = (TextMessage) (tsub2.receive(1) ) ; + if ( dtxtmsg == null ) { + done=true ; + } else { + System.out.print(" Color: " + dtxtmsg.getStringProperty("color")); + System.out.print(" Make: " + dtxtmsg.getStringProperty("make")); + System.out.print(" Year: " + dtxtmsg.getStringProperty("year")); + System.out.print(" Price: " + dtxtmsg.getStringProperty("price")); + System.out.println(" Carno: " + dtxtmsg.getStringProperty("carno")); + } + } + tsess.commit() ; + ((AQjmsDestination)topic).stop(tsess, true, true, false); + + } catch (Exception e) { + System.out.println("Error in performJmsOperations: " + e) ; + } + } +} diff --git a/aqjmsdemo02.java b/aqjmsdemo02.java new file mode 100644 index 0000000..8561194 --- /dev/null +++ b/aqjmsdemo02.java @@ -0,0 +1,214 @@ +/* $Header: aqjmsdemo02.java 05-jun-2007.15:10:20 aatam Exp $ */ + +/* Copyright (c) 2000, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - jdk 1.5 + jleinawe 12/20/02 - update instructions + rbhyrava 01/09/01 - bug 1419924 + rbhyrava 03/16/00 - AQ jms demos + rbhyrava 03/15/00 - AQ JMS demo - Message Listener Demo - Enqueue Messag + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqjmsdemo02.java 05-jun-2007.15:10:20 aatam Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + + + +/*** + * This is a sample java file which uses Oracle JMS - Java Messaging Service + * API to Publish messages into topic. aqjmsdemo04 will demonstrate the + * Subscribers receiving the messages asynchronously using Message Listener + * aqjmsdemo02 - enqueues the messages to the queue + * aqjmsdemo03 - setup Message Listener and dequeue the messages + + * This demo does the following: + * -- Create a Queue + * -- Send several MAP messages + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + ***/ + +/* import useful packages */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; + +public class aqjmsdemo02 +{ + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + QueueSession qsess = null; + QueueConnectionFactory qcfact; + QueueConnection qconn; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + //args passed are sid,host,port,driver + qcfact = AQjmsFactory.getQueueConnectionFactory( + args[1], args[0], Integer.parseInt(args[2]), args[3]); + + /* Create Queue Connection */ + qconn = qcfact.createQueueConnection( "jmsuser","JMSUSER"); + + /* Create a Queue Session */ + qsess = qconn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + + qconn.start() ; + setupQueue(qsess) ; + enqueueMessages(qsess); + System.out.println("End of Demo") ; + qsess.close() ; + qconn.close() ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void setupQueue(QueueSession qsess) throws Exception + { + AQQueueTableProperty qtprop ; + AQQueueTable qtable; + AQjmsDestinationProperty dprop; + javax.jms.Queue q1; + try { + + /* Create Queue Tables */ + System.out.println("Creating Queue Table...") ; + + qtprop = new AQQueueTableProperty ("SYS.AQ$_JMS_MAP_MESSAGE") ; + qtprop.setCompatible("8.1") ; + qtprop.setPayloadType("SYS.AQ$_JMS_MAP_MESSAGE") ; + + /* Drop if the queue table already exists */ + try { + qtable=((AQjmsSession)qsess).getQueueTable("JMSUSER", "JMSQTABLE"); + qtable.drop(true); + } catch (Exception e) {} + + qtable = ((AQjmsSession)qsess).createQueueTable("JMSUSER", + "jmsqtable", qtprop) ; + + System.out.println ("Creating Queue..."); + dprop = new AQjmsDestinationProperty() ; + q1=((AQjmsSession)qsess).createQueue(qtable,"JMSMAPQ",dprop) ; + + /* Start the Queue */ + ((AQjmsDestination)q1).start(qsess, true, true); + + System.out.println("Successfully setup Queue"); + } catch (Exception ex) { + System.out.println("Error in setupTopic: " + ex); + throw ex; + } + } + + public static void enqueueMessages(QueueSession qsess) throws Exception + { + javax.jms.Queue q1 ; + MapMessage[] Messages; + byte[] barray ; + QueueSender qsender; + + TopicSubscriber tsub1,tsub2; + TopicPublisher publisher; + StringBuffer txtbuf ; + TextMessage txtmsg, dtxtmsg; + try + { + /* Get Queue */ + q1 = ((AQjmsSession)qsess).getQueue("JMSUSER", "JMSMAPQ") ; + + System.out.println("Send messages...") ; + + barray = new byte[25] ; + for ( int i=0 ; i< 25 ; i++) barray[i] = 67 ; + + Messages = new MapMessage[5] ; + + Messages[0] = qsess.createMapMessage() ; + Messages[0].setIntProperty ("carno", 3355) ; + Messages[0].setStringProperty ("color", "BLUE") ; + Messages[0].setStringProperty ("make", "BMW") ; + Messages[0].setDoubleProperty ("price", 20000) ; + Messages[0].setIntProperty ("year", 1999) ; + + Messages[1] = qsess.createMapMessage() ; + Messages[1].setIntProperty ("carno", 4444) ; + Messages[1].setStringProperty ("color", "BLACK") ; + Messages[1].setStringProperty ("make", "ACURA") ; + Messages[1].setDoubleProperty ("price", 22995) ; + Messages[1].setIntProperty ("year", 1998) ; + + Messages[2] = qsess.createMapMessage() ; + Messages[2].setIntProperty ("carno", 1212) ; + Messages[2].setStringProperty ("color", "BLUE") ; + Messages[2].setStringProperty ("make", "MERCEDES") ; + Messages[2].setDoubleProperty ("price", 30995) ; + Messages[2].setIntProperty ("year", 2001) ; + + Messages[3] = qsess.createMapMessage() ; + Messages[3].setIntProperty ("carno", 5345) ; + Messages[3].setStringProperty ("color", "GREEN") ; + Messages[3].setStringProperty ("make", "LEXUS") ; + Messages[3].setDoubleProperty ("price", 21895) ; + Messages[3].setIntProperty ("year", 1995) ; + + Messages[4] = qsess.createMapMessage() ; + Messages[4].setIntProperty ("carno", 8909) ; + Messages[4].setStringProperty ("color", "BLUE") ; + Messages[4].setStringProperty ("make", "BMW") ; + Messages[4].setDoubleProperty ("price", 40995) ; + Messages[4].setIntProperty ("year", 2002) ; + + /* Create Queue Sender */ + qsender = qsess.createSender(q1) ; + + for ( int i = 0 ; i < 5 ; i++ ) + { + Messages[i].setBytes("Picture" , barray) ; + Messages[i].setJMSCorrelationID(Messages[i].getStringProperty("color")); + System.out.println("Sending "+Messages[i].getStringProperty ("color") + + " " + Messages[i].getStringProperty("make") + + " " + Messages[i].getIntProperty("year") + + " " + Messages[i].getDoubleProperty("price")) ; + + qsender.send(q1, Messages[i], DeliveryMode.PERSISTENT, + 1+ (i%10) , AQjmsConstants.EXPIRATION_NEVER ) ; + try { + Thread.sleep(5000) ; + } catch (InterruptedException e) {} ; + qsess.commit() ; + } + System.out.println("Successfully Sent Messages."); + + } catch (JMSException e) { + System.out.println("Error in Sending Messages : " + e) ; + throw e; + } + } +} diff --git a/aqjmsdemo03.java b/aqjmsdemo03.java new file mode 100644 index 0000000..8fe7960 --- /dev/null +++ b/aqjmsdemo03.java @@ -0,0 +1,130 @@ +/* $Header: aqjmsdemo03.java 05-jun-2007.15:10:22 aatam Exp $ */ + +/* Copyright (c) 2000, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - + jleinawe 12/20/02 - update instructions + rbhyrava 03/01/02 - increase sleep + rbhyrava 01/25/02 - increase sleep time + lzhao 06/26/01 - comment + rbhyrava 01/09/01 - bug 1419924 + rbhyrava 03/15/00 - AQ JMS demo - Message Listener Demo + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqjmsdemo03.java 05-jun-2007.15:10:22 aatam Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/* Message Listener */ +/*** + * This is a sample java file which uses Oracle JMS - Java Messaging Service + * API where Subscribers can Recieve messages asynchronously using + * MessageListener + * Subscribers receiveing the messages asynchronously using Message Listener + * aqjmsdemo02 - enqueues the messages to the queue + * aqjmsdemo03 - setup Message Listener and dequeue the messages + * This demo does the following: + * -- Get the Queue already created in aqjmsdemo03.java + * -- Create Receiver for the Queue + * -- Setup the message listener for Queue Receiver + * -- Start the connection + * -- Recieve the messages + * -- Stop the connection + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + ***/ + +/* import useful packages */ + +/* import useful packages */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; + +public class aqjmsdemo03 +{ + + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + QueueSession qsess = null; + QueueConnectionFactory qcfact; + QueueConnection qconn; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + qcfact = AQjmsFactory.getQueueConnectionFactory( + args[1], args[0], Integer.parseInt(args[2]), args[3]); + qconn = qcfact.createQueueConnection( "jmsuser","JMSUSER"); + /* Create a Queue Session */ + qsess = qconn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + System.out.println("Successfully created QueueSession"); + + qconn.start() ; + demoMessageListener(qsess); + qsess.close() ; + qconn.close() ; + System.out.println("End of Demo") ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void demoMessageListener(QueueSession qsess) throws Exception + { + javax.jms.Queue queue; + QueueReceiver qrecv ; + MessageListener mLis ; + + try + { + System.out.println("Get the Queue") ; + /* Get the Queue */ + /* Queue JMSMAPQ is created in aqjmsdemo02 */ + queue = ((AQjmsSession)qsess).getQueue("JMSUSER", "JMSMAPQ") ; + + System.out.println("Create Receiver...") ; + + /* Create a queue receiever */ + qrecv = qsess.createReceiver(queue, "JMSCorrelationID='BLUE'") ; + + /* Setup the message listener */ + System.out.println("Set Message Listener... and Sleep...") ; + mLis = new MesgListener(qsess); + qrecv.setMessageListener (mLis) ; + + try { + Thread.sleep(250000) ; + } catch (InterruptedException e) {} ; + + System.out.println("Successfully dequeued with MessageListener") ; + + } catch (JMSException e) { + System.out.println("Error in demoMessageListener: " +e ) ; + throw e; + } + } +} diff --git a/aqjmsdemo04.java b/aqjmsdemo04.java new file mode 100644 index 0000000..ec0cfb9 --- /dev/null +++ b/aqjmsdemo04.java @@ -0,0 +1,238 @@ +/* $Header: aqjmsdemo04.java 05-jun-2007.15:10:23 aatam Exp $ */ + +/* Copyright (c) 2000, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - + jleinawe 12/20/02 - update instructions + rbhyrava 03/01/02 - use ORAData + rbhyrava 01/09/01 - bug 1419924 + rbhyrava 03/16/00 - AQ jms demos + rbhyrava 03/15/00 - AQ JMS demo - Object Type Payload + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqjmsdemo04.java 05-jun-2007.15:10:23 aatam Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ +/*** + * This is a sample java file which uses Oracle JMS - Java Messaging Service + * API to Publish/Receive messages to/from topic. The Oracle Type Payload is + * used. Dequeue is based on the Payload content + * This is an Oracle Extention to JMS. + * This demo does the following: + * -- Create a multi-consumer topic with Payload type as EMP + * Refer to aqjmsdemo.sql for definition of EMP and CARS Object Type + definitions + * -- Create a Topic Publisher + * -- Create two durable subscribers based on the Payload content + * -- Publish messages + * -- Receive the messages for both the subscribers + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + ***/ + +/* import useful packages */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; + +public class aqjmsdemo04 +{ + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + TopicSession tsess = null; + TopicConnectionFactory tcfact=null; + TopicConnection tconn=null; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + tcfact = AQjmsFactory.getTopicConnectionFactory( + args[1], args[0], Integer.parseInt(args[2]), args[3]); + + tconn = tcfact.createTopicConnection( "jmsuser","JMSUSER"); + + /* Create a Topic Session */ + tsess = tconn.createTopicSession(true, Session.CLIENT_ACKNOWLEDGE); + tconn.start() ; + setupTopic(tsess) ; + publishReceiveMessages(tsess); + tsess.close() ; + tconn.close() ; + System.out.println("End of Demo") ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void setupTopic(TopicSession tsess) throws Exception + { + AQQueueTableProperty qtprop ; + AQQueueTable qtable; + AQjmsDestinationProperty dprop; + Topic topic; + try { + /* Create Queue Tables */ + System.out.println("Creating Queue Table...") ; + /* Drop the queue if already exists */ + try { + qtable=((AQjmsSession)tsess).getQueueTable("jmsuser", "jmsadtqueue"); + qtable.drop(true); + } catch (Exception e) {} ; + + qtprop = new AQQueueTableProperty ("EMP") ; + qtprop.setComment("EMP queue") ; + qtprop.setMultiConsumer(true) ; + qtprop.setCompatible("8.1") ; + qtprop.setPayloadType("JMSUSER.EMP") ; + + qtable = ((AQjmsSession)tsess).createQueueTable("JMSUSER", + "JMSADTQUEUE", qtprop) ; + + System.out.println ("Creating Topic EMPCARS..."); + dprop = new AQjmsDestinationProperty() ; + dprop.setComment("create topic") ; + topic= ((AQjmsSession)tsess).createTopic( qtable,"EMPCARS",dprop); + + /* Start the topic */ + ((AQjmsDestination)topic).start(tsess, true, true); + System.out.println("Successfully setup Topic"); + } catch (Exception ex) { + System.out.println("Error in setupTopic: " + ex); + throw ex; + } + } + + public static void publishReceiveMessages(TopicSession tsess) + throws Exception + { + Topic topic =null; + TopicSubscriber[] subs; + TopicPublisher publisher; + StringBuffer txtbuf ; + AdtMessage adt_msg; + Emp empmsg, rmsg; + Cars c; + try + { + + /* Get the topic */ + System.out.println("Getting the Topic...") ; + topic = ((AQjmsSession)tsess).getTopic("JMSUSER", "EMPCARS"); + + System.out.println("Creating Topic Subscribers...") ; + subs = new TopicSubscriber[2] ; + + subs[0] = ((AQjmsSession)tsess).createDurableSubscriber(topic, + "PROG1", "TAB.USER_DATA.CAROWN.COLOR = 'RED'", + false, Emp.getORADataFactory()) ; + subs[1] = ((AQjmsSession)tsess).createDurableSubscriber(topic, + "PROG2", "TAB.USER_DATA.RANK > 2", + false, Emp.getORADataFactory()) ; + + System.out.println("Create a Publisher...") ; + publisher = tsess.createPublisher(topic); + + adt_msg = ((AQjmsSession)tsess).createAdtMessage() ; + + String[] names={"KING JOE","SCOTT RAY","ADITYA NELLORE","LORI MAXWELL" }; + int[] rank={1,2,3,4} ; + String color[] = {"YELLOW", "RED", "BLUE","RED" } ; + String make[] = {"BMW", "ACURA", "MERCEDES","LEXUS" } ; + empmsg = new Emp() ; + c = new Cars() ; + + System.out.println("Publish messages...") ; + + for ( int i = 1 ; i < 4 ; i++) + { + java.math.BigDecimal id = new java.math.BigDecimal(i) ; + empmsg.setId(id) ; + empmsg.setName(names[i]) ; + empmsg.setRank(new java.math.BigDecimal(rank[i])) ; + c.setCarno(new java.math.BigDecimal(1000 + i)) ; + c.setMake(make[i] ); + c.setColor(color[i] ); + c.setPrice(new java.math.BigDecimal(10000 * i) ); + empmsg.setCarown(c) ; + + adt_msg.clearProperties() ; + //adt_msg.setJMSCorrelationID(new Integer(100+i) ) ; + adt_msg.setAdtPayload(empmsg) ; + adt_msg.setJMSPriority(1+(i%3)) ; + publisher.publish(topic,adt_msg, DeliveryMode.PERSISTENT, + 1+(i%3),AQjmsConstants.EXPIRATION_NEVER); + + System.out.print("Sent Message Pri: " +adt_msg.getJMSPriority()) ; + System.out.print(" Id: " +empmsg.getId()) ; + System.out.print(" Name: " +empmsg.getName()) ; + System.out.print(" Rank: " +empmsg.getRank()) ; + System.out.print(" Car: " +empmsg.getCarown().getColor()) ; + System.out.println(" " +empmsg.getCarown().getMake()) ; + } + + System.out.println("Commit") ; + tsess.commit() ; + + Thread.sleep(500); + + System.out.println("Receive Messages...") ; + + /* Receive messages for each subscriber */ + + for (int i=0; i< subs.length ; i++) + { + System.out.println ("Messages for subscriber : " +i) ; + boolean more = true; + while(more) { + try { + adt_msg = (AdtMessage)( subs[i].receiveNoWait() ); + if (adt_msg != null) + { + rmsg = (Emp) (adt_msg.getAdtPayload()); + System.out.print("Priority : " +adt_msg.getJMSPriority()) ; + System.out.print(" Id: " +rmsg.getId()) ; + System.out.print(" Name: " +rmsg.getName()) ; + System.out.print(" Rank: " +rmsg.getRank()) ; + System.out.print(" Car: " +rmsg.getCarown().getColor()) ; + System.out.println(" " +rmsg.getCarown().getMake()) ; + } + else { + System.out.println ("No more messages.") ; + more=false; + } + tsess.commit(); + } catch (Exception e) { + System.out.println ("Error in Receive: " + e) ; + more=false; + } + } /* while loop*/ + } + } catch (Exception e) { + System.out.println("Error in publish receive Messages: " + e) ; + throw e; + } + } +} diff --git a/aqjmsdemo05.java b/aqjmsdemo05.java new file mode 100644 index 0000000..a2f8d33 --- /dev/null +++ b/aqjmsdemo05.java @@ -0,0 +1,234 @@ +/* $Header: aqjmsdemo05.java 05-jun-2007.15:10:24 aatam Exp $ */ + +/* Copyright (c) 2000, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + aatam 06/27/06 - fix Queue is ambiguous error + jleinawe 07/11/05 - + jleinawe 12/20/02 - update instructions + rbhyrava 01/09/01 - bug 1419924 + rbhyrava 03/15/00 - AQ JMS demo - Queue Browser + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqjmsdemo05.java 05-jun-2007.15:10:24 aatam Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/*** + * This is a sample java file which uses Oracle JMS - Java Messaging Service + * API to demonstrate QueueBrowser. + * Client uses a QueueBrowser to view messages on a queue without removing them. + * + * This demo does the following: + * -- Create a single consumer queue of Payload type as CARS + * Refer to aqjmsdemo.sql for definition of CARS Object Type + * -- Create a Queue Sender + * -- Create a Queue Browser with Message Selector ; + messages delivered to the browser to those that match the selector. + * -- Save the message Ids + * -- Dequeue the messages based on the Message ids + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + * + ***/ + +/* import useful packages */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; +import java.util.* ; +public class aqjmsdemo05 +{ + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + QueueSession qsess = null; + QueueConnectionFactory qcfact=null; + QueueConnection qconn=null; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + qcfact = AQjmsFactory.getQueueConnectionFactory( + args[1], args[0], Integer.parseInt(args[2]), args[3]); + + qconn = qcfact.createQueueConnection( "jmsuser","JMSUSER"); + + /* Create a Queue Session */ + qsess = qconn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + + qconn.start() ; + setupQueue(qsess) ; + sendMessages(qsess) ; + queueBrowserDemo(qsess); + qsess.close() ; + qconn.close() ; + System.out.println("End of Demo") ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void setupQueue(QueueSession qsess) throws Exception + { + AQQueueTable qtable=null; + AQQueueTableProperty qtprop; + AQjmsDestinationProperty dprop; + javax.jms.Queue queue; + try { + /* Create Queue Tables */ + System.out.println("Creating Queue Table...") ; + + /* Drop the queue if already exists */ + try { + qtable=((AQjmsSession)qsess).getQueueTable("jmsuser", "jmsqbtable" ); + qtable.drop(true); + } catch (Exception e) {} ; + + qtprop = new AQQueueTableProperty ("SYS.AQ$_JMS_TEXT_MESSAGE") ; + qtprop.setPayloadType("SYS.AQ$_JMS_TEXT_MESSAGE") ; + + qtable = ((AQjmsSession)qsess).createQueueTable("JMSUSER", + "jmsqbtable", qtprop) ; + + System.out.println ("Creating Queue jmsqb..."); + dprop = new AQjmsDestinationProperty() ; + queue=((AQjmsSession)qsess).createQueue( qtable,"jmsqb",dprop) ; + + /* Start the Queue */ + ((AQjmsDestination)queue).start(qsess, true, true); + System.out.println("Successfully setup Queue"); + } catch (Exception ex) { + System.out.println("Error in setupQueue: " + ex); + throw ex; + } + } + + public static void sendMessages(QueueSession qsess) throws Exception + { + javax.jms.Queue q1; + QueueSender qsender ; + TextMessage txtmsg; + StringBuffer txtbuf; + String color[] = {"YELLOW", "RED", "BLUE","RED" } ; + String make[] = {"BMW", "ACURA", "MERCEDES","LEXUS" } ; + try + { + System.out.println ("get Queue JMSQB"); + q1=((AQjmsSession)qsess).getQueue("JMSUSER","JMSQB") ; + + System.out.println("Send messages...") ; + /* Create Queue Sender */ + qsender = qsess.createSender(q1) ; + + txtbuf = new StringBuffer() ; + txtbuf.append ("Favorite Cars") ; + txtmsg = ((AQjmsSession)qsess).createTextMessage(txtbuf) ; + + for (int i =0; i < 4 ; i++) { + txtmsg.setIntProperty("carno",1000 + i) ; + txtmsg.setStringProperty("make", make[i]) ; + txtmsg.setIntProperty ("year",1999 + i) ; + txtmsg.setDoubleProperty("price",10000*(i+1)); + txtmsg.setStringProperty("color",color[i]) ; + txtmsg.setJMSCorrelationID(color[i]+"-"+make[i]) ; + + qsender.send(q1, txtmsg, DeliveryMode.PERSISTENT, 1+ (i%10), + AQjmsConstants.EXPIRATION_NEVER) ; + + byte[] msgid =((AQjmsMessage)txtmsg).getJMSMessageIDAsBytes() ; + System.out.println("Sent "+ txtmsg.getStringProperty("color") + + " " + txtmsg.getStringProperty("make") + + " " + txtmsg.getIntProperty("year") ) ; + } + qsess.commit(); + + }catch (Exception e) { + System.out.println("Error in SendMessages : " + e) ; + throw e; + } + } + + public static void queueBrowserDemo(QueueSession qsess) throws JMSException + { + javax.jms.Queue q1; + QueueBrowser qb; + Enumeration q1_enum ; + String[] msgids ; + int cnt=0; + TextMessage tmsg; + QueueReceiver qr ; + try + { + /* Get the queue */ + System.out.println("Get the Queue..") ; + q1= ((AQjmsSession)qsess).getQueue("JMSUSER", "JMSQB") ; + /* Create Queue Browser */ + System.out.println("Create Queue Browser..") ; + qb = ((AQjmsSession)qsess).createBrowser(q1, + "JMSCorrelationID LIKE 'RED%'", null, true); + + q1_enum = qb.getEnumeration() ; + + /* Browse the messages now */ + msgids = new String[10]; + while(q1_enum.hasMoreElements() == true ) + { + try { + tmsg = (TextMessage) (q1_enum.nextElement()) ; + msgids[cnt] = tmsg.getJMSMessageID() ; + System.out.println("MessageID is "+ msgids[cnt]) ; + cnt++ ; + System.out.println("Browser "+ tmsg.getStringProperty("color") + + " " + tmsg.getStringProperty("make") + + " " + tmsg.getIntProperty("year")) ; + + System.out.print(" Correlation id "+ tmsg.getJMSCorrelationID()); + System.out.println(" Priority "+ tmsg.getJMSPriority()); + + } catch (Exception e) { + System.out.println("Browser raised exception " + e) ; + } + } + + System.out.println("Now Dequeue Messages using message Ids") ; + for (int i =0; i< cnt; i++) { + + qr = ((AQjmsSession)qsess).createReceiver(q1, + "JMSMessageID = '"+msgids[i]+"'",null ) ; + + tmsg= (TextMessage)qr.receiveNoWait() ; + + System.out.println("Dequeued "+ tmsg.getStringProperty("color") + + " " + tmsg.getStringProperty("make") + + " " + tmsg.getIntProperty("year")) ; + qr.close() ; + } + qsess.commit(); + } catch (JMSException e) { + System.out.println("Error in QueueBrowserDemo : "+ e) ; + throw e ; + } + } /* end of demo06 */ +} diff --git a/aqjmsdemo06.java b/aqjmsdemo06.java new file mode 100644 index 0000000..acaa31a --- /dev/null +++ b/aqjmsdemo06.java @@ -0,0 +1,274 @@ +/* $Header: aqjmsdemo06.java 05-jun-2007.15:10:24 aatam Exp $ */ + +/* Copyright (c) 2000, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - + jleinawe 03/12/03 - add unschedulePropagation call + jleinawe 12/20/02 - update instructions + rbhyrava 01/09/01 - bug 1419924 + rbhyrava 07/13/00 - fix typo + rbhyrava 03/16/00 - AQ jms demos + rbhyrava 03/15/00 - AQ JMS demo - Propagation + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqjmsdemo06.java 05-jun-2007.15:10:24 aatam Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/*** + * This is a sample java file which uses Oracle JMS - Java Messaging Service + * API to schedule Propagation between Queues in Oracle database + * + * This demo is functionally same a newaqdemo01.sql and does the following: + * -- Create two queue tables - input_queue_table, prop_queue_table + * -- Create two queues - input_queue belonging to input_queue_table, + * prop_queue belonging to prop_queue_table + * -- Create two subscribers to input_queue - prog1, prog2 + * -- Create one subscribers to input_queue - prog3 at prop_queue + * -- Schedule propagation between input_queue and other queues in + * the database + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + * + ***/ + +/* Object Message */ + +/* import useful packages */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; + +public class aqjmsdemo06 +{ + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + TopicSession tsess = null; + TopicConnectionFactory tcfact=null; + TopicConnection tconn=null; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + tcfact = AQjmsFactory.getTopicConnectionFactory( + args[1], args[0], Integer.parseInt(args[2]), args[3]); + + tconn = tcfact.createTopicConnection( "jmsuser","JMSUSER"); + + /* Create a Topic Session */ + tsess = tconn.createTopicSession(true, Session.CLIENT_ACKNOWLEDGE); + + tconn.start() ; + setupTopic(tsess) ; + performJmsOperations(tsess); + tsess.close(); + tconn.close(); + System.out.println("End of Demo") ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void setupTopic(TopicSession tsess) throws Exception + { + AQQueueTableProperty qtprop1,qtprop2 ; + AQQueueTable qtable,table1, table2; + AQjmsDestinationProperty dprop; + Topic topic1, topic2; + try { + /* Create Queue Tables */ + System.out.println("Creating Input Queue Table...") ; + + /* Drop the queue if already exists */ + try { + qtable=((AQjmsSession)tsess).getQueueTable("jmsuser", + "INPUT_QUEUE_TABLE" ); + qtable.drop(true); + } catch (Exception e) {} ; + try { + qtable=((AQjmsSession)tsess).getQueueTable("jmsuser", + "PROP_QUEUE_TABLE" ); + qtable.drop(true); + } catch (Exception e) {} ; + + qtprop1 = new AQQueueTableProperty ("SYS.AQ$_JMS_OBJECT_MESSAGE") ; + qtprop1.setComment("input queue") ; + qtprop1.setMultiConsumer(true) ; + qtprop1.setCompatible("8.1") ; + qtprop1.setPayloadType("SYS.AQ$_JMS_OBJECT_MESSAGE") ; + table1 = ((AQjmsSession)tsess).createQueueTable("JMSUSER", + "INPUT_QUEUE_TABLE", qtprop1) ; + + System.out.println("Creating Propagation Queue Table...") ; + qtprop2 = new AQQueueTableProperty ("SYS.AQ$_JMS_OBJECT_MESSAGE") ; + qtprop2.setComment("Popagation queue") ; + qtprop2.setPayloadType("SYS.AQ$_JMS_OBJECT_MESSAGE") ; + qtprop2.setMultiConsumer(true) ; + qtprop2.setCompatible("8.1") ; + table2 = ((AQjmsSession)tsess).createQueueTable("JMSUSER", + "PROP_QUEUE_TABLE", qtprop2) ; + + System.out.println ("Creating Topic input_queue..."); + dprop = new AQjmsDestinationProperty() ; + dprop.setComment("create topic 1") ; + topic1=((AQjmsSession)tsess).createTopic(table1,"INPUT_QUEUE",dprop) ; + + dprop.setComment("create topic 2") ; + topic2=((AQjmsSession)tsess).createTopic( table2,"PROP_QUEUE",dprop) ; + + /* Start the topic */ + ((AQjmsDestination)topic1).start(tsess, true, true); + ((AQjmsDestination)topic2).start(tsess, true, true); + System.out.println("Successfully setup Topics"); + + } catch (Exception ex) { + System.out.println("Error in setupTopic: " + ex); + throw ex; + } + + } + + + public static void performJmsOperations(TopicSession tsess) + throws Exception + { + Topic topic1,topic2; + TopicSubscriber[] subs; + AQjmsAgent agt; + ObjectMessage objmsg = null, robjmsg=null; + TopicPublisher publisher ; + Message sobj , rmsg; + String[] cities={"BELMONT","REDWOOD SHORES", "SUNNYVALE", "BURLINGAME" }; + try + { + + System.out.println("Get Topics...") ; + topic1 = ((AQjmsSession)tsess).getTopic("JMSUSER", "INPUT_QUEUE") ; + topic2 = ((AQjmsSession)tsess).getTopic("JMSUSER", "PROP_QUEUE") ; + + System.out.println("Creating Topic Subscribers...") ; + + subs = new TopicSubscriber[3] ; + subs[0] = ((AQjmsSession)tsess).createDurableSubscriber( + topic1, "PROG1", null, false); + subs[1] = ((AQjmsSession)tsess).createDurableSubscriber( + topic1, "PROG2", "JMSPriority > 2", false); + subs[2] = tsess.createDurableSubscriber( + topic2, "PROG3", null , false) ; + + agt = new AQjmsAgent("PROG3", "PROP_QUEUE" ) ; + + System.out.println("Creating Remote Subscriber...") ; + ((AQjmsSession)tsess).createRemoteSubscriber( + topic1, agt,"JMSPriority = 2"); + + /* Schedule Propagation with latency 0 */ + System.out.println("Schedule Propagation...") ; + ((AQjmsDestination)topic1).schedulePropagation( + tsess, null, null, null, null, new Double(0)) ; + + System.out.println("Publish messages...") ; + objmsg = ((AQjmsSession)tsess).createObjectMessage() ; + + publisher = tsess.createPublisher(topic1); + + /*publish 100 messages*/ + + for ( int i = 1 ; i <= 100 ; i++) + { + objmsg.setIntProperty("Id",i) ; + if ( ( i % 3 ) == 0 ) { + objmsg.setStringProperty("City",cities[0]) ; + } + else if ((i % 4 ) == 0) { + objmsg.setStringProperty("City",cities[1]) ; + } + else if (( i % 2) == 0) { + objmsg.setStringProperty("City",cities[2]) ; + } + else { + objmsg.setStringProperty("City",cities[3]) ; + } + + objmsg.setIntProperty("Priority",(1+ (i%3))) ; + + sobj = new Message() ; + sobj.setId(i) ; + sobj.setName("message# "+i) ; + sobj.setData(500); + objmsg.setObject(sobj) ; + objmsg.setJMSCorrelationID(""+i) ; + objmsg.setJMSPriority(1+(i%3)) ; + publisher.publish(topic1,objmsg, DeliveryMode.PERSISTENT, + 1 +(i%3), AQjmsConstants.EXPIRATION_NEVER); + } + System.out.println("Commit now...") ; + tsess.commit() ; + + Thread.sleep(50000); + + /* Receive messages for each subscriber */ + System.out.println("Receive Messages...") ; + for (int i=0; i< subs.length ; i++) + { + System.out.println ("Messages for subscriber : " +i) ; + if (subs[i].getMessageSelector() != null) + { + System.out.println(" with selector: " + + subs[i].getMessageSelector()); + } + + boolean done = false; + while(!done) { + try { + robjmsg = (ObjectMessage)( subs[i].receiveNoWait() ); + if (robjmsg != null) + { + rmsg = (Message)robjmsg.getObject(); + System.out.print("Name : " +rmsg.getName()) ; + System.out.print(" Pri: " +robjmsg.getJMSPriority()) ; + System.out.print(" Message: " +robjmsg.getIntProperty("Id")) ; + System.out.print(" " +robjmsg.getStringProperty("City")) ; + System.out.println(" " +robjmsg.getIntProperty("Priority")) ; + } + else { + System.out.println ("No more messages.") ; + done=true; + } + tsess.commit(); + } catch (Exception e) { + System.out.println("Error in performJmsOperations: " + e) ; + done=true; + } + } /* while loop*/ + } + ((AQjmsDestination)topic1).unschedulePropagation(tsess,null); + } catch (Exception e) { + System.out.println("Error in performJmsOperations: " + e) ; + throw e; + } + } /* end of demo06 */ +} diff --git a/aqjmsdemo07.java b/aqjmsdemo07.java new file mode 100644 index 0000000..72d0edf --- /dev/null +++ b/aqjmsdemo07.java @@ -0,0 +1,418 @@ +/* $Header: aqjmsdemo07.java 05-jun-2007.15:10:25 aatam Exp $ */ + +/* Copyright (c) 2002, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + AQ/OJMS XML payload demo + + PRIVATE CLASSES + + + NOTES + see below + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - + jleinawe 04/18/05 - update lcr format + jleinawe 12/20/02 - update instructions + rbhyrava 10/07/02 - import oracle.jdbc.* + jleinawe 09/04/02 - jleinawe_new_aq_demos + jleinawe 08/30/02 - Creation + */ + +/** + * @version $Header: aqjmsdemo07.java 05-jun-2007.15:10:25 aatam Exp $ + * @author jleinawe + * @since release specific (what release of product did this appear in) + */ + +/**** + * This is a sample java file which uses Oracle JMS - Java Message Service + * API to Enqueue/Dequeue an XML message using a sys.Anydata queue. + * + * This demo does the following: + * - creates an Anydata Queue + * - creates a QueueSender + * - sends a message containing an XML message body + * - create a QueueReceiver + * - receives and prints the XML message + * - drops the Anydata Queue + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + * + ***/ + +import javax.jms.*; +import java.sql.*; +import oracle.AQ.*; +import oracle.jms.*; +import oracle.xdb.*; + +public class aqjmsdemo07 +{ + + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + try + { + String ora_sid; + String host; + int port; + try + { + ora_sid = args[0]; + host = args[1]; + port = Integer.parseInt(args[2]); + + System.out.println ("ora_sid: " + ora_sid); + System.out.println ("host: " + host); + System.out.println ("port: " + port); + + init(ora_sid, host, port); + EnqueueAnydata(ora_sid, host, port); + DequeueAnydata(ora_sid, host, port); + tearDown(ora_sid, host, port); + System.out.println("End of Demo"); + } + catch (ArrayIndexOutOfBoundsException ex) + { + System.out.println ("Not enough parameters. " + + "Usage: java filename [SID] [HOST] [PORT]\n" + + "\tExample: java aqjmsdemo07 orcl myserver 1521"); + return; + } + } + catch (Exception ex) + { + System.out.println("Exception: " + ex); + ex.printStackTrace(); + } + } + + + public static void EnqueueAnydata(String ora_sid, String host, int port) + { + QueueConnectionFactory qc_fact = null; + QueueConnection q_conn = null; + QueueSession q_sess = null; + java.sql.Connection db_conn = null; + AQQueueTableProperty qt_prop = null; + AQQueueTable q_table = null; + AQjmsDestinationProperty dest_prop = null; + javax.jms.Queue queue = null; + AdtMessage adt_msg = null; + QueueSender q_sender = null; + Message jms_msg = null; + oracle.xdb.XMLType xtype = null; + String data = null; + + + try + { + qc_fact = AQjmsFactory.getQueueConnectionFactory(host, + ora_sid, port, "oci8"); + + q_conn = qc_fact.createQueueConnection("jmsuser", "JMSUSER"); + q_sess = q_conn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + + q_conn.start(); + db_conn = ((AQjmsSession)q_sess).getDBConnection(); + + queue = ((AQjmsSession)q_sess).getQueue("jmsuser", "xmlq"); + + // + // create sender + // + q_sender = q_sess.createSender(queue); + + // + // create ade message + // + adt_msg = ((AQjmsSession)q_sess).createAdtMessage(); + + System.out.println("start xml convert"); + + data = " \n" + + "source_dbname \n" + + "INSERT \n" + + "RAM \n" + + "EMP \n" + + "0ABC \n" + + "0.0.0 \n" + + "0 \n" + + " \n" + + " \n" + + "C01 \n" + + "Clob old \n" + + " \n" + + " \n" + + "C02 \n" + + "A123FF \n" + + " \n" + + " \n" + + "C03 \n" + + " \n" + + "1997/11/24 00:00:00SYYYY/MM/DD HH24:MI:SS \n" + + " \n" + + " \n" + + " \n" + + "C04 \n" + + " \n" + + "1999/05/31 13:20:00.000000000SYYYY/MM/DD HH24:MI:SSXFF9 \n" + + " \n" + + " \n" + + " \n" + + "C05 \n" + + "0ABCDE \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "C01 \n" + + "A123FF \n" + + " \n" + + " \n" + + "C02 \n" + + "35.23 \n" + + " \n" + + " \n" + + "C03 \n" + + "-100000 \n" + + " \n" + + " \n" + + "C04 \n" + + "Hel lo \n" + + " \n" + + " \n" + + "C05 \n" + + "wor ld \n" + + " \n" + + " \n" + + ""; + + + xtype = oracle.xdb.XMLType.createXML(db_conn, data); + + adt_msg.setAdtPayload(xtype); + + System.out.println("Enqueue anydata(xmltype) message"); + + // + // send the message + // + ((AQjmsQueueSender)q_sender).send(queue, adt_msg, + DeliveryMode.PERSISTENT, 1, + AQjmsConstants.EXPIRATION_NEVER); + + q_sess.commit(); + q_sess.close(); + q_conn.close(); + + } + catch (java.sql.SQLException sql_ex) + { + System.out.println("Exception: " + sql_ex); + sql_ex.printStackTrace(); + } + catch (JMSException aq_ex) + { + System.out.println("Exception: " + aq_ex); + aq_ex.printStackTrace(); + + if(aq_ex.getLinkedException() != null) + { + aq_ex.getLinkedException().printStackTrace(); + } + } + + } + + + public static void DequeueAnydata(String ora_sid, String host, int port) + { + QueueConnectionFactory qc_fact = null; + QueueConnection q_conn = null; + QueueSession q_sess = null; + java.sql.Connection db_conn = null; + AQQueueTableProperty qt_prop = null; + AQQueueTable q_table = null; + AQjmsDestinationProperty dest_prop = null; + javax.jms.Queue queue = null; + AdtMessage adt_msg = null; + AdtMessage adt_msg2 = null; + QueueReceiver q_receiver= null; + TextMessage t_msg = null; + javax.jms.Message jms_msg = null; + oracle.xdb.XMLType xtype2 = null; + + try + { + qc_fact = AQjmsFactory.getQueueConnectionFactory(host, + ora_sid, port, "oci8"); + + q_conn = qc_fact.createQueueConnection("jmsuser", "JMSUSER"); + q_sess = q_conn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + + q_conn.start(); + db_conn = ((AQjmsSession)q_sess).getDBConnection(); + + // + // get queue xmlq + // + queue = ((AQjmsSession)q_sess).getQueue("jmsuser", "xmlq"); + + // + // Create receiver + // + q_receiver = ((AQjmsSession)q_sess).createReceiver(queue); + + // + // Receive message + // + jms_msg = (javax.jms.Message) q_receiver.receive(); + + // + // output message contents + // + if(jms_msg == null) + System.out.println("Null message received"); + else + { + if(jms_msg instanceof AdtMessage) + { + adt_msg2 = (AdtMessage)jms_msg; + System.out.println("Retrieved message: " + adt_msg2.getAdtPayload()); + + if(adt_msg2.getAdtPayload() instanceof oracle.xdb.XMLType) + { + xtype2 = (XMLType)adt_msg2.getAdtPayload(); + System.out.println("Data: \n" + xtype2.getStringVal()); + } + + System.out.println("Msg id: " + adt_msg2.getJMSMessageID()); + q_sess.commit(); + } + else + System.out.println("Invalid message type"); + } + q_conn.close(); + } + catch (java.sql.SQLException sql_ex) + { + System.out.println("Exception: " + sql_ex); + sql_ex.printStackTrace(); + } + catch (JMSException aq_ex) + { + System.out.println("Exception: " + aq_ex); + aq_ex.printStackTrace(); + + if(aq_ex.getLinkedException() != null) + { + aq_ex.getLinkedException().printStackTrace(); + } + } + catch (Exception ex) + { + System.out.println("Exception: " + ex); + ex.printStackTrace(); + } + } + + + public static void init(String ora_sid, String host, int port) + { + java.sql.Connection conn = null; + String url = null; + String jmsCall = null; + CallableStatement stmt = null; + try + { + // + // setup connection (either thin or oci8) + // + url = new String ("jdbc:oracle:oci8:"); + url = url.concat("@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(PORT=" +port); + url = url.concat(")(HOST=" +host+ "))(CONNECT_DATA=(SID=" + + ora_sid+ ")))"); + DriverManager.registerDriver(new oracle.jdbc.OracleDriver()); + conn = DriverManager.getConnection(url, "jmsuser", "JMSUSER"); + + // + // create queue table xmlq_t and enable it for jms types + // + jmsCall ="{call dbms_aqadm.create_queue_table( queue_table => 'xmlq_t',"+ + " multiple_consumers => false, "+ + "queue_payload_type => 'sys.ANYDATA',compatible => '8.1.3')}"; + stmt = conn.prepareCall(jmsCall); + stmt.execute(); + + // enable jms types + jmsCall = "{call dbms_aqadm.enable_jms_types('xmlq_t')}"; + stmt = conn.prepareCall(jmsCall); + stmt.execute(); + + // + // create queue xmlq + // + jmsCall = "{call dbms_aqadm.create_queue(queue_name => 'xmlq',"+ + " queue_table => 'xmlq_t')}"; + stmt = conn.prepareCall(jmsCall); + stmt.execute(); + + // + // start queue xmlq + // + jmsCall = "{call dbms_aqadm.start_queue(queue_name => 'xmlq')}"; + stmt = conn.prepareCall(jmsCall); + stmt.execute(); + + conn.close(); + } + catch (SQLException s) + { + System.out.println("Exception: "+s); + s.printStackTrace(); + } + } + + + public static void tearDown(String ora_sid, String host, int port) + { + java.sql.Connection conn = null; + String url = null; + String jmsCall = null; + CallableStatement stmt = null; + try + { + // + // Drop queue table 'xmlq_t' + // + url = new String ("jdbc:oracle:oci8:"); + url = url.concat("@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(PORT=" +port); + url = url.concat(")(HOST=" +host+ "))(CONNECT_DATA=(SID=" + + ora_sid+ ")))"); + DriverManager.registerDriver(new oracle.jdbc.OracleDriver()); + conn = DriverManager.getConnection(url, "jmsuser", "JMSUSER"); + + jmsCall = "{call dbms_aqadm.drop_queue_table( queue_table => 'xmlq_t',"+ + " force => TRUE)}"; + stmt = conn.prepareCall(jmsCall); + stmt.execute(); + + conn.close(); + } + catch (SQLException s) + { + s.printStackTrace(); + } + } +} diff --git a/aqjmsdemo08.java b/aqjmsdemo08.java new file mode 100644 index 0000000..4b7506d --- /dev/null +++ b/aqjmsdemo08.java @@ -0,0 +1,410 @@ +/* $Header: aqjmsdemo08.java 05-jun-2007.15:10:25 aatam Exp $ */ + +/* Copyright (c) 2002, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + OJMS JMS 1.1 domain unification demo + + PRIVATE CLASSES + None + + NOTES + This sample performs JMS topic and queue operations using the same JMS + connection and session and in the context of the same transaction using + JMS 1.1 domain unified apis. + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - + jleinawe 09/19/03 - no destination for Producer.send(...) + jleinawe 12/20/02 - update instructions + jleinawe 11/01/02 - + vmaganty 10/04/02 - checkin OJMS JMS 1.1 compliance changes + vmaganty 09/20/02 - Creation + */ + +/** + * @version $Header: aqjmsdemo08.java 05-jun-2007.15:10:25 aatam Exp $ + * @author vmaganty + * @since release specific (what release of product did this appear in) + */ + + +/*** This is a sample java file which uses Oracle JMS - Java Messaging + * Service API to Enqueue/Dequeue JMS Messages from both queues and + * topics in the same transaction using the same session and + * connection using the JMS 1.1 domain unfied APIs. + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + * + ***/ +/* import useful packages */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; + +public class aqjmsdemo08 +{ + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + Session sess = null; + ConnectionFactory cfact = null; + Connection conn = null; + try { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + System.out.println("Create connection factory, connection and session"); + cfact = + AQjmsFactory.getConnectionFactory(args[1], args[0], + Integer.parseInt(args[2]), + args[3]); + + conn = cfact.createConnection( "jmsuser","JMSUSER"); + + /* Create a Topic Session */ + sess = conn.createSession(true, Session.CLIENT_ACKNOWLEDGE); + + System.out.println("Start the connection"); + conn.start() ; + + System.out.println("Setup a queue and a topic"); + setupQueue(sess) ; + setupTopic(sess) ; + + System.out.println("Perform queue and topic operations on the same connection and session in the same transaction"); + System.out.println("Begin transaction"); + enqueueMessages(sess); + dequeueMessages(sess); + performTopicOperations(sess); + System.out.println("Committing transaction"); + sess.commit(); + System.out.println("Cleaning up"); + sess.unsubscribe("atlanta"); + sess.close() ; + conn.close() ; + System.out.println("End of Demo") ; + } + } + catch (Exception ex) { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void setupTopic(Session sess) throws Exception + { + AQQueueTableProperty qtprop ; + AQQueueTable qtable; + AQjmsDestinationProperty dprop; + Topic topic; + + try { + /* Create Queue Tables */ + System.out.println("Creating Queue Table...") ; + + /* Drop the queue if already exists */ + try { + qtable=((AQjmsSession)sess).getQueueTable("jmsuser", "jmstxtqtable" ); + qtable.drop(true); + } catch (Exception e) {} ; + + qtprop = new AQQueueTableProperty ("SYS.AQ$_JMS_TEXT_MESSAGE") ; + qtprop.setMultiConsumer(true) ; + qtprop.setCompatible("8.1") ; + qtprop.setPayloadType("SYS.AQ$_JMS_TEXT_MESSAGE") ; + qtable = ((AQjmsSession)sess).createQueueTable("JMSUSER", + "jmstxtqtable", qtprop) ; + + System.out.println ("Creating Topic ..."); + dprop = new AQjmsDestinationProperty() ; + topic=((AQjmsSession)sess).createTopic( qtable,"jmstopic",dprop) ; + + /* Start the topic */ + ((AQjmsDestination)topic).start(sess, true, true); + System.out.println("Successfully setup Topic"); + } catch (Exception ex) { + System.out.println("Error in setupTopic: " + ex); + throw ex; + } + } + + public static void performTopicOperations(Session sess) + { + Topic topic = null; + MessageConsumer mcon; + TopicSubscriber tsub; + MessageProducer mprod; + TextMessage txtmsg, dtxtmsg; + + try { + System.out.println ("Get the Topic..."); + topic = ((AQjmsSession)sess).getTopic("JMSUSER","jmstopic") ; + + System.out.println("Creating a nondurable MessageConsumer with selector...") ; + + mcon = + sess.createConsumer(topic, + "(year = 1998 OR color NOT IN ('GREEN','RED','WHITE')) " + + " AND make IN ('ACURA ', 'BMW', 'MERCEDES')", false); + + System.out.println("Creating a durable TopicSubscriber with selector...") ; + + tsub = sess.createDurableSubscriber(topic, "atlanta", + "price < 20000", false ); + + + System.out.println("Produce and send text messages to topic...") ; + + mprod = sess.createProducer(topic); + + txtmsg = sess.createTextMessage() ; + txtmsg.setText("Cars Distribution") ; + txtmsg.setObjectProperty("carno", new Integer(12345)) ; + txtmsg.setStringProperty("color", "BLUE") ; + txtmsg.setIntProperty("year", 1999) ; + txtmsg.setStringProperty("make", "BMW") ; + txtmsg.setDoubleProperty("price", 25995) ; + txtmsg.setJMSCorrelationID("dallas") ; + + mprod.send(txtmsg) ; + + txtmsg.clearProperties() ; + txtmsg.setObjectProperty("carno", new Integer(55)) ; + txtmsg.setStringProperty("color", "CYAN") ; + txtmsg.setIntProperty("year", 2000) ; + txtmsg.setStringProperty("make", "MERCEDES") ; + txtmsg.setDoubleProperty("price", 19000) ; + txtmsg.setJMSCorrelationID("atlanta") ; + + mprod.send(txtmsg) ; + + txtmsg.clearProperties() ; + txtmsg.setObjectProperty("carno", new Integer(99099)) ; + txtmsg.setStringProperty("color", "RED") ; + txtmsg.setIntProperty("year", 1998) ; + txtmsg.setStringProperty("make", "ACURA") ; + txtmsg.setDoubleProperty("price", 19995) ; + txtmsg.setJMSCorrelationID("atlanta") ; + + mprod.send(txtmsg) ; + + // sess.commit() ; + + System.out.println ("Consume messages from topic using non durable consumer") ; + boolean done = false ; + while (!done) { + dtxtmsg = (TextMessage) (mcon.receiveNoWait() ) ; + + if (dtxtmsg == null) { + done=true; + } else + { + System.out.print(" Color: " + dtxtmsg.getStringProperty("color")); + System.out.print(" Make: " + dtxtmsg.getStringProperty("make")); + System.out.print(" Year: " + dtxtmsg.getStringProperty("year")); + System.out.print(" Price: " + dtxtmsg.getStringProperty("price")); + System.out.println(" Carno: " + dtxtmsg.getStringProperty("carno")); + } + } + + System.out.println ("Consume messages from topic using durable subscriber") ; + done=false ; + while (!done) { + dtxtmsg = (TextMessage) (tsub.receiveNoWait() ) ; + + if (dtxtmsg == null) { + done=true; + } else + { + System.out.print(" Color: " + dtxtmsg.getStringProperty("color")); + System.out.print(" Make: " + dtxtmsg.getStringProperty("make")); + System.out.print(" Year: " + dtxtmsg.getStringProperty("year")); + System.out.print(" Price: " + dtxtmsg.getStringProperty("price")); + System.out.println(" Carno: " + dtxtmsg.getStringProperty("carno")); + } + } + + + // sess.commit() ; + + ((AQjmsDestination)topic).stop(sess, true, true, false); + + } catch (Exception e) { + System.out.println("Error in performJmsOperations: " + e) ; + } + } + + + public static void setupQueue(Session sess) throws Exception + { + AQQueueTableProperty qtprop ; + AQQueueTable qtable; + AQjmsDestinationProperty dprop; + javax.jms.Queue q1; + + try { + + /* Create Queue Tables */ + System.out.println("Creating Queue Table...") ; + + qtprop = new AQQueueTableProperty ("SYS.AQ$_JMS_MAP_MESSAGE") ; + qtprop.setCompatible("8.1") ; + qtprop.setPayloadType("SYS.AQ$_JMS_MAP_MESSAGE") ; + + /* Drop if the queue table already exists */ + try { + qtable=((AQjmsSession)sess).getQueueTable("JMSUSER", "JMSMAPQTABLE"); + qtable.drop(true); + } catch (Exception e) {} + + qtable = ((AQjmsSession)sess).createQueueTable("JMSUSER", + "jmsmapqtable", qtprop) ; + + System.out.println ("Creating Queue..."); + dprop = new AQjmsDestinationProperty() ; + q1=((AQjmsSession)sess).createQueue(qtable,"JMS_MAPQ",dprop) ; + + /* Start the Queue */ + ((AQjmsDestination)q1).start(sess, true, true); + + System.out.println("Successfully setup Queue"); + } catch (Exception ex) { + System.out.println("Error in setupQueue: " + ex); + throw ex; + } + } + + public static void enqueueMessages(Session sess) throws Exception + { + javax.jms.Queue q1 ; + MapMessage[] Messages; + byte[] barray ; + MessageProducer mprod; + + StringBuffer txtbuf ; + TextMessage txtmsg, dtxtmsg; + try + { + /* Get Queue */ + q1 = ((AQjmsSession)sess).getQueue("JMSUSER", "JMS_MAPQ") ; + + System.out.println("Produce and send text messages to queue...") ; + + barray = new byte[25] ; + for ( int i=0 ; i< 25 ; i++) barray[i] = 67 ; + + Messages = new MapMessage[5] ; + + Messages[0] = sess.createMapMessage() ; + Messages[0].setIntProperty ("carno", 3355) ; + Messages[0].setStringProperty ("color", "BLUE") ; + Messages[0].setStringProperty ("make", "BMW") ; + Messages[0].setDoubleProperty ("price", 20000) ; + Messages[0].setIntProperty ("year", 1999) ; + + Messages[1] = sess.createMapMessage() ; + Messages[1].setIntProperty ("carno", 4444) ; + Messages[1].setStringProperty ("color", "BLACK") ; + Messages[1].setStringProperty ("make", "ACURA") ; + Messages[1].setDoubleProperty ("price", 22995) ; + Messages[1].setIntProperty ("year", 1998) ; + + Messages[2] = sess.createMapMessage() ; + Messages[2].setIntProperty ("carno", 1212) ; + Messages[2].setStringProperty ("color", "BLUE") ; + Messages[2].setStringProperty ("make", "MERCEDES") ; + Messages[2].setDoubleProperty ("price", 30995) ; + Messages[2].setIntProperty ("year", 2001) ; + + Messages[3] = sess.createMapMessage() ; + Messages[3].setIntProperty ("carno", 5345) ; + Messages[3].setStringProperty ("color", "GREEN") ; + Messages[3].setStringProperty ("make", "LEXUS") ; + Messages[3].setDoubleProperty ("price", 21895) ; + Messages[3].setIntProperty ("year", 1995) ; + + Messages[4] = sess.createMapMessage() ; + Messages[4].setIntProperty ("carno", 8909) ; + Messages[4].setStringProperty ("color", "BLUE") ; + Messages[4].setStringProperty ("make", "BMW") ; + Messages[4].setDoubleProperty ("price", 40995) ; + Messages[4].setIntProperty ("year", 2002) ; + + /* Create Queue Sender */ + mprod = sess.createProducer(q1) ; + + for ( int i = 0 ; i < 5 ; i++ ) + { + Messages[i].setBytes("Picture" , barray) ; + Messages[i].setJMSCorrelationID(Messages[i].getStringProperty("color")); + System.out.println("Sending "+Messages[i].getStringProperty ("color") + + " " + Messages[i].getStringProperty("make") + + " " + Messages[i].getIntProperty("year") + + " " + Messages[i].getDoubleProperty("price")) ; + + mprod.send(Messages[i], DeliveryMode.PERSISTENT, + 1+ (i%10) , AQjmsConstants.EXPIRATION_NEVER ) ; + try { + Thread.sleep(5000) ; + } catch (InterruptedException e) {} ; + // sess.commit() ; + } + System.out.println("Successfully Sent Messages."); + + } catch (JMSException e) { + System.out.println("Error in Sending Messages : " + e) ; + throw e; + } + } + + public static void dequeueMessages(Session sess) throws Exception + { + MapMessage mm; + int mesgno = 0; + javax.jms.Queue queue; + MessageConsumer mcon; + + try + { + System.out.println("Get the Destination") ; + queue = ((AQjmsSession)sess).getQueue("JMSUSER", "JMS_MAPQ") ; + + System.out.println("Create message consumer with selector...") ; + mcon = sess.createConsumer((Destination) queue, "JMSCorrelationID='BLUE'") ; + + System.out.println("Receive messages using the message consumer...") ; + boolean done = false ; + while (!done) { + mm = (MapMessage) (mcon.receiveNoWait() ) ; + + if (mm == null) { + done=true; + } else { + mesgno++; + System.out.println("Retrieved message " + + mesgno + " with correlation: " + mm.getJMSCorrelationID()); + System.out.println (" "+ mm.getStringProperty ("color") + + " " + mm.getStringProperty("make") + + " " + mm.getIntProperty("year") + + " " + mm.getDoubleProperty("price")) ; + } + } + + /* + try { + sess.commit() ; + } catch (Exception e) { + System.out.println("Exception on Session Commit " + e) ; + } + */ + } catch (JMSException e) { + System.out.println("Exception onMessage:" + e) ; + } + } +} + diff --git a/aqjmsdemo09.java b/aqjmsdemo09.java new file mode 100644 index 0000000..8111644 --- /dev/null +++ b/aqjmsdemo09.java @@ -0,0 +1,429 @@ +/* $Header: aqjmsdemo09.java 05-jun-2007.15:10:27 aatam Exp $ */ + +/* Copyright (c) 2002, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - + jleinawe 12/20/02 - update instructions + jleinawe 11/19/02 - queue name conflict + vmaganty 11/05/02 - OJMS bulk enqueue/dequeue changes + vmaganty 10/30/02 - Creation + */ + +/** + * @version $Header: aqjmsdemo09.java 05-jun-2007.15:10:27 aatam Exp $ + * @author vmaganty + * @since release specific (what release of product did this appear in) + */ + + +/*** This is a sample java file which uses Oracle JMS - Oracle + * specific bulk array enqueue dequeue messaging APIs to + * Enqueue/Dequeue JMS Messages from both queues and topics in the + * same transaction using the same session and connection using JMS + * 1.1 domain unfied APIs. + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + * + ***/ + +/* import useful packages */ +import oracle.AQ.*; +import javax.jms.*; +import oracle.jms.*; +import java.lang.*; + +public class aqjmsdemo09 +{ + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + Session sess = null; + ConnectionFactory cfact = null; + Connection conn = null; + try { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + System.out.println("Create connection factory, connection and session"); + cfact = + AQjmsFactory.getConnectionFactory(args[1], args[0], + Integer.parseInt(args[2]), + args[3]); + + conn = cfact.createConnection( "jmsuser","JMSUSER"); + + /* Create a Topic Session */ + sess = conn.createSession(true, Session.CLIENT_ACKNOWLEDGE); + + System.out.println("Start the connection"); + conn.start() ; + + System.out.println("Setup a queue and a topic"); + setupQueue(sess) ; + setupTopic(sess) ; + System.out.println("Perform bulk queue and topic operations on the"); + System.out.println("same connection and session in the same transaction"); + System.out.println("Begin transaction"); + enqueueMessages(sess); + dequeueMessages(sess); + + performTopicOperations(sess); + System.out.println("Committing transaction"); + sess.commit(); + System.out.println("Cleaning up"); + sess.unsubscribe("atlanta"); + sess.close() ; + conn.close() ; + System.out.println("End of Demo") ; + } + } + catch (Exception ex) { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void setupTopic(Session sess) throws Exception + { + AQQueueTableProperty qtprop ; + AQQueueTable qtable; + AQjmsDestinationProperty dprop; + Topic topic; + + try { + /* Create Queue Tables */ + System.out.println("Creating Queue Table...") ; + + /* Drop the queue if already exists */ + try { + qtable=((AQjmsSession)sess).getQueueTable("jmsuser", "jmst9table" ); + qtable.drop(true); + } catch (Exception e) {} ; + + qtprop = new AQQueueTableProperty ("SYS.AQ$_JMS_MESSAGE") ; + qtprop.setMultiConsumer(true) ; + qtprop.setCompatible("8.1") ; + qtprop.setPayloadType("SYS.AQ$_JMS_MESSAGE") ; + qtable = ((AQjmsSession)sess).createQueueTable("JMSUSER", + "jmst9table", qtprop) ; + + System.out.println ("Creating Topic ..."); + dprop = new AQjmsDestinationProperty() ; + topic=((AQjmsSession)sess).createTopic( qtable,"JMSDemoTopic9",dprop) ; + + /* Start the topic */ + ((AQjmsDestination)topic).start(sess, true, true); + System.out.println("Successfully setup Topic"); + } catch (Exception ex) { + System.out.println("Error in setupTopic: " + ex); + throw ex; + } + } + + public static void performTopicOperations(Session sess) + { + Topic topic = null; + MessageConsumer mcon; + TopicSubscriber tsub; + MessageProducer mprod; + javax.jms.Message[] send_messages = null; + javax.jms.Message[] receive_messages = null; + + try { + System.out.println ("Get the Topic..."); + topic = ((AQjmsSession)sess).getTopic("JMSUSER","JMSDemoTopic9") ; + + System.out.println("Creating a nondurable MessageConsumer with selector...") ; + + mcon = + sess.createConsumer(topic, + "(year = 1998 OR color NOT IN ('GREEN','RED','WHITE')) " + + " AND make IN ('ACURA ', 'BMW', 'MERCEDES')", false); + + System.out.println("Creating a durable TopicSubscriber with selector...") ; + + tsub = sess.createDurableSubscriber(topic, "atlanta", + "price < 20000", false ); + + + System.out.println("Produce and send assorted messages to topic...") ; + + send_messages = new javax.jms.Message[4]; + + mprod = sess.createProducer(topic); + + + send_messages[0] = (javax.jms.Message) (sess.createMapMessage()); + send_messages[0].setObjectProperty("carno", new Integer(55)) ; + send_messages[0].setStringProperty("color", "CYAN") ; + send_messages[0].setIntProperty("year", 2000) ; + send_messages[0].setStringProperty("make", "MERCEDES") ; + send_messages[0].setDoubleProperty("price", 19000) ; + send_messages[0].setJMSCorrelationID("atlanta") ; + + send_messages[1] = (javax.jms.Message) (sess.createBytesMessage()) ; + ((BytesMessage) send_messages[1]).writeBytes("Cars Distribution".getBytes()) ; + send_messages[1].setObjectProperty("carno", new Integer(12345)) ; + send_messages[1].setStringProperty("color", "BLUE") ; + send_messages[1].setIntProperty("year", 1999) ; + send_messages[1].setStringProperty("make", "BMW") ; + send_messages[1].setDoubleProperty("price", 15995) ; + send_messages[1].setJMSCorrelationID("dallas") ; + + + send_messages[2] = (javax.jms.Message) (sess.createStreamMessage()); + send_messages[2].setObjectProperty("carno", new Integer(99099)) ; + send_messages[2].setStringProperty("color", "RED") ; + send_messages[2].setIntProperty("year", 1998) ; + send_messages[2].setStringProperty("make", "ACURA") ; + send_messages[2].setDoubleProperty("price", 19995) ; + send_messages[2].setJMSCorrelationID("seattle") ; + + send_messages[3] = (javax.jms.Message) (sess.createTextMessage()) ; + ((TextMessage) send_messages[3]).setText("Cars WholeSale") ; + send_messages[3].setObjectProperty("carno", new Integer(5678)) ; + send_messages[3].setStringProperty("color", "RED") ; + send_messages[3].setIntProperty("year", 2003) ; + send_messages[3].setStringProperty("make", "Subaru") ; + send_messages[3].setDoubleProperty("price", 18488) ; + send_messages[3].setJMSCorrelationID("portland") ; + + + ((AQjmsProducer) mprod).bulkSend((Destination) topic, send_messages) ; + + // sess.commit() ; + + System.out.println ("Consume messages in bulk from topic using non durable consumer") ; + boolean done = false ; + while (!done) { + receive_messages = ((AQjmsConsumer) mcon).bulkReceiveNoWait(2); + + if (receive_messages == null) { + done=true; + } else { + for ( int i=0; i + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - + jleinawe 03/13/03 - jleinawe_newaqdemos + jleinawe 03/11/03 - Creation + */ + +/** + * @version $Header: aqjmsdemo10.java 07-jun-2007.14:35:37 aatam Exp $ + * @author jleinawe + * @since release specific (what release of product did this appear in) + */ + +/*** This is a sample java file which shows messaging with SYS.ANYDATA queues + * It will demonstrate a send/receive using each of the five JMS Message + * Types (Text, Map, Object, Bytes, Stream) and with an AdtMessage. + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt + * + * Note: SYS.ANYDATA Queue Types are not supported for thin jdbc driver + ***/ + +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; + +public class aqjmsdemo10 +{ + public static void main (String args[]) + throws Exception + { + javax.jms.QueueConnectionFactory qcf = null; + javax.jms.QueueConnection qconn = null; + javax.jms.QueueSession qsession = null; + javax.jms.Queue queue = null; + + if (args.length < 3) + System.out.println("Usage: java filename [SID] [HOST] [PORT]"); + else + { + // + // setup + // + qcf = AQjmsFactory.getQueueConnectionFactory( + args[1], args[0], Integer.parseInt(args[2]), "oci8"); + qconn = qcf.createQueueConnection( "jmsuser","JMSUSER"); + qsession = qconn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + qconn.start() ; + queue = setup(qsession); + + // + // run the demo + // + enqueueMessages(qsession, queue); + dequeueMessages(qsession, queue); + + // + // cleanup and exit + // + cleanup(qsession); + qsession.close(); + qconn.close(); + } + System.out.println("End of Demo"); + } + + +/** + * Enqueue each type of JMS Message on the ANYDATA queue + */ + public static void enqueueMessages(QueueSession session, javax.jms.Queue queue) + throws javax.jms.JMSException, java.sql.SQLException + { + StringBuffer msgBody = null;; + javax.jms.QueueSender sender = null; + javax.jms.Message message = null; + oracle.jms.AdtMessage adt_message = null; + Cars car = null; + int counter = 0; + + // + // create the QueueSender + // + sender= session.createSender(queue); + + // + // send a message for each message type + // + + // TextMessage + msgBody = new StringBuffer("This is a Text Message"); + message = session.createTextMessage(); + ((TextMessage)message).setText(msgBody.toString()); + sender.send(message); + System.out.println("Sent TextMessage"); + counter++; + + // MapMessage + msgBody = new StringBuffer("This is a Map Message"); + message = session.createMapMessage(); + ((MapMessage)message).setString("stringbuf", msgBody.toString()); + sender.send(message); + System.out.println("Sent MapMessage"); + counter++; + + // ObjectMessage + msgBody = new StringBuffer("This is a Object Message"); + message = session.createObjectMessage(); + ((ObjectMessage)message).setObject(msgBody); + sender.send(message); + System.out.println("Sent ObjectMessage"); + counter++; + + // BytesMessage + msgBody = new StringBuffer("This is a Bytes Message"); + message = session.createBytesMessage(); + ((BytesMessage)message).writeBytes(msgBody.toString().getBytes()); + sender.send(message); + System.out.println("Sent BytesMessage"); + counter++; + + // StreamMessage + msgBody = new StringBuffer("This is a Stream Message"); + message = session.createStreamMessage(); + ((StreamMessage)message).writeBytes(msgBody.toString().getBytes()); + sender.send(message); + System.out.println("Sent StreamMessage"); + counter++; + + // ADT Message + car = new Cars(); + car.setCarno(new java.math.BigDecimal(11051963)); + car.setMake("CHEVROLET"); + car.setColor("BLUE"); + car.setPrice(new java.math.BigDecimal(21099)); + adt_message = ((AQjmsSession)session).createAdtMessage(); + adt_message.setAdtPayload(car); + sender.send(adt_message); + System.out.println("Sent AdtMessage"); + counter++; + + // + // commit the sends + // + session.commit(); + System.out.println("Sent a total of "+counter+" messages"); + + sender.close(); + } + + +/** + * Dequeue each message enqueued on the ANYDATA Queue + */ + public static void dequeueMessages(QueueSession session, javax.jms.Queue queue) + throws javax.jms.JMSException, java.lang.ClassNotFoundException, + java.sql.SQLException + { + javax.jms.QueueReceiver receiver = null; + javax.jms.Message message = null; + int counter = 0; + java.util.Dictionary map = null; + + // + // setup mapping (needed because we have an AdtMessage) + // + map = (java.util.Dictionary)((AQjmsSession)session).getTypeMap(); + map.put("JMSUSER.CARS", Class.forName("Cars")); + + // + // create receiver + // + receiver = session.createReceiver(queue); + + // + // receive all messages on the queue + // + boolean nullMsgReceive = false; + while (!nullMsgReceive) + { + message = (javax.jms.Message) receiver.receive(20000); + + if (message == null) + { + System.out.println("Received a total of "+counter+" messages"); + nullMsgReceive = true; + } + else + { + counter++; + if (message instanceof TextMessage) + { + String body = ((TextMessage)message).getText(); + System.out.println("Received TextMessage: "+body); + } + else if (message instanceof MapMessage) + { + String body = ((MapMessage)message).getString("stringbuf"); + System.out.println("Received MapMessage: "+body); + } + else if (message instanceof ObjectMessage) + { + StringBuffer strbuf + = (StringBuffer)((ObjectMessage)message).getObject(); + System.out.println("Received ObjectMessage: "+strbuf.toString()); + } + else if (message instanceof StreamMessage) + { + byte[] bdata = new byte[128]; + ((StreamMessage) message).readBytes(bdata); + String body = new String(bdata); + System.out.println("Received StreamMessage: "+body); + } + else if (message instanceof BytesMessage) + { + byte[] bdata = new byte[128]; + ((BytesMessage) message).readBytes(bdata); + String body = new String(bdata); + System.out.println("Received BytesMessage: "+body); + } + else if (message instanceof AdtMessage) + { + Cars car = (Cars) ((AdtMessage) message).getAdtPayload(); + System.out.print("Received AdtMessage for Cars: "); + System.out.print(car.getCarno()+", "); + System.out.print(car.getMake()+", "); + System.out.print(car.getColor()+", "); + System.out.println(car.getPrice()); + } + else + { + System.out.println("Unknown Message Type Received!"); + } + } + session.commit(); + } + receiver.close(); + } + +/** + * Creates and returns ANYDATA queue called jmsuser.jmsanydata10 + */ + public static javax.jms.Queue setup(QueueSession session) + throws javax.jms.JMSException, oracle.AQ.AQException + { + oracle.AQ.AQQueueTableProperty qtprop = null; + oracle.AQ.AQQueueTable qtable = null; + oracle.jms.AQjmsDestinationProperty dprop = null; + javax.jms.Queue queue = null; + + // + // drop queue table if it already exists + // + try + { + qtable = + ((AQjmsSession)session).getQueueTable("jmsuser", "jmsqtable_any"); + if (qtable != null) + qtable.drop(true); + } + catch (Exception e){} + + // + // create ANYDATA queue table + // + qtprop = new AQQueueTableProperty ("SYS.ANYDATA"); + qtprop.setMultiConsumer(false); + qtprop.setCompatible("9.2.0.0.0"); + qtable = ((AQjmsSession)session).createQueueTable("jmsuser", + "jmsqtable_any", qtprop); + + // + // create JMS Queue for ANYDATA queue table + // + dprop = new AQjmsDestinationProperty(); + queue = ((AQjmsSession)session).createQueue (qtable, "jmsanydata10", dprop); + System.out.println("Created queue jmsanydata10"); + + // + // enable the ANYDATA JMS Queue for JMS Messaging + // + try + { + java.sql.CallableStatement stmt; + java.sql.Connection conn = ((AQjmsSession)session).getDBConnection(); + String sqlCall = + "{call dbms_aqadm.enable_jms_types('jmsuser.jmsqtable_any')}"; + stmt = conn.prepareCall(sqlCall); + stmt.execute(); + System.out.println("Queue is JMS enabled"); + } + catch (java.sql.SQLException s) + { + s.printStackTrace(); + } + + // + // Start the queue + // + ((AQjmsDestination)queue).start(session, true, true); + + return queue; + } + +/** + * drops queue table "jmsuser.jmsqtable_any" + */ + private static void cleanup(QueueSession session) + { + // + // drop queue table used for test + // + try + { + oracle.AQ.AQQueueTable qtable = + ((AQjmsSession)session).getQueueTable("jmsuser", "jmsqtable_any"); + if (qtable != null) + qtable.drop(true); + } + catch (Exception e) + { + System.out.println("Error dropping jmsanydata10"); + e.printStackTrace(); + } + System.out.println("Queue jmsanydata10 dropped successfully"); + } +} + diff --git a/aqjmsdmo.sql b/aqjmsdmo.sql new file mode 100644 index 0000000..bbd892c --- /dev/null +++ b/aqjmsdmo.sql @@ -0,0 +1,61 @@ +Rem +Rem $Header: aqjmsdmo.sql 05-jun-2007.15:02:55 aatam Exp $ +Rem +Rem aqjmsdmo.sql +Rem +Rem Copyright (c) 2000, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqjmsdmo.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem aatam 06/05/07 - password need to be consistent +Rem rbhyrava 11/16/04 - user creation +Rem rbhyrava 07/10/00 - AQ JMS demo -setup +Rem rbhyrava 07/10/00 - Created +Rem +REM ===================================================== +REM SETUP for AQ JMS Demos:create user and payload types +REM ===================================================== +SET echo on; +CONNECT system/manager; +DROP USER jmsuser CASCADE ; +CREATE USER jmsuser IDENTIFIED BY JMSUSER; +GRANT CONNECT, RESOURCE, AQ_ADMINISTRATOR_ROLE TO jmsuser; + +CONNECT jmsuser/JMSUSER; + +CREATE TYPE message AS OBJECT ( + id NUMBER, + city VARCHAR2(30), + priority NUMBER +); +/ + +CREATE OR REPLACE TYPE cars AS OBJECT ( + carno NUMBER, + make VARCHAR2(20) , + year NUMBER, + price NUMBER(10,2) , + color VARCHAR2(10) +); +/ +CREATE OR REPLACE TYPE emp AS OBJECT ( + id NUMBER , + name VARCHAR2(20), + carown cars, + rank NUMBER, + zip VARCHAR2(5) +); +/ +EXIT; + +REM ============================================== +REM SETUP complete +REM ============================================== diff --git a/aqjmsdrp.sql b/aqjmsdrp.sql new file mode 100644 index 0000000..e373e2c --- /dev/null +++ b/aqjmsdrp.sql @@ -0,0 +1,22 @@ +Rem +Rem $Header: template.sql 06-feb-96.13:23:14 kosinski Exp $ +Rem +Rem aqjmsdrp.sql +Rem +Rem Copyright (c) Oracle Corporation 2000. All Rights Reserved. +Rem +Rem NAME +Rem aqjmsdrp.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 07/10/00 - Created +Rem +CONNECT system/manager; +DROP USER jmsuser cascade ; +EXIT; diff --git a/aqjmskprb01.java b/aqjmskprb01.java new file mode 100644 index 0000000..205a3c0 --- /dev/null +++ b/aqjmskprb01.java @@ -0,0 +1,173 @@ +/* $Header: aqjmskprb01.java 11-jul-2005.13:27:45 jleinawe Exp $ */ + +/* Copyright (c) 2002, 2005, Oracle. All rights reserved. */ + +/* + DESCRIPTION + AQ/OJMS KPRB driver demo + + PRIVATE CLASSES + + + NOTES + see below + + MODIFIED (MM/DD/YY) + jleinawe 07/11/05 - + rbhyrava 10/07/02 - import oracle.jdbc.* + jleinawe 09/04/02 - jleinawe_new_aq_demos + jleinawe 08/30/02 - Creation + */ + +/** + * @version $Header: aqjmskprb01.java 11-jul-2005.13:27:45 jleinawe Exp $ + * @author jleinawe + * @since release specific (what release of product did this appear in) + */ + +/**** + * This is a sample java file which uses Oracle JMS - Java Message service + * API. This file helps demonstrate how to send and receive a message + * from within an Oracle Database. + * + * This demo runs within the database and does the following + * - gets the database connection + * - creates a QueueReceiver + * - creates a QueueSender + * - sends and receives a text message + * + * Compilation + * =========== + * 1) The client machine should have JDK 1.1.x or JDK 1.2 or higher installed. + * 2) The following jar/zip files should be in the CLASSPATH + * For JDK1.2 or higher + * classes12.zip + * aqapi.jar + * jmscommon.jar + * nls_charset12.zip + * + * For JDK1.1.x + * classes111.zip + * aqapi11.jar + * jmscommon.jar + * nls_charset11.zip + * + * 3) Compile by executing "javac aqjmskprb01.java" + * + * This demo cannot be executed standalone. For execution, see the + * instructions for the kprb driver demo in the aqjmsREADME.txt file. + * + */ + +import oracle.jms.*; +import oracle.jdbc.*; +import javax.jms.*; +import java.sql.*; + +public class aqjmskprb01 +{ + + public static void main(String[] args) + throws Exception + { + runTest(args[0]); + } + + // send and receive one message + public static void runTest(String msgBody) + { + OracleDriver ora_drv = null; + java.sql.Connection db_conn = null; + + + QueueConnection s_conn = null; + QueueSession s_session = null; + QueueSender sender = null; + javax.jms.Queue s_queue = null; + TextMessage s_msg = null; + + QueueConnection r_conn = null; + QueueSession r_session = null; + QueueReceiver receiver = null; + javax.jms.Queue r_queue = null; + TextMessage r_msg = null; + + try + { + // + // get database connection + // + ora_drv = new OracleDriver(); + db_conn = ora_drv.defaultConnection(); + + // + // setup receiver + // + r_conn = AQjmsQueueConnectionFactory.createQueueConnection(db_conn); + r_conn.start(); + r_session = r_conn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + r_queue = ((AQjmsSession) r_session).getQueue("jmsuser1", "queue1"); + receiver = r_session.createReceiver(r_queue); + System.out.println("receiver created"); + + // + // setup sender + // + s_conn = AQjmsQueueConnectionFactory.createQueueConnection(db_conn); + s_conn.start(); + s_session = s_conn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + s_queue = ((AQjmsSession) s_session).getQueue("jmsuser1", "queue1"); + sender = r_session.createSender(s_queue); + System.out.println("sender created"); + + // + // create message + // + s_msg = s_session.createTextMessage(msgBody); + System.out.println("message created"); + + // + // send message + // + sender.send(s_msg); + s_session.commit(); + System.out.println("message sent"); + + // + // receive message + // + r_msg = (TextMessage) receiver.receive(); + r_session.commit(); + System.out.println("message received"); + + // + // output message text + // + String body = r_msg.getText(); + System.out.println("message was '"+body+"'"); + + // + // cleanup + // + s_session.close(); + s_conn.close(); + r_session.close(); + r_conn.close(); + } + catch (java.sql.SQLException sql_ex) + { + System.out.println("Exception-2: " + sql_ex); + sql_ex.printStackTrace(); + } + catch (JMSException aq_ex) + { + System.out.println("Exception-2: " + aq_ex); + aq_ex.printStackTrace(); + + if(aq_ex.getLinkedException() != null) + { + aq_ex.getLinkedException().printStackTrace(); + } + } + } +} diff --git a/aqjmskprb01a.sql b/aqjmskprb01a.sql new file mode 100644 index 0000000..f41cf43 --- /dev/null +++ b/aqjmskprb01a.sql @@ -0,0 +1,53 @@ +Rem +Rem $Header: aqjmskprb01a.sql 05-jun-2007.15:02:52 aatam Exp $ +Rem +Rem aqjmskprb01a.sql +Rem +Rem Copyright (c) 2002, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqjmskprb01a.sql +Rem +Rem DESCRIPTION +Rem creates user and queue for AQ/OJMS kprb driver demo +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem aatam 06/05/07 - password need to be consistent +Rem jleinawe 09/04/02 - jleinawe_new_aq_demos +Rem jleinawe 08/30/02 - Created +Rem + +SET ECHO ON +CONNECT system/manager +SET SERVEROUTPUT on + +-- +-- create the user "jmsuser1" +-- +CREATE USER jmsuser1 IDENTIFIED BY JMSUSER1; + +GRANT CONNECT, RESOURCE, AQ_ADMINISTRATOR_ROLE, AQ_USER_ROLE TO jmsuser1; +GRANT EXECUTE ON DBMS_AQADM TO jmsuser1; +GRANT EXECUTE ON DBMS_AQ TO jmsuser1; + +execute dbms_java.grant_permission('JMSUSER1', 'java.net.SocketPermission', 'localhost:1024-', 'accept, listen, resolve'); + +execute dbms_java.grant_permission( 'JMSUSER1', 'SYS:java.lang.RuntimePermission', ' getClassLoader', '' ) + +execute dbms_java.grant_permission( 'JMSUSER1', 'SYS:java.lang.RuntimePermission' , 'setContextClassLoader', '' ) + +CONNECT jmsuser1/JMSUSER1; + +-- +-- create and start the JMS Queue "queue1" +-- +execute dbms_aqadm.create_queue_table(queue_table => 'queue1', queue_payload_type => 'SYS.AQ$_JMS_TEXT_MESSAGE', comment => 'a test queue', multiple_consumers => false, compatible => '8.1.0'); + +execute dbms_aqadm.create_queue( queue_name => 'queue1', queue_table => 'queue1' ); + +execute dbms_aqadm.start_queue(queue_name => 'queue1'); + +quit; diff --git a/aqjmskprb01b.sql b/aqjmskprb01b.sql new file mode 100644 index 0000000..2332d2f --- /dev/null +++ b/aqjmskprb01b.sql @@ -0,0 +1,43 @@ +Rem +Rem $Header: aqjmskprb01b.sql 05-jun-2007.15:02:53 aatam Exp $ +Rem +Rem aqjmskprb01b.sql +Rem +Rem Copyright (c) 2002, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqjmskprb01b.sql - +Rem +Rem DESCRIPTION +Rem defines java stored procedure for AQ/OJMS kprb driver demo +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem aatam 06/05/07 - password need to be consistent +Rem jleinawe 09/04/02 - jleinawe_new_aq_demos +Rem jleinawe 08/30/02 - Created +Rem + +set echo on +set serveroutput on +connect jmsuser1/JMSUSER1 + +-- +-- define the kprb driver demos in the database +-- + +create or replace package jmsdemo authid current_user as + procedure start_me(t1 VARCHAR2); +end jmsdemo; +/ +create or replace package body jmsdemo as + procedure start_me(t1 VARCHAR2) is language java + name 'aqjmskprb01.main (java.lang.String[])'; +end jmsdemo; +/ +show errors + + +quit; diff --git a/aqjmskprb01c.sql b/aqjmskprb01c.sql new file mode 100644 index 0000000..2c4be87 --- /dev/null +++ b/aqjmskprb01c.sql @@ -0,0 +1,37 @@ +Rem +Rem $Header: aqjmskprb01c.sql 05-jun-2007.15:02:53 aatam Exp $ +Rem +Rem aqjmskprb01c.sql +Rem +Rem Copyright (c) 2002, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqjmskprb01c.sql - +Rem +Rem DESCRIPTION +Rem Calls java stored procedure for AQ/OJMS kprb driver demo +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem aatam 06/05/07 - password need to be consistent +Rem jleinawe 09/04/02 - jleinawe_new_aq_demos +Rem jleinawe 08/30/02 - Created +Rem + +set echo on +connect jmsuser1/JMSUSER1 + +-- +-- run the kprb driver demo +-- +set serveroutput on + +call dbms_java.set_output(30000); + +call jmsdemo.start_me('hello'); +call jmsdemo.start_me('hello again'); + +quit; + diff --git a/aqjmskprb01d.sql b/aqjmskprb01d.sql new file mode 100644 index 0000000..cecd1f8 --- /dev/null +++ b/aqjmskprb01d.sql @@ -0,0 +1,34 @@ +Rem +Rem $Header: aqjmskprb01d.sql 05-jun-2007.15:02:54 aatam Exp $ +Rem +Rem aqjmskprb01d.sql +Rem +Rem Copyright (c) 2002, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqjmskprb01d.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem aatam 06/05/07 - password need to be consistent +Rem jleinawe 09/04/02 - jleinawe_new_aq_demos +Rem jleinawe 08/30/02 - Created +Rem + + +connect jmsuser1/JMSUSER1; + +execute dbms_aqadm.drop_Queue_table(queue_table => 'queue1', force => true); + +drop package jmsdemo; + +connect system/manager; +drop user jmsuser1 cascade; + +quit; + diff --git a/aqorademo01.java b/aqorademo01.java new file mode 100644 index 0000000..83a9b1d --- /dev/null +++ b/aqorademo01.java @@ -0,0 +1,306 @@ +/* $Header: aqorademo01.java 12-aug-2003.12:51:11 rbhyrava Exp $ */ + +/* Copyright (c) 2000, 2003, Oracle Corporation. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 08/12/03 - stop/drop queue/queuetables + rbhyrava 10/07/02 - import oracle.jdbc.* + rbhyrava 03/20/00 - use driver arg + rbhyrava 03/16/00 - AQ API demos + rbhyrava 03/15/00 - AQ API demo - Enqueue,Dequeue RAW Message + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqorademo01.java 12-aug-2003.12:51:11 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ +/*** + * This is a sample java file which uses Oracle AQ API to enqueue and + * dequeue RAW messages + + * -- Create a Queue + * -- Enqueue RAW Message + * Dequeue RAW message + * + * The following instructions describe how to compile and execute + * this sample on the client machine. + * + * System requirements: + * ==================== + * 1) Oracle 8.1.6 database or higher + * 2) The client machine should have JDK 1.1.x or JDK1.2 or higher installed + * 3) The following jar/zip files should be in the CLASSPATH on the client + * machine. + * For JDK1.2.x + * classes12.zip + * aqapi.jar + * For JDK1.1.x + * classes111.zip + * aqapi11.jar + * Set up CLASSPATH, PATH, LD_LIBRARY_PATH based on JDK version and platform. + * Compilation and Running: + * ======================== + * 4) If you already have the jars in step 3) in classpath + * javac aqorademo01.java + * + * 5) java aqorademo01 + * Example usage: + * java aqorademo01 orcl82 dlsun666 1521 thin + * + * Thin driver is used in the demo. Modify the connect string to use oci8 + * jdbc driver + ***/ + +/* Set up main class from which we will call subsequent examples and handle + exceptions: */ +import java.sql.*; +import oracle.AQ.*; + +public class aqorademo01 +{ + public static void main(String args[]) + { + AQSession aq_sess = null; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + aq_sess = createSession(args); + /* now Enqueue and Dequeue Messages */ + createQTable(aq_sess) ; + enqRawMsg(aq_sess); + deqRawMsg(aq_sess); + dropQTable(aq_sess); + System.out.println("End of Demo") ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + +/* Create an Java AQ Session for the 'aqjava' user as shown in the + AQDriverManager section above: */ + + public static AQSession createSession(String args[]) throws Exception + { + Connection db_conn; + AQSession aq_sess = null; + + try + { + Class.forName("oracle.jdbc.OracleDriver"); + + String drv,url; + drv=args[3]; + + if ( drv.toLowerCase().compareTo("thin") == 0) + url="jdbc:oracle:"+args[3]+":@"+args[1]+":"+args[2]+":"+args[0]; + else { + url= new String ("jdbc:oracle:oci8:"); + url= url.concat("@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)" + + "(PORT=" + args[2] + + ")(HOST=" + args[1] + "))(CONNECT_DATA=(SID=" + + args[0] + ")))"); + + } + //"jdbc:oracle:thin:@host:port:sid" + System.out.println("Connect String is :"+url) ; + + db_conn = DriverManager.getConnection(url, "aqjava", "aqjava"); + + System.out.println("JDBC Connection opened "); + db_conn.setAutoCommit(false); + + /* Load the Oracle8i AQ driver: */ + Class.forName("oracle.AQ.AQOracleDriver"); + + /* Create an AQ Session: */ + aq_sess = AQDriverManager.createAQSession(db_conn); + System.out.println("Successfully created AQSession "); + } + catch (Exception ex) + { + System.out.println("Exception: " + ex); + throw ex; + } + return aq_sess; + } + + + public static void createQTable(AQSession aq_sess) throws Exception + { + AQQueueTableProperty qtable_prop; + AQQueueProperty queue_prop; + AQQueueTable q_table; + AQQueue queue; + + try { + /* Create a AQQueueTableProperty object (payload type - RAW): */ + qtable_prop = new AQQueueTableProperty("RAW"); + + /* Drop the queue if already exists */ + try { + q_table = aq_sess.getQueueTable ("aqjava", "aq_table4" ); + q_table.drop(true); + } catch (Exception e) {} ; + + /* Create a queue table called aq_table4 in aqjava schema: */ + q_table=aq_sess.createQueueTable ("aqjava", "aq_table4", qtable_prop); + System.out.println("Successfully created aq_table4 in aqjava schema"); + + /* Create a new AQQueueProperty object */ + queue_prop = new AQQueueProperty(); + + /* Create a queue called aq_queue4 in aq_table4: */ + queue = aq_sess.createQueue (q_table, "aq_queue4", queue_prop); + System.out.println("Successfully created aq_queue4 in aq_table4"); + + /* Enable enqueue/dequeue on this queue: */ + queue.start(); + System.out.println("Successful start queue"); + } catch (Exception e) { + System.out.println("Error in createQTable:"+ e); + throw e; + } + } + + + + public static void enqRawMsg(AQSession aq_sess) throws Exception + { + AQQueueTable q_table; + AQQueue queue; + AQMessage message; + AQRawPayload raw_payload; + AQEnqueueOption enq_option; + String test_data = "new message"; + byte[] b_array; + Connection db_conn; + + try { + db_conn = ((AQOracleSession)aq_sess).getDBConnection(); + + /* Get a handle to queue table - aq_table4 in aqjava schema: */ + q_table = aq_sess.getQueueTable ("aqjava", "aq_table4"); + System.out.println("Successful getQueueTable"); + + /* Get a handle to a queue - aq_queue4 in aquser schema: */ + queue = aq_sess.getQueue ("aqjava", "aq_queue4"); + System.out.println("Successful getQueue"); + + /* Create a message to contain raw payload: */ + message = queue.createMessage(); + + /* Get handle to the AQRawPayload object and populate it with raw data: */ + b_array = test_data.getBytes(); + + raw_payload = message.getRawPayload(); + + raw_payload.setStream(b_array, b_array.length); + + /* Create a AQEnqueueOption object with default options: */ + enq_option = new AQEnqueueOption(); + /* Enqueue the message: */ + queue.enqueue(enq_option, message); + + db_conn.commit(); + } catch (Exception e) { + System.out.println("Exception during Enqueue: " + e) ; + throw e; + } + } + + + + public static void deqRawMsg(AQSession aq_sess) throws Exception + { + AQQueueTable q_table; + AQQueue queue; + AQMessage message; + AQRawPayload raw_payload; + AQEnqueueOption enq_option; + String test_data = "new message"; + AQDequeueOption deq_option; + byte[] b_array; + Connection db_conn; + try { + db_conn = ((AQOracleSession)aq_sess).getDBConnection(); + + /* Get a handle to queue table - aq_table4 in aqjava schema: */ + q_table = aq_sess.getQueueTable ("aqjava", "aq_table4"); + System.out.println("Successful getQueueTable"); + + /* Get a handle to a queue - aq_queue4 in aquser schema: */ + queue = aq_sess.getQueue ("aqjava", "aq_queue4"); + System.out.println("Successful getQueue"); + + /* Create a message to contain raw payload: */ + message = queue.createMessage(); + + /* Get handle to the AQRawPayload object and populate it with raw data: */ + b_array = test_data.getBytes(); + + raw_payload = message.getRawPayload(); + + raw_payload.setStream(b_array, b_array.length); + + /* Create a AQEnqueueOption object with default options: */ + enq_option = new AQEnqueueOption(); + + /* Enqueue the message: */ + queue.enqueue(enq_option, message); + System.out.println("Successful enqueue"); + + db_conn.commit(); + + /* Create a AQDequeueOption object with default options: */ + deq_option = new AQDequeueOption(); + + /* Dequeue a message: */ + message = queue.dequeue(deq_option); + System.out.println("Successful dequeue"); + + /* Retrieve raw data from the message: */ + raw_payload = message.getRawPayload(); + + b_array = raw_payload.getBytes(); + + db_conn.commit(); + } catch (Exception e) { + System.out.println("Exception during Dequeue: " + e) ; + throw e; + } + } + public static void dropQTable(AQSession aq_sess) throws Exception + { + AQQueueTable q_table; + AQQueue queue ; + try { + q_table = aq_sess.getQueueTable ("aqjava", "aq_table4" ); + queue = aq_sess.getQueue("aqjava", "aq_queue4"); + queue.stop(true, true, true) ; + q_table.dropQueue("aq_queue4"); + q_table.drop(true); + } catch (Exception e) { + System.out.println("Error in dropQTable:"+ e); + } ; + + System.out.println("Successfully dropped aq_table4 in aqjava schema"); + } +} diff --git a/aqorademo02.java b/aqorademo02.java new file mode 100644 index 0000000..b5a0380 --- /dev/null +++ b/aqorademo02.java @@ -0,0 +1,260 @@ +/* $Header: aqorademo02.java 12-aug-2003.12:51:12 rbhyrava Exp $ */ + +/* Copyright (c) 2000, 2003, Oracle Corporation. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 08/12/03 - stop/drop queue/queuetables + rbhyrava 10/07/02 - import oracle.jdbc.* + rbhyrava 03/01/02 - use ORAData + rbhyrava 03/20/00 - oci driver + rbhyrava 03/16/00 - AQ API demos + rbhyrava 03/15/00 - AQ API demo - Object Type, Dequeue on Payload conten + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqorademo02.java 12-aug-2003.12:51:12 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/*** + * This is a sample java file which uses Oracle AQ API to enqueue and + * dequeue Object Type Payload messages + + * -- Create a Queue + * -- Enqueue Object Payload message + * Dequeue Object Payload Message + * + * ORAData interface is used for Object types. Jpub generated classes + * are used and provided for reference. + * + * The following instructions describe how to compile and execute + * this sample on the client machine. + * + * System requirements: + * ==================== + * 1) Oracle 8.1.6 database or higher + * 2) The client machine should have JDK 1.1.x or JDK1.2 or higher installed + * 3) The following jar/zip files should be in the CLASSPATH on the client + * machine. + * For JDK1.2.x + * classes12.zip + * aqapi.jar + * For JDK1.1.x + * classes111.zip + * aqapi11.jar + * Set up CLASSPATH, PATH, LD_LIBRARY_PATH based on JDK version and platform. + * Compilation and Running: + * ======================== + * 4) If you already have the jars in step 3) in classpath + * javac aqorademo02.java ADDRESS.java PERSON.java + * + * 5) java aqorademo02 + * Example usage: + * java aqorademo02 orcl82 dlsun666 1521 thin + * + * Thin driver is used in the demo. Modify the connect string to use oci8 + * jdbc driver + * + ***/ + +/* Set up main class from which we will call subsequent examples and handle + exceptions: */ +import java.sql.*; +import oracle.AQ.*; + +public class aqorademo02 +{ + public static void main(String args[]) + { + AQSession aq_sess = null; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + aq_sess = createSession(args); + /* now Enqueue and Dequeue Messages */ + createQTable(aq_sess) ; + AQObjectPayloadTest(aq_sess) ; + dropQTable(aq_sess) ; + System.out.println("End of Demo") ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + +/* Create an Java AQ Session for the 'aqjava' user as shown in the + AQDriverManager section above: */ + + public static AQSession createSession(String args[]) throws Exception + { + Connection db_conn; + AQSession aq_sess = null; + + try + { + Class.forName("oracle.jdbc.OracleDriver"); + String url, drv; + + drv=args[3]; + + if ( drv.toLowerCase().compareTo("thin") == 0) + url="jdbc:oracle:"+args[3]+":@"+args[1]+":"+args[2]+":"+args[0]; + else { + url= new String ("jdbc:oracle:oci8:"); + url= url.concat("@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)" + + "(PORT=" + args[2] + + ")(HOST=" + args[1] + "))(CONNECT_DATA=(SID=" + + args[0] + ")))"); + + } + //"jdbc:oracle:thin:@host:port:sid" + System.out.println("Connect String is :"+url) ; + + db_conn = DriverManager.getConnection(url, "aqjava", "aqjava"); + + System.out.println("JDBC Connection opened "); + db_conn.setAutoCommit(false); + + /* Load the Oracle8i AQ driver: */ + Class.forName("oracle.AQ.AQOracleDriver"); + + /* Create an AQ Session: */ + aq_sess = AQDriverManager.createAQSession(db_conn); + System.out.println("Successfully created AQSession "); + } + catch (Exception ex) + { + System.out.println("Exception: " + ex); + throw ex; + } + return aq_sess; + } + + + public static void createQTable(AQSession aq_sess) throws Exception + { + AQQueueTableProperty qtable_prop; + AQQueueProperty queue_prop; + AQQueueTable q_table; + AQQueue queue; + + try { + /* Create a AQQueueTableProperty object (payload type ): */ + qtable_prop = new AQQueueTableProperty("PERSON"); + + /* Drop the queue if already exists */ + try { + q_table = aq_sess.getQueueTable ("aqjava", "aq_table2" ); + q_table.drop(true); + } catch (Exception e) {} ; + + /* Create a queue table called aq_table2 in aqjava schema: */ + q_table = aq_sess.createQueueTable ("aqjava","aq_table2", qtable_prop); + System.out.println("Successfully created aq_table2 in aqjava schema"); + + /* Create a new AQQueueProperty object */ + queue_prop = new AQQueueProperty(); + + /* Create a queue called test_queue2 */ + queue = aq_sess.createQueue (q_table, "test_queue2", queue_prop); + System.out.println("Successfully created test_queue2 in aq_table2"); + + /* Enable enqueue/dequeue on this queue: */ + queue.start(); + System.out.println("Successful start queue"); + } catch (Exception e) { + System.out.println("Error in createQTable:"+ e); + throw e; + } + } + + public static void AQObjectPayloadTest(AQSession aq_sess) + throws AQException, SQLException, ClassNotFoundException + { + Connection db_conn = null; + AQQueue queue = null; + AQMessage message = null; + AQObjectPayload payload = null; + AQEnqueueOption eq_option = null; + AQDequeueOption dq_option = null; + PERSON pers = null; + PERSON pers2= null; + ADDRESS addr = null; + + db_conn = ((AQOracleSession)aq_sess).getDBConnection(); + + queue = aq_sess.getQueue("aqjava", "test_queue2"); + + /* Enqueue a message in test_queue2 */ + message = queue.createMessage(); + + pers = new PERSON(); + pers.setName("John"); + addr = new ADDRESS(); + addr.setStreet("500 Easy Street"); + addr.setCity("San Francisco"); + pers.setHome(addr); + + payload = message.getObjectPayload(); + payload.setPayloadData(pers); + eq_option = new AQEnqueueOption(); + + /* Enqueue a message into test_queue2 */ + queue.enqueue(eq_option, message); + + db_conn.commit(); + + /* Dequeue a message from test_queue2 */ + dq_option = new AQDequeueOption(); + message = ((AQOracleQueue)queue).dequeue(dq_option, PERSON.getORADataFactory()); + + payload = message.getObjectPayload(); + pers2 = (PERSON) payload.getPayloadData(); + + System.out.println("Object data retrieved: [PERSON]"); + System.out.println("Name: " + pers2.getName()); + System.out.println("Address "); + System.out.println("Street: " + pers2.getHome().getStreet()); + System.out.println("City: " + pers2.getHome().getCity()); + + db_conn.commit(); + } + + public static void dropQTable(AQSession aq_sess) throws Exception + { + AQQueueTable q_table; + AQQueue queue; + + try { + q_table = aq_sess.getQueueTable ("aqjava", "aq_table2" ); + queue = aq_sess.getQueue("aqjava", "test_queue2"); + queue.stop(true, true, true) ; + q_table.dropQueue("test_queue2"); + q_table.drop(true); + } catch (Exception e) { + System.out.println("Error in dropQTable:"+ e); + } ; + + System.out.println("Successfully dropped aq_table2 in aqjava schema"); + } + +} + + diff --git a/aqoradmo.sql b/aqoradmo.sql new file mode 100644 index 0000000..e4049e5 --- /dev/null +++ b/aqoradmo.sql @@ -0,0 +1,48 @@ +Rem +Rem $Header: aqoradmo.sql 16-nov-2004.15:56:51 rbhyrava Exp $ +Rem +Rem aqoradmo.sql +Rem +Rem Copyright (c) 2000, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqoradmo.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/16/04 - user creation +Rem rbhyrava 07/10/00 - AQ API demo - setup +Rem rbhyrava 07/10/00 - Created +Rem + +REM =========================================================== +REM SETUP for AQ Java API demos:create user and payload types +REM =========================================================== +SET echo on; +CONNECT system/manager; +DROP USER aqjava CASCADE; +CREATE USER aqjava IDENTIFIED BY aqjava; +GRANT CONNECT, RESOURCE, AQ_ADMINISTRATOR_ROLE TO aqjava; +GRANT EXECUTE ON DBMS_AQADM TO aqjava; +GRANT EXECUTE ON DBMS_AQ TO aqjava; +CONNECT aqjava/aqjava; + +CREATE TYPE address AS OBJECT ( + street VARCHAR (30), + city VARCHAR(30) +); +/ +CREATE TYPE person AS OBJECT ( + name VARCHAR (30), + home ADDRESS +); +/ +EXIT; +REM ============================================== +REM SETUP complete +REM ============================================== diff --git a/aqoradrp.sql b/aqoradrp.sql new file mode 100644 index 0000000..267f6ba --- /dev/null +++ b/aqoradrp.sql @@ -0,0 +1,28 @@ +Rem +Rem $Header: aqoradrp.sql 15-nov-2000.10:01:53 ociqa Exp $ +Rem +Rem aqoradrp.sql +Rem +Rem Copyright (c) Oracle Corporation 2000. All Rights Reserved. +Rem +Rem NAME +Rem aqoradrp.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ociqa 11/15/00 - +Rem rbhyrava 07/10/00 - demodrop script +Rem rbhyrava 07/10/00 - Created +Rem +REM -------------------- +REM Drop the user +REM -------------------- + +CONNECT system/manager ; +DROP USER aqjava CASCADE ; +EXIT; diff --git a/aqxml01.xml b/aqxml01.xml new file mode 100644 index 0000000..b6e24b1 --- /dev/null +++ b/aqxml01.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + aqxmladmn.book_q1 + + + + 3 + + + 1 + + + PROGRAMMING + 0 + + AGENT01 + 0 + + + + + + XML Unleashed + Mike Johnson + ISBN0101 + 25 + + + + + + 2 + + + CLASSICS + 0 + + AGENT02 + 0 + + + + + + GREAT ADVENTURES + Charles Dikens + ISBN0202 + 8 + + + + + 3 + + + CHILDREN + 0 + + AGENT01 + 0 + + + + + + MARY HAD A LITTLE LAMB + Tommy Close + ISBN0303 + 5 + + + + + + + + + diff --git a/aqxml02.xml b/aqxml02.xml new file mode 100644 index 0000000..b7c71e9 --- /dev/null +++ b/aqxml02.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + aqxmladmn.BOOK_Q1 + 0 + 10 + + + + + + diff --git a/aqxml03.xml b/aqxml03.xml new file mode 100644 index 0000000..7da5a1a --- /dev/null +++ b/aqxml03.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + aqxmladmn.cars_q1 + + + + 2 + + + 1 + + + CARS + 0 + + AGENT01 + 0 + + + + + + 4MEG123 + 2001 + BMW + RED + Red on Sale -20 + 35000 + + + + + + 2 + + + CARS + 0 + + AGENT02 + 0 + + + + + + 4PCE123 + 2000 + LEXUS + BLUE + In Stock -50 + 55000 + + + + + + + diff --git a/aqxml04.xml b/aqxml04.xml new file mode 100644 index 0000000..2d8e81c --- /dev/null +++ b/aqxml04.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + aqxmladmn.cars_q1 + DEALS_CARS_Q1 + 8 + + + + diff --git a/aqxml05.xml b/aqxml05.xml new file mode 100644 index 0000000..b78b328 --- /dev/null +++ b/aqxml05.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/aqxml06.xml b/aqxml06.xml new file mode 100644 index 0000000..e03ef4a --- /dev/null +++ b/aqxml06.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + aqxmladmn.jms_text_q1 + + + + 1 + + + 1 + + + JMSTEXT + 1 + + scott +
home
+ 0 +
+
+ + + + + + + oracle + + jmsuser + AQProduct + AQ + + + + + Country + USA + + + State + california + + + Zip + 94065 + + + + + All things bright and beautiful + All creatures great and small + All Things wise and Wonderful + The Great Lord made them all. + + + + +
+
+ + + +
+ +
+ diff --git a/aqxml07.xml b/aqxml07.xml new file mode 100644 index 0000000..f884538 --- /dev/null +++ b/aqxml07.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + aqxmladmn.JMS_TEXT_Q1 + 2 + 10 + + + + + + diff --git a/aqxml08.xml b/aqxml08.xml new file mode 100644 index 0000000..2681103 --- /dev/null +++ b/aqxml08.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + aqxmladmn.jms_map_q1 + + + + 1 + + + 1 + + + CARS + 0 + + scott +
home
+ 0 +
+ + + RECP1 + 0 + + +
+ + + + + + + oracle +
redwoodshores
+ 100 +
+ scott + AQProduct + AQ +
+ + + + country + USA + + + State + california + + + + + + make + Toyota + + + Color + Blue + + + Price + 20000 + + + +
+
+
+
+
+ +
diff --git a/aqxml09.xml b/aqxml09.xml new file mode 100644 index 0000000..f0f7227 --- /dev/null +++ b/aqxml09.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + aqxmladmn.jms_map_q1 + RECP1 + + + + diff --git a/aqxml10.xml b/aqxml10.xml new file mode 100644 index 0000000..cf3ba54 --- /dev/null +++ b/aqxml10.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/aqxmlREADME.txt b/aqxmlREADME.txt new file mode 100644 index 0000000..47079a6 --- /dev/null +++ b/aqxmlREADME.txt @@ -0,0 +1,266 @@ +/ +/ $Header: aqxmlREADME.txt 13-may-2008.13:16:32 rbhyrava Exp $ +/ +/ aqxmlREADME.txt +/ +/ Copyright (c) Oracle Corporation 2001. All Rights Reserved. +/ +/ NAME +/ aqxmlREADME.txt +/ +/ DESCRIPTION +/ This document contains list and description of aqxml demos +/ NOTES +/ +/ +/ MODIFIED (MM/DD/YY) +/ rbhyrava 05/13/08 - aqxmlctl args +/ rbhyrava 10/29/04 - OC4J support +/ rbhyrava 03/30/01 - Creation +/ + +The following files are required for running AQXML samples + + aqxmldmo.sql - Setup Users, Queue tables and Queues + aqxmldrp.sql - Drop/Cleanup AQ xml demo users/queue tables/queues + + aqxml01.xml AQXmlSend + Enqueue to ADT single consumer queue with piggyback commit + + aqxml02.xml AQXmlReceive + Dequeue from ADT Single consumer queue with piggyback commit + + aqxml03.xml AQXmlPublish + Enqueue to ADT (with LOB) multi consumer queue + + aqxml04.xml AQXmlReceive + Dequeue from ADT multi consumer queue + + aqxml05.xml AQXmlCommit + commit previous operation + + aqxml06.xml AQXmlSend + Enqueue to JMS Text single consumer queue with piggyback commit + + aqxml07.xml AQXmlReceive + Dequeue from JMS Text single consumer queue with piggyback commit + + aqxml08.xml AQXmlPublish + Enqueue JMS MAP message with recipient into multi consumer queue + + aqxml09.xml AQXmlReceive + Dequeue JMS MAP message from multi consumer queue + + aqxml10.xml AQXmlRollback + rollback previous operation + + aqxmlhtp.sql HTTP Propagation + + AQHttp.java , AQHttpRq.java - Helpers to Post XML Request using HTTPClient + + AQDemoServlet.java - Servlet to Post AQ XML files + AQPropServlet.java - Servlet for AQ HTTP Propagation + +For additional demos using E-business examples unzip +aqbzdemo.tar (aqbzdemo.zip for Windows). + +Steps to run demos using oc4j: +=============================== + +(1) Make sure classpath include the following: + + For JDK1.2.x or JDK1.3.x: + $ORACLE_HOME/jdbc/lib/classes12.zip + $ORACLE_HOME/jdbc/lib/nls_charset12.zip + $ORACLE_HOME/rdbms/jlib/aqapi.jar + $ORACLE_HOME/rdbms/jlib/jmscommon.jar + $ORACLE_HOME/rdbms/jlib/aqxml.jar + $ORACLE_HOME/rdbms/jlib/xsu12.jar + $ORACLE_HOME/rdbms/jlib/xdb.jar + $ORACLE_HOME/jlib/jndi.jar + $ORACLE_HOME/jlib/jta.jar + $ORACLE_HOME/jlib/jssl-1_1.jar + $ORACLE_HOME/jlib/javax-ssl-1_1.jar + $ORACLE_HOME/lib/xmlparserv2.jar + $ORACLE_HOME/lib/xsu12.jar + $ORACLE_HOME/lib/xschema.jar + $ORACLE_HOME/lib/http_client.jar + $ORACLE_HOME/lib/servlet.jar + $ORACLE_HOME/lib/lclasses12.zip + + For JDK1.4.x + $ORACLE_HOME/jdbc/lib/ojdbc14.jar + $ORACLE_HOME/jdbc/lib/orai18n.zip + $ORACLE_HOME/rdbms/jlib/aqapi.jar + $ORACLE_HOME/rdbms/jlib/jmscommon.jar + $ORACLE_HOME/rdbms/jlib/aqxml.jar + $ORACLE_HOME/rdbms/jlib/xdb.jar + $ORACLE_HOME/jlib/jndi.jar + $ORACLE_HOME/jlib/jta.jar + $ORACLE_HOME/jlib/jssl-1_1.jar + $ORACLE_HOME/jlib/javax-ssl-1_1.jar + $ORACLE_HOME/lib/xmlparserv2.jar + $ORACLE_HOME/lib/xsu12.jar + $ORACLE_HOME/lib/xschema.jar + $ORACLE_HOME/lib/http_client.jar + $ORACLE_HOME/lib/servlet.jar + $ORACLE_HOME/lib/lclasses12.zip + + NOTE : + http_client.jar, jssl-1_1.jar, javax-ssl-1_1.jar + are required by HTTPClient used in AQHttp.java AQHttpRq.java. + +(2) Compile AQHttpRq.java: + + cd $ORACLE_HOME/rdbms/demo + javac AQHttpRq.java AQHttp.java + +(3) Database Setup: + + Make sure init.ora file contains: + job_queue_processes=2 + compatible=10.2.0 or above + restart database and listener. + +(4) Users Authentication setup for restricted access and queues: + cd $ORACLE_HOME/rdbms/demo + SQL> @aqxmldmo.sql + +(5) Configure AQDemoServlet: + (deploy,start may be already done at your installation during install, see + step (6)). Otherwise, + + cd $ORACLE_HOME/bin + follow the steps for deploy, start of the servlet + + To Deploy the servlet: sh aqxmlctl deploy welcome + To Start OC4J instance: sh aqxmlctl start welcome + To Stop OC4J instance: sh aqxmlctl stop welcome + +(6) Verify the setup: + + #############------------------------------############## + NOTE: The default deployment is done using https protocol. + #############------------------------------############## + + Refer to $ORACLE_HOME/rdbms/demo/aqxml.ini for status of servlet. + Refer to $ORACLE_HOME/oc4j/j2ee/OC4J_AQ/config/rmi.xml + Refer to $ORACLE_HOME/oc4j/j2ee/OC4J_AQ/config/http-web-site.xml + for information on protocol,port number used for deploying this servlet. + + From the browser try, + https://:/aqserv/servlet/AQDemoServlet + replace hostname, portnumber, protocol with webserver host/port,protocol +used. + Eg: https request + https://my-pc:5760:aqserv/servlet/AQDemoServlet + + Eg: http request + http://my-pc:5740:aqserv/servlet/AQDemoServlet + + This should display (after prompting for user/password- john/welcome) + Sample AQ Servlet + AQxmlServlet is working! + + Refer to OC4J documentation for https configuration using admin.jar. + + (a) Creating an SSL Certificate and generating keystore. + Refer to keytool documentation for maintaining or creating + your own keystore. + + $ORACLE_HOME/rdbms/demo/keystore, + $ORACLE_HOME/rdbms/demo/aqxmloc4j.cert is provided for demo purposes. + + (b) The following tags in + $ORACLE_HOME/oc4j/j2ee/OC4J_AQ/config/http-web-site.xml indicate + the website is secure and keystore is used for SSL authentication. + + Modify http-web-site.html for secure tag and adding ssl-config. + + .... + + + + To make the site to access only http requests, remove the secure="true" and + from the http-web-site.xml. + Re-start the OC4J instance. + + Note: + The above step can also be done using admin.jar provided by OC4J Standalone. + + +(7) Http(s) Access: POST a request: + + Usage: + java AQHttpRq webuser pswd xmlfile xmlfile .. + + Example: + + cd $ORACLE_HOME/rdbms/demo; + Replace 7777,http in the sample requests below with appropriate + values of host, port and protocol(http/https) used in Step (6). + + (a) Enqueue to ADT single consumer queue with piggyback commit: + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml01.xml + + (b) Dequeue from ADT Single consumer queue with piggyback commit: + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml02.xml + + (c) Enqueue to ADT (with LOB) multi consumer queue and Commit + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml03.xml aqxml05.xml + + (d) Dequeue from ADT multi consumer queue and Commit: + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml04.xml aqxml05.xml + + (e) Enqueue to JMS Text single consumer queue with piggyback commit: + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml06.xml + + (f) Dequeue from JMS Text single consumer queue with piggyback commit + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml07.xml + + (g) Enqueue JMS MAP message with recipient into multi consumer queue-Commit + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml08.xml aqxml05.xml + + (h) Dequeue JMS MAP message from multi consumer queue and Rollback + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml09.xml aqxml10.xml + + (i) Dequeue JMS MAP message from multi consumer queue and Commit + to commit dequeue call + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml09.xml aqxml05.xml + +(8) HTTP Propagation: + + (a) Make sure the AQPropServlet is working.See Step(6) + + (b) Run AQ http propagation demo. + Specify arguments protocol, hostname, portnumber for creating dblink. + + SQL>@aqxmlhtp http <7777> + +(9) HTTPS Propagation: + + (a) Make sure the AQPropServlet is working.See Step(6) + (b) Set up Wallet: + -create a new wallet using Oracle Wallet Manager + - Import trusted cerificate ($ORACLE_HOME/rdbms/demo/aqxmloc4j.cert) + - New trustpoint will be added + - select AutoLogin button under Wallet menu option + - Save the wallet to a directory location (eg: $ORACLE_HOME/rdbms/demo) + - Verify the two files created under the specified directory + cwallet.sso, ewallet.p12 + Exit Wallet Manager + + - add to network/admin/sqlnet.ora(replace $ORACLE_HOME) + eg: + oss.source.my_wallet= + (SOURCE=(METHOD=FILE)(METHOD_DATA= + (DIRECTORY=$ORACLE_HOME/rdbms/demo))) + + - from sqlplus + SQL>@aqxmlhtp https <443> + Specify arguments protocol, hostname, portnumber for creating dblink. + +(10) Cleanup: + (a) run aqxmldrp.sql to drop users/queues diff --git a/aqxmldemo.ear b/aqxmldemo.ear new file mode 100644 index 0000000000000000000000000000000000000000..b453219be404b3ba58979d9f09e75863fc3eee53 GIT binary patch literal 9190 zcmai)1#lcol7?k5Gh1LWGc#Gt%*@P;7Be$5Gg&+WOR|`mnVBU^I(ctnpZ9ItUUp1J zPfS&IP37O!8TF-{BnT)p&~H0{g6I0j#XnC_K%hXNGQogZ9Bd5S-Qt@J^gO#(^E6#zrGa zM!av{##Y^opvR3{-Kle3YY*8?T!G(DzV;$FAyIZ7`9Q9_+7`&Tv2@@|`SL{S1u^y3 z!{Yg@dSfBvN|I;oQh1?hQ8h52qd3CtBtj&@mk2$EF&&zwp=PS9B6@ZI7tV6krMQmRr`qDz;8`v^I}d1l9VB4y(5z4zh_HKXHJl3{%+x$3sxO6N)&478 zb2sB56xdu8LIii?$3t3-hC0Kv2r$Jjydl}d_HPll6vzBKGyX$J%nR{GqZ+g3Uq4Si zFX6eDwj9iuBezP`wJ`Zg)|sz~TN$q*jVy312J7?*AUp@d^O_}f&i5oNzMtrQ_JD)n zG5ZXG3z2Q9&-Rsy?MnYj``!rP7(!3L6Bv$tcPau_tzgK4Qnm)jI)k4zQ>x}@1Eq*d z$ta^8kmO{E9fZPLUrBT(rpV5kA5h^o+%3|#u`8o`HXT}*v?6H@wxWBQUUQcmTHpO1 zuO-x+;$^;-8K*^3yGq*u^NuWA`plo>$PB(OA;h9qvXqVA!_$)hY5}s0Gay$^7Kgso zT6&hRAm;Cqw|!X6hlNl+t!xHU#LHUv;>+s$p*jdi3r-(kF<>AdAE^JPLi9gXXzO5Z zYeVx-Efy(B+pf^V@+<%ZXSBBsth(vhDVmEzJ_)S|h2)EB?3;i+hZi=E0di)+gd8jM z_z|V9d3cBO*|oaV`m)JM&(_jwc13+!kAe|aRw`Zw+b#DEuOdvb!GgQbeZ1eFcEasH z*=e(@v_t860*t?-4d9s>Z3xn9=vTYY@u6+PnR<BW5o|^PNwP&EBe24 z)~9;SIQOMFxH8DoznKjgUo~qijbyuGw4(+JvLvKB5hrA@{)&)81~^N(k2!K9 zh7229xkZ7EGF50IrChq470Z8{B6@tjbFUXar&n=7;mFtVwudS0O(wEQwgRy4ghy+m@t&X8}?)|HK$o73rjQ zSA}BftveLFiVb3=WnkMRCpX1o=oZLt{;dHQNnAJ3ip>NHsMzX=hge_=^l)*)=b z>y86hc#0p@TvUEC{+#ci&U~}q$#$c)@v9m99y8(IX1KZn;j|cQLG>nNWe~pt>`}~_ zR*1eWDebNAc%@|TKvPdE6l_fWED`Z$kYiOE9VQhnw$4#qGw{ShaM2UoD#h`U98|nb z>4{u3K>4IR?t6(P$kmd@dpq_N$O%o~jI%b_CgM zt^z%1+cplh`hpG2XMBQuX7t5|UpvotSa$1u+UT5=m2%$h-e7)fLgAd?>gR_hLP7qUCjRX)x6t>np)t~T(*Lc6s$^-~40=qziJ=<1 z*4wXsUZ(jPEqAD%Pu$F(pp#<25N&ouU6ft>9f7a-xn?hZ#uq^ECSv>qg+B1 z;V^j^yQ3@sa|bZ{2g*A+tAFuv$BlfA$Y?+7n|L+71bvt1^2Y*wxyW(RZSH=4zFJ^= z89aku4Xp&LG)yMJ#}T!o$f-pQ29*{>=fZR#8zwww4h>`10A45ducKdLjTN(t`4T2c zUTZyLggQX(H-QwMcKaxk7MqkAaS$($mMp*a{v-OfNzsUC6a^TjUHPoA zyqaDZDIY615CVfP6cYbB%cZ%IBkH_zaVDd4-C|;uXRf`Zb4}6lLFyv=&SheB&9T#S zeT9e3mG1Uj*!H1!wR5&TrE^Wv@j>E3=gy^Obj`BUb8V%Q)z$X)T-x?wVD;>H&Bpe- z<$iGD6rl;n#WNCuVy4md4l*|mQs^Yns5m%0$9CGxD3CZxMpIjR7bWHQOGOd6&KOuO zN$wQu3xI#yr`3p_23tarE8Dv%v*DQHOl%8R~&Nd|*+ z<^DZ+6hjJ|b}dQlO~O{OO-Ma0n|v-)5q7!(_BLp|YihYyICquO4_q!iXdCrJlv{LB zBO0SyBz$Z+vXb~Y=V!j(GF!Wn$RzrBn{2@RH<@Anx%B*P(NUI_whj1rpQPw++2dXD zb4jb0!?QP9EXbS{o&_?7GE>G+5>MW5&^eWZVyt-J`>cCw5dUTW zf*=qu-b5EFy6$MeB`iU6l?wSSse(GXKDQf7zto z$Lg&kKw4PLp4X{$Ty7a`E;6xgdib5-SZeHX$XC~0a|_8~KX^N`D+Y^e@kAGK7Q4=|5y`@jIC{Tf2RSi z`VL8{&Pubk_k(45sB&#cg%C#~29QX>=ZWX%N|=~!`at4C0^q?mpN?$gG&CeM5Q}`; zUIvd{U47dA!7}^I=nT8H==i=@dPB#R(ug)Y( z_r6Y{TG)`xw zB&2}7Rd40G$$`RsX`Xl`iM$=Jr9w-9$ajKH9ZAPgIXf>xn2t26i+mHau~LZC zvpe#jW-w#r^O$m5ptAt>5ai zV0KY=t(s(L$_$^L_N;OJ&V|0;temTVCgRTVoV;oS#7oNW$@AJ=@-_%(M zgP=@)-8FnC#ji)FD3RfI$wnNGXvdJXB^-AO61yz5)v}~heFo2!a-$ZXHNI3JCK<9m zLgw>Gv=vM7Zi8EJ^Oh+IGeqB-hFe+obK!thh1drN**P8VOwq6vprY(Afhx*mH9IT8 zL>e;6gSBX^i-Zwgch&m~p|Os5BW=>9(}Ec&U*P~%q)W5Cu3uxJ08X=w&M_v6i`qI@ z$5{nBj!`kWm}8%2*9ove=zt-=m-r%X7MJ|__Bd#Kc{Bz{>+IDIxifb$yPQ+dj>zO! zOJB4lQxYB>8hrieNmXZHrr>0E1?vhOzAQd3$Ykdj8jqn#k*ppQmU)aD!yTVavA3H0xYKh)7oj_otxbF z#nLbSpD9%$4fqUwZ}(~u?v}u##gwm7MmK3Bea||qUnyxWT;?C6gA57rjIgPc3(Uvn zMJDH3>*5)jk(lQVEloK`A?_P};y2PUP+TNXCYk%{i|qNpJAAqlO|j0rEY{zSy-TFB zW5X-N8%(`?3z;saz57>w>5Ed( z3!0l7y7``U_zvSex2mo69@aH+@m^><_Z1905^I|NWn4QmxXi0Gu>k&uL$$adImqDH zWn;3=Oe@FoxZm?>Ast`Hz16LzmU4tD7mn@JI`?6JML`54MPAf>1nxE8M)GD2&cn#( zk?@CFlv2B`(QyxvSt2XHm1aFHC)nBt+NR90lWbbnEFX9Sj|dUjqq}Qw_wTbLR&e8F_&PH@lH*7{E<3SaCl zOycIL-mSLtn|evvOJ&2nlgJC3TdxIvYH<>vC@sR0t)jh)iB|_4n)~}Fa)G%lXU`Oi zZ=~2}HLKJaFZu;MqDEhC+Mg^`J|jgDLEXsl=Y#^d!?MK!3N5?C0d+P6m&LESd)uQs zAg%i1UcxOwaz!&P4ksE1=yrZWt?FlC(@mOIcohMM7Wy;co-Tffh6u#Js0~`p`M+eU zsm()9P3vWjf73_q1)JzzN;ONX9tr2$9Q;&{FNRX6!buCeLel1#w#E3_SfNuo`4uL-FL?R|t**`ITI8adO^VQNM zty6O4uR1L|PrHb`@b+@6zl*Q*KuM(!AQ28TXDDj&+1*dc$FtrMsPeN9x+-vfeOWXy zb^97s7jqs+)r7a=vZ3Q7J*^fwY*to@*U+4$$E``%u_Owr_oJM6O$xkAf|Hu5Ez7JS z#~J>((LbTc1-S&=N|X(M+AQA>MyJn^vZi8-)TRr{1A+XMvn~nd7FhvHAoQ?^qB=pq zM7q_kh(rd^ghJAUGm1V}o>3gK96FXbN3^~KBEww7l!Vx(6DJfVFEv5-;8 zJ2TFb$nSXfDwE9yq17m~ssiNL54V9hwBQA2@T?Bc>ffviv#Cf(gwr$L6UI(tsdb8s1qb6K@-tw#tc)rPoMAC4q?z zA#iAUh8Z=n4UWy*$4|}>Y#iU^wMoFnL+ZfTRuDw&a(lhU zGV{YEd)?9ERcDwxv14-C2XrysGiDuKJ(xSP%*u_~UyGR9iPR z05r|I+IUqRy$-_KdEv~qglqd0i>2Qnuf9+xK6~d#ZBG{JsZu$ zH%TuDY0eH=XqX97gzZPDHY2=n2PU@S%kzl}`jH$sW3f8yweKh+QXGw}mpOsp{Sn5o zpl)TKM(G%uJh+vy*V+$egsFIvG!31TH1ZxMe}SBh0^FD&_h-1$3KaR#F;6q;e4O$m zAdQafYj}X$@I+WE!0PHlV`7p*EMX7&aI{c^^mfS5EE&IM?(zoD5x8_~NK{mP8s6&H zPBjgFPK91S+4-75#`yetkotqg+moV7UiOP2x}HcAYAv~S+Q5LXyW_BR$30Mr1Vd zG{t?7h$p)i@0VhV6xk%o}cNIubazfD`7hn2p6Zu_d*5$ zDK+!A?DZ+y6_G_ow%^SzqFE~r8@<9)ED}L&qZGWZMotCpI6g9}M}fDe)?JpaPoDX2 zChn5#$%yuL+S@x(A_RYps{dboFUuo)r!id8f~W(DjeU9qf-Pi^nW zdsbzFllW?r*Kd*y~+z&D;w7sf~`m+jKNmDbc~|+hKBw!-N4xZCX||RY_hw? z*l|O4rZrwHeFvQ6O|ML?uK{8a-Nc@SwsX0tf<#~pjB)aucH|HpY$03k!WWL(0*cg7 zt_!dnfyM!yaD%nOm_-yiLqx9+h>e}LW^I$Swe16h5?(F7~K*`=H!$ZvnxredJ$riF_ z;M-dT{Nfw3a*=$B&{DSPML=vkw%|!c7GUJ>KLQ}3gGEE34?x+CSeoz`vGi(22dK3x zVzKY38t#btej3GMi3HS!)d77CbDABT4st6&t!JD}y&l1*swlT3H{COtg{>%b766}Z z>k!2e@E$ea4^{#SrbRbl`)R>YpV>z@wy3C=06Z%hNF&?wjI3aMMAyx7cGW@DhxH z8670ve*Vp-9va@cMVOy5=7fNDP{Cal8XhAj$;I3p+e8I%{#ZN83_=a&wi+yV%`Xp? zdr=wVu3oNf#tIrOJz>MtxX|O%Z8EY=J_@s=*;k{d_!bhRm)>e^^&(gaN zYFnLomfru-dvEXzoc+cx?N-#zz*aJQ`SU&a_eCuRe(LyMdlek*g^N^)Ekk5G_(w7# zqiYDb^R0jx1r8a7yhE&10r)zEUOuNEW1MBJn)bfum5qdw!$o!+JOK+m#_iNt)qNdM z8>9IeSvc~v=Jh_9>f?A|3WwMk#%ZJ(CCiD~5XI*uW<8FN{oVx*`8hV5mYjfFP^wWI zZv$*$Rt%#|-SeItGgmo=PuME{# zYAb9sb@8m($~XF7Tbj0U&1b*HGw>zAS}eG-bg^tGXKj<)S7_%^fFq^sBG%J{tFzTX96Dcv=+8>S{gJaZ>!NV@-;EHubj= zQ@#zlr~n`>*$5C))4qFQU7h5{9zz(Rm@uU`}gtj(FUGEkjhIcWtva5LJRo}$PgihaU^obv%WO!BfGrMG>A=Huv}f^+M( z1`?K9y9dQ^1scd$ZO^S>^sRYfctwY(Zh4y-d@nBq#JsD6!CIl73$5I$Wx4YBdH#kJ zW7|y^RIup&;;C*q2Ur!E8&oxwYXaJkgn-1SejwZJGRbS>kZJQg`vACrX37g zI?)dPi`o;zNP3C;(wqeRHu~g-_^?)N6s(ZPs;p;8-j2byJeJg#lC-0*##6abTR$Q* z1R~YRVWg2jA6T0U2GjHy^vCS1I3)X^PrFbJ<|Pj=C$EkkP5V$vphRK1PDG-TIjxG! zk8M-|CPEU7(&^@*reugPKTqI&zXz7@ghh`b?c>$L0if0 z6x!|1G}w-$hn6rw*6+CkhHxfRXFKFl3=!NIeh4rgBFSZX+#!V)YF*LI1Atd6vO(kL z1E{R8_{}>GD(uWtqFOB(zxA+5ctuViBSXxgWYW|bb2Ose4I?2Ff%;pO!Rk4Iw%I}b zv_7&{asKJQ>BS}y2_rq3JzW_mWURG?i4>RPUD{w>mg?Iy$J^-|6&K`cnENU~wQ7-L zVm!%XXxH8%BYche#$aNIB$4hgis#D;tOPaip#6WQxhGjvP^mPS*-`f zoGwnq78c8;^Q70N&{a7xvO6zY7zYjT?hMiUErRLQjGUaw4R8)biA_5U$Vq$0@=eQq ze^EH)8}{>+nthkQt1&r#hrILENAgidDfqQB{l@#Q|5(6z$mb#pFyZx`d+B6)QM>@Z z+!&4ZS$Jt`-x!|X^M|69xP2^baV zuWF7z3H$GAj=zlRius_{_j5ignz%W?_U-O z`X4_2#$*2O>rcY-@8d}Y|HIe6!Nb4%_>*<~WsT^b$)pG55^%U3HI?9f&NjZgZeS~9R$C>{SOYwsqz2- literal 0 HcmV?d00001 diff --git a/aqxmldmo.sql b/aqxmldmo.sql new file mode 100644 index 0000000..4d84833 --- /dev/null +++ b/aqxmldmo.sql @@ -0,0 +1,232 @@ +Rem +Rem $Header: aqxmldmo.sql 15-nov-2004.15:26:34 rbhyrava Exp $ +Rem +Rem aqxmldmo.sql +Rem +Rem Copyright (c) 2001, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqxmldmo.sql - AQ xml demo - setup users, queues and queue tables +Rem +Rem DESCRIPTION +Rem AQ XML demos to perform AQ operations over the Internet +Rem using the Internet Data Access Presentation +Rem +REM This program is used to setup users, queue tables, queues to +REM demonstrate AQ xml access and propagation. +Rem +Rem NOTES +Rem This sql file creates AQ adminstrator , aq database user +Rem grant required privileges to AQ internet super user +Rem grant database access to internet AQ agents +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/15/04 - agent +Rem rbhyrava 10/29/04 - add user setup +Rem rbhyrava 05/09/01 - remove REM from plsql blocK +Rem rbhyrava 04/12/01 - Merged rbhyrava_aqxmldemos +Rem rbhyrava 04/11/01 - +Rem rbhyrava 03/30/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +REM SETUP AQXML USERS +REM ================= + +REM +REM create admin and user accounts and grant http access to user +REM +CONNECT SYSTEM/MANAGER; +CREATE USER aqxmladmn IDENTIFIED BY aqxmladmn; +CREATE USER aqxmluser IDENTIFIED BY aqxmluser; + +GRANT CONNECT, RESOURCE, AQ_ADMINISTRATOR_ROLE TO aqxmladmn; +GRANT CONNECT, RESOURCE, AQ_USER_ROLE TO aqxmluser; + +GRANT EXECUTE ON dbms_lock TO aqxmladmn,aqxmluser ; + +REM +REM grant access to admin packages +REM +GRANT EXECUTE ON dbms_aqadm TO aqxmladmn; +GRANT EXECUTE ON dbms_aq TO aqxmluser; + +REM +REM Grant Create proxy session privileges to AQ servlet super-user +REM +GRANT CREATE SESSION TO scott; +ALTER USER aqxmluser GRANT CONNECT THROUGH scott; + +REM +REM Create AQ Agent to access AQ Servlet using HTTP +REM Used for 9.2/10.2 database compatibility for agent names +EXECUTE dbms_aqadm.create_aq_agent(agent_name=>'AQDEMO.COM/JOHN', enable_http =>true); +EXECUTE dbms_aqadm.create_aq_agent(agent_name=>'"AQDEMO.COM/JOHN"', enable_http =>true); + +REM +REM Map AQ Agent to Database user +REM +REM Used for 9.2/10.2 database compatibility for agent names +EXECUTE dbms_aqadm.enable_db_access('AQDEMO.COM/JOHN', 'aqxmluser'); +EXECUTE dbms_aqadm.enable_db_access('"AQDEMO.COM/JOHN"', 'aqxmluser'); + +REM +REM view registered AQ agents +REM +SELECT agent_name, db_username, http_enabled +FROM aq$internet_users ; + + +REM SETUP QUEUES +REM ================= + +CONNECT aqxmladmn/aqxmladmn; +SET SERVEROUTPUT ON + +rem create ADT +CREATE OR REPLACE TYPE book_typ AS OBJECT ( + title VARCHAR2(100), + authors VARCHAR2(100), + ISBN VARCHAR2(20), + price NUMBER); +/ + +GRANT EXECUTE ON book_typ TO PUBLIC ; + +CREATE OR REPLACE TYPE cars_typ AS OBJECT( + carno VARCHAR2(10), + year NUMBER, + model VARCHAR2(20), + color VARCHAR2(10), + car_details CLOB, + price NUMBER(12,2)); +/ + +GRANT EXECUTE ON cars_typ TO PUBLIC ; + +REM +REM create 8.1 compatible single consumer queue +REM +BEGIN +dbms_aqadm.create_queue_table( + queue_table => 'book_queue_tab', + queue_payload_type => 'BOOK_TYP' + ); +END; +/ + +REM +REM Create 8.1 compatible multi consumer queue table for ADT with CLOB +REM +BEGIN +dbms_aqadm.create_queue_table( + queue_table => 'cars_queue_tab', + queue_payload_type => 'CARS_TYP', + multiple_consumers => true + ); +END; +/ + +REM +REM Create single consumer queue table for JMS TEXT Message +REM +BEGIN +dbms_aqadm.create_queue_table( + queue_table => 'jmstext_queue_tab', + queue_payload_type => 'SYS.AQ$_JMS_TEXT_MESSAGE' + ); +END; +/ + +REM +REM Create multi consumer queue table for JMS MAP Message +REM +BEGIN +dbms_aqadm.create_queue_table( + queue_table => 'jmsmap_queue_tab', + queue_payload_type => 'SYS.AQ$_JMS_MAP_MESSAGE', + multiple_consumers => true + ); +END; +/ + +REM create queues +REM +BEGIN +dbms_aqadm.create_queue( queue_name => 'book_q1', + queue_table => 'book_queue_tab'); + +dbms_aqadm.create_queue( queue_name => 'cars_q1', + queue_table => 'cars_queue_tab'); + +dbms_aqadm.create_queue( queue_name => 'cars_q2', + queue_table => 'cars_queue_tab'); + +dbms_aqadm.create_queue( queue_name => 'jms_text_q1', + queue_table => 'jmstext_queue_tab'); + +dbms_aqadm.create_queue( queue_name => 'jms_map_q1', + queue_table => 'jmsmap_queue_tab'); +END; +/ + +REM +Rem Add subscribers to multi consumer queues +REM +BEGIN + dbms_aqadm.add_subscriber( queue_name=> 'CARS_Q1', + subscriber=> sys.aq$_agent('DEALS_CARS_Q1',null, null), + rule => 'tab.user_data.price > 30000'); + + dbms_aqadm.add_subscriber( queue_name=> 'CARS_Q2', + subscriber=> sys.aq$_agent('DEALS_CARS_Q2',null, null)); + + + dbms_aqadm.add_subscriber( queue_name=> 'JMS_MAP_Q1', + subscriber=> sys.aq$_agent('SUB1MAP',null, null)); + +END; +/ + +REM +REM Start queues +REM +BEGIN + dbms_aqadm.start_queue(queue_name => 'BOOK_Q1'); + dbms_aqadm.start_queue(queue_name => 'CARS_Q1'); + dbms_aqadm.start_queue(queue_name => 'CARS_Q2'); + dbms_aqadm.start_queue(queue_name => 'JMS_TEXT_Q1'); + dbms_aqadm.start_queue(queue_name => 'JMS_MAP_Q1'); +END; +/ + +REM +REM grant enqueue/dequeue privileges to aq database user +REM +BEGIN + dbms_aqadm.grant_queue_privilege('ENQUEUE', 'BOOK_Q1', 'aqxmluser', FALSE) ; + dbms_aqadm.grant_queue_privilege('DEQUEUE', 'BOOK_Q1', 'aqxmluser', FALSE) ; + + dbms_aqadm.grant_queue_privilege('ENQUEUE', 'CARS_Q1', 'aqxmluser', FALSE) ; + dbms_aqadm.grant_queue_privilege('DEQUEUE', 'CARS_Q1', 'aqxmluser', FALSE) ; + + dbms_aqadm.grant_queue_privilege('ENQUEUE', 'CARS_Q2', 'aqxmluser', FALSE) ; + dbms_aqadm.grant_queue_privilege('DEQUEUE', 'CARS_Q2', 'aqxmluser', FALSE) ; + + dbms_aqadm.grant_queue_privilege('ENQUEUE', 'JMS_TEXT_Q1','aqxmluser',FALSE) ; + dbms_aqadm.grant_queue_privilege('DEQUEUE', 'JMS_TEXT_Q1','aqxmluser',FALSE) ; + + dbms_aqadm.grant_queue_privilege('ENQUEUE', 'JMS_MAP_Q1','aqxmluser',FALSE) ; + dbms_aqadm.grant_queue_privilege('DEQUEUE', 'JMS_MAP_Q1','aqxmluser',FALSE) ; +END; +/ + +EXIT ; + diff --git a/aqxmldrp.sql b/aqxmldrp.sql new file mode 100644 index 0000000..336caae --- /dev/null +++ b/aqxmldrp.sql @@ -0,0 +1,90 @@ +Rem +Rem $Header: aqxmldrp.sql 02-nov-2004.17:21:31 rbhyrava Exp $ +Rem +Rem aqxmldrp.sql +Rem +Rem Copyright (c) 2001, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqxmldrp.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/02/04 - drop users +Rem rbhyrava 04/12/01 - Merged rbhyrava_aqxmldemos +Rem rbhyrava 04/09/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect aqxmladmn/aqxmladmn +REM Stop queues +BEGIN + dbms_output.put_line ('Stopping Queues ...'); + dbms_aqadm.stop_queue(queue_name => 'BOOK_Q1'); + dbms_aqadm.stop_queue(queue_name => 'CARS_Q1'); + dbms_aqadm.stop_queue(queue_name => 'CARS_Q2'); + dbms_aqadm.stop_queue(queue_name => 'JMS_TEXT_Q1'); + dbms_aqadm.stop_queue(queue_name => 'JMS_MAP_Q1'); +END; +/ + +REM Drop queues +BEGIN + dbms_output.put_line ('Dropping Queues ...'); + dbms_aqadm.drop_queue(queue_name => 'BOOK_Q1'); + dbms_aqadm.drop_queue(queue_name => 'CARS_Q1'); + dbms_aqadm.drop_queue(queue_name => 'CARS_Q2'); + dbms_aqadm.drop_queue(queue_name => 'JMS_TEXT_Q1'); + dbms_aqadm.drop_queue(queue_name => 'JMS_MAP_Q1'); +END; +/ + +BEGIN + dbms_output.put_line ('Dropping Queue Tables ...'); + dbms_aqadm.drop_queue_table ( + queue_table => 'book_queue_tab', + force => TRUE + ); + dbms_output.put_line ('Dropped Queue Table book_queue_tab.'); + dbms_aqadm.drop_queue_table ( + queue_table => 'cars_queue_tab', + force => TRUE + ); + dbms_output.put_line ('Dropped Queue Table cars_queue_tab.'); + + dbms_aqadm.drop_queue_table ( + queue_table => 'jmstext_queue_tab', + force => TRUE + ); + dbms_output.put_line ('Dropped Queue Table jmstext_queue_tab.'); + + dbms_aqadm.drop_queue_table ( + queue_table => 'jmsmap_queue_tab', + force => TRUE + ); + dbms_output.put_line ('Dropped Queue Table jmsmap_queue_tab.'); + +END; +/ + +connect system/manager + +EXECUTE dbms_aqadm.drop_aq_agent('"aqdemo.com/john"') ; +EXECUTE dbms_aqadm.drop_aq_agent('"AQDEMO.COM/JOHN"') ; +ALTER USER aqxmluser REVOKE CONNECT THROUGH scott; + +drop user aqxmladmn cascade ; +drop user aqxmluser cascade ; + diff --git a/aqxmlhtp.sql b/aqxmlhtp.sql new file mode 100644 index 0000000..9516449 --- /dev/null +++ b/aqxmlhtp.sql @@ -0,0 +1,190 @@ +Rem +Rem $Header: aqxmlhtp.sql 02-nov-2004.22:26:43 rbhyrava Exp $ +Rem +Rem aqxmlhtp.sql +Rem +Rem Copyright (c) 2001, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqxmlhtp.sql - AQ xml HTTP Propagation Demo +Rem +Rem DESCRIPTION +Rem args passed : PROTOCOL,HOST, PORT arguments with appropriate values +Rem PROTOCOL is http or https +Rem HOST is webserver hostname +Rem PORT is http/(s) port number +Rem for eg: http://my-pc:18081/aqserv/servlet/AQPropServlet +Rem HOST is my-pc, PORT is 18081 +Rem NOTES +Rem See aqxmlREADME.txt for setup instructions +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/02/04 - use oc4j +Rem rbhyrava 07/20/01 - args +Rem rbhyrava 06/20/01 - comments- dblink creation +Rem rbhyrava 05/09/01 - dequeue all messages +Rem rbhyrava 04/12/01 - Merged rbhyrava_aqxmldemos +Rem rbhyrava 03/30/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +REM create database link using http protocol for aq http propagation demo +REM john is http user using propagation with password welcome + +spool aqxmlhtp.log + +set serveroutput on +CONNECT / as sysdba ; +GRANT EXECUTE ON dbms_aqjms TO scott; +GRANT EXECUTE ON dbms_aqadm TO scott; +GRANT EXECUTE ON dbms_aqjms TO aqxmluser; +GRANT EXECUTE ON dbms_aqadm TO aqxmluser; +GRANT EXECUTE ON dbms_aq TO aqxmladmn ; + +REM create database link using http protocol +REM ---------------------------------------- + +drop public database link dba ; + +CREATE PUBLIC DATABASE LINK dba + CONNECT TO '"aqdemo.com/john"' IDENTIFIED BY "welcome" USING + '(DESCRIPTION=(ADDRESS=(PROTOCOL=&1)(HOST=&2)(PORT=&3)))' ; + +REM Verify the dblink status + + +SELECT owner, db_link, username, host, created + FROM dba_db_links + WHERE username IS NOT NULL ; + +connect aqxmladmn/aqxmladmn +set serveroutput on + +REM setup remote subscribers +BEGIN + + dbms_aqadm.remove_subscriber( queue_name=> 'CARS_Q1', + subscriber=> sys.aq$_agent( + 'HTTP_DEALS_CARS_Q1Q2','aqxmladmn.CARS_Q2@dba', NULL)); + +END; +/ + +BEGIN + dbms_aqadm.add_subscriber( queue_name=> 'CARS_Q1', + subscriber=> sys.aq$_agent( + 'HTTP_DEALS_CARS_Q1Q2','aqxmladmn.CARS_Q2@dba', NULL)); +END; +/ + +REM Schedule propagation +BEGIN + dbms_aqadm.unschedule_propagation(queue_name => 'aqxmladmn.CARS_Q1', + destination => 'dba'); +END; +/ + +BEGIN + dbms_aqadm.schedule_propagation(queue_name => 'aqxmladmn.CARS_Q1', + destination => 'dba'); +END; +/ + +connect aqxmluser/aqxmluser +set serveroutput on + +REM Enqueue messages + +CREATE OR REPLACE PROCEDURE ENQUEUE_CARS( cars aqxmladmn.CARS_TYP, pri in number) as +enq_msgid RAW(16); +eopt dbms_aq.enqueue_options_t; +mprop dbms_aq.message_properties_t; +rcpt dbms_aq.aq$_recipient_list_t; + +BEGIN + + mprop.priority := pri; + + dbms_aq.enqueue( + queue_name => 'aqxmladmn.cars_q1', + enqueue_options => eopt, + message_properties => mprop, + payload => cars, + msgid => enq_msgid); + dbms_output.put_line ('Enqueued ' || cars.car_details) ; +END ENQUEUE_CARS; +/ +show errors + +DECLARE + carspayload aqxmladmn.cars_typ ; +BEGIN + carspayload := aqxmladmn.cars_typ( + '3MEW123', 1999, 'BMW', 'RED','1999 Model BMW RED car', 45000) ; + enqueue_cars(carspayload, 1) ; + + carspayload := aqxmladmn.cars_typ( + '4MAT567', 2001, 'LEXUS', 'BLACK','2001 Model LEXUS BLACK car', 48000); + enqueue_cars(carspayload, 2) ; + +END; +/ +commit ; + +REM Dequeue Messages Now + + +CREATE OR REPLACE PROCEDURE DEQUEUE_CARS(appname varchar2) AS + deq_msgid RAW(16); + dopt dbms_aq.dequeue_options_t; + mprop dbms_aq.message_properties_t; + payload aqxmladmn.cars_typ; + no_messages exception; + pragma exception_init(no_messages, -25228); + +BEGIN + + dopt.consumer_name := appname; + dopt.wait := 30; + dopt.navigation := DBMS_AQ.FIRST_MESSAGE; + loop + dbms_aq.dequeue( + queue_name => 'aqxmladmn.cars_q2', + dequeue_options => dopt, + message_properties => mprop, + payload => payload, + msgid => deq_msgid); + + dbms_output.put_line ('-Carno:' || payload.carno || + ' Year :' || payload.year || + ' Model:' || payload.Model || + ' Color:' || payload.color || + ' Price:' || payload.Price ) ; + + commit; + end loop; + +EXCEPTION + WHEN no_messages THEN + dbms_output.put_line('No more messages in queue '); + commit; + +END DEQUEUE_CARS; +/ +show errors + +execute dbms_lock.sleep(100) ; + +BEGIN + DEQUEUE_CARS ('HTTP_DEALS_CARS_Q1Q2' ) ; +END; +/ +commit ; +spool off diff --git a/blobdemo.dat b/blobdemo.dat new file mode 100644 index 0000000..2bebc2f --- /dev/null +++ b/blobdemo.dat @@ -0,0 +1,2 @@ +1234567890 + diff --git a/calldemo.sql b/calldemo.sql new file mode 100644 index 0000000..8b9f7c9 --- /dev/null +++ b/calldemo.sql @@ -0,0 +1,87 @@ +rem +rem $Header: calldemo.sql 21-sep-2004.11:03:44 stsun Exp $ +rem +rem Copyright (c) 1991, 2004, Oracle. All rights reserved. +rem +rem NAME +rem calldemo.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem stsun 09/21/04 - add order by the query +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem rkooi2 11/27/92 - Creation +CREATE OR REPLACE PACKAGE calldemo AS + + TYPE char_array IS TABLE OF VARCHAR2(20) + INDEX BY BINARY_INTEGER; + TYPE num_array IS TABLE OF FLOAT + INDEX BY BINARY_INTEGER; + + PROCEDURE get_employees( + dept_number IN number, -- department to query + batch_size IN INTEGER, -- rows at a time + found IN OUT INTEGER, -- rows actually returned + done_fetch OUT INTEGER, -- all done flag + emp_name OUT char_array, + job OUT char_array, + sal OUT num_array); + +END calldemo; +/ + +CREATE OR REPLACE PACKAGE BODY calldemo AS + + CURSOR get_emp (dept_number IN number) IS + SELECT ename, job, sal FROM emp + WHERE deptno = dept_number + ORDER BY ename, job, sal; + + -- Procedure "get_employees" fetches a batch of employee + -- rows (batch size is determined by the client/caller + -- of the procedure). It can be called from other + -- stored procedures or client application programs. + -- The procedure opens the cursor if it is not + -- already open, fetches a batch of rows, and + -- returns the number of rows actually retrieved. At + -- end of fetch, the procedure closes the cursor. + + PROCEDURE get_employees( + dept_number IN number, + batch_size IN INTEGER, + found IN OUT INTEGER, + done_fetch OUT INTEGER, + emp_name OUT char_array, + job OUT char_array, + sal OUT num_array) IS + + BEGIN + IF NOT get_emp%ISOPEN THEN -- open the cursor if + OPEN get_emp(dept_number); -- not already open + END IF; + + -- Fetch up to "batch_size" rows into PL/SQL table, + -- tallying rows found as they are retrieved. When all + -- rows have been fetched, close the cursor and exit + -- the loop, returning only the last set of rows found. + + done_fetch := 0; -- set the done flag FALSE + found := 0; + + FOR i IN 1..batch_size LOOP + FETCH get_emp INTO emp_name(i), job(i), sal(i); + IF get_emp%NOTFOUND THEN -- if no row was found + CLOSE get_emp; + done_fetch := 1; -- indicate all done + EXIT; + ELSE + found := found + 1; -- count row + END IF; + END LOOP; + END; +END; +/ diff --git a/case1.rcv b/case1.rcv new file mode 100644 index 0000000..cf19e5b --- /dev/null +++ b/case1.rcv @@ -0,0 +1,260 @@ +# +# $Header: case1.rcv 11-apr-2001.15:20:02 banand Exp $ +# +# Copyright (c) 1995, 2000 Oracle Corporation. All rights reserved. +# +# NAME +# case1.rcv +# +# DESCRIPTION +# This case study can be used as the basis for developing your own backup, +# maintenance, restore, and recovery scripts for a single instance database +# running in no-archivelog mode. +# +# NOTES +# You should not run all of the commands in this file in a single RMAN +# session. Rather, the various sections in this file should be separated +# into individual RMAN scripts which can be run to configure, backup, +# restore, and recover the database. +# +# MODIFIED (MM/DD/YY) +# banand 04/11/01 - re-write this case for no-archivelog mode database +# banand 04/11/01 - Creation +# +# Organization: +# This case study is divided into the following sections: +# 1. Configuring RMAN parameters +# 2. Backup +# - start script for backup cycle +# (full level 0 consistent backups) +# - script for other days of backup cycle +# (differential incremental level 1 consistent backups) +# - taking backups of read-only tablespace +# 3. Restore validation +# - command to verify database is restorable. +# 4. Recovery Catalog maintenance +# 5. Restore and Recovery +# +# How to run a file containing RMAN commands: +# +# Here is an example of how to run a file that contains RMAN commands: +# rman target internal/pwd@prod1 catalog rman/rman@rcat cmdfile command.rcv +# +# See the Recovery Manager Users Guide for more options on how to connect. +# + +# Section 1 - CONFIGURATION +#----------------------------------------------------------------------------- + +# There are various parameters that can be used to configure RMAN operations +# to suit your needs. Some of the things that you can configure are: +# - the required number of backups of each datafile +# - the number of server processes that will do backup/restore operations +# in parallel +# - the directory where on-disk backups will be stored +# +# This case study assumes that you want: +# - 5 backups of each datafile +# - backups to be stored on disk in the /backup directory +# - 2 server processes to do backup/restore operations in parallel +# - no backups for tablespace tbl_exclude, because it is easy to recreate +# +# It should be noted that configuration settings are stored persistently, and +# will be used by RMAN for all subsequent backup, restore, recovery, and +# maintenance operations. + +# Configure backups to be written to disk. +CONFIGURE DEFAULT DEVICE TYPE TO DISK; + +# Configure RMAN to keep at least 5 backups of each datafile. +# If you have certain backups which must be retained longer than this +# retention policy, you can use the KEEP option with the BACKUP command when +# creating those backups. +CONFIGURE RETENTION POLICY TO REDUNDANCY 5; + +# Configure RMAN to use two disk channels for backup, restore, recovery, and +# maintenance operations. +CONFIGURE DEVICE TYPE DISK PARALLELISM 2; + +# Configure RMAN to write disk backups to the /backup directory. +# The format specifier %t is replaced with a 4-byte timestamp, %s with the +# backup set number, and %p with the backup piece number. +CONFIGURE CHANNEL DEVICE TYPE DISK FORMAT '/backup/ora_df%t_s%s_s%p'; + +# Configure RMAN to back up the control file after each backup. +CONFIGURE CONTROLFILE AUTOBACKUP ON; + +# Configure RMAN to write controlfile autobackups to the /backup directory. +CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '/backup/ora_cf%F'; + +# Excludes tbs_exclude from full database backups. NOEXCLUDE can be specified +# with the BACKUP command to override this configuration. +CONFIGURE EXCLUDE FOR TABLESPACE tbl_exclude; + +# NOTES: +# - If you want backups to go to tape, refer to the configuration +# section in case2.rcv on how to configure tape backups. +# However in case of disaster recover if RMAN is not connected to +# recovery catalog, you will have to manually allocate all channels where +# backups were taken. +# +# - Use the SHOW ALL command to see your current configuration settings. +# +# - Save the database id displayed in the RMAN output if you are taking +# RMAN backups in nocatalog mode or database name is ambigious in recovery +# catalog. The database id is required during disaster recovery (See +# Section 5). You will see the database id in RMAN output on connecting +# to target database like : +# +# connected to target database: INVENTORY (DBID=1670954628) + +# Section 2 - BACKUP +# ----------------------------------------------------------------------------- +# Since you are operating the database in no-archivelog mode, only the +# following kinds of backups are allowed: +# - whole database backups when the database is cleanly closed and the +# instance is mounted +# - tablespace backups of tablespaces that are offline clean or read only + +# The following scenario assumes that you want to take one full database +# backup every week, and one incremental database backup every day. The +# backup cycle starts on Friday. A full backup is taken on Friday, and an +# incremental backup is taken every other day. The retention policy of +# REDUNDANCY 5 applies only to full (not incremental) backups, so the +# combination of that policy and this backup schedule ensures that you can +# restore to any incremental backup time for the last 5 weeks. + +# Section 2.1 - Start script for backup cycle +# ------------------------------------------------------ +# The following commands are run each Friday to start the backup cycle. +# The steps are: +# - Re-start the database to perform crash recovery, in case the database is +# not currently open, and was not shut down consistently. The database is +# started in DBA mode so that normal users cannot connect. +# - Shut down with the IMMEDIATE option to close the database consistently. +# - Startup and mount the database. +# - Backup database with incremental level 0. +# - Open database for normal operation. + +STARTUP FORCE DBA; +SHUTDOWN IMMEDIATE; +STARTUP MOUNT; +BACKUP INCREMENTAL LEVEL 0 DATABASE FILESPERSET 4; +ALTER DATABASE OPEN; + + +# If the above backup fails for any reaon, you can use the NOT BACKED UP SINCE +# option on the BACKUP command (9i restartable backup feature) to continue +# from the point of failure. The small value of FILESPERSET is good for +# restartable backups. However you should note that smaller FILESPERSET +# produces more backup sets. + +# To re-start from the point of failure, run following commands +BACKUP INCREMENTAL LEVEL 0 DATABASE FILESPERSET 4 + NOT BACKED UP SINCE TIME 'SYSDATE-1'; +ALTER DATABASE OPEN; + + +# Section 2.2 - script for other days of the backup cycle +# ------------------------------------------------------------- +# The following commands can be run from Saturday through Thursday to take +# cumulative incremental backups. They are same as in section 2.1, except +# that LEVEL 1 is specified on BACKUP command. +# The steps are the same as in section 2.1, except that the options +# LEVEL 1 CUMULATIVE indicate that only the blocks that have changed +# since the last level 0 backup will be backed up. If the CUMULATIVE +# option was not specified, then only the blocks that have changed since +# the last level 1 backup will be backed up. The advantage of a cumulative +# backup is that only one incremental backup ever needs to be applied +# during recovery. + +STARTUP FORCE DBA; +SHUTDOWN IMMEDIATE; +STARTUP MOUNT; +BACKUP INCREMENTAL LEVEL 1 CUMULATIVE DATABASE FILESPERSET 4; +ALTER DATABASE OPEN; + + +# Section 2.3 - Taking backups of readonly tablespaces +# ---------------------------------------------------- +# The database does not have to be closed to back up a readonly tablespace. +# The following command can be used to backup a readonly tablespace. + +BACKUP TABLESPACE read_only_tablespace_name; + +# Section 3 - RESTORE VALIDATION +#----------------------------------------------------------------------------- +# The following commands can be run any time to check if RMAN is capable of +# restoring database/tablespace using existing backups. + +RESTORE DATABASE VALIDATE; # checks if database + # can be restored +RESTORE TABLESPACE read_only_tablespace_name VALIDATE; # check if tablespace + # is restorable + +# Section 4 - MAINTENANCE COMMANDS +#----------------------------------------------------------------------------- +# Basic steps for maintenance are: + +# - Verify all backups on backup media are intact +CROSSCHECK BACKUP OF DATABASE; + +# - Display a list of files that need to be backed up based on the retention +# policy. For this case study, files that don't have at least 5 backups +# will be reported. +REPORT NEED BACKUP; + +# - delete un-necessary backups. This command deletes backups based on the +# retention policy. For this case study, all backups older than the 5 most +# recent backups of each datafile will be deleted. +DELETE OBSOLETE; + +# - get complete list of existing backups +LIST BACKUP SUMMARY; + + +# Section 5 - RESTORE AND RECOVERY +#----------------------------------------------------------------------------- +# In case of any user error or media failure you would have to do complete +# database recovery. However using the SET UNTIL command, it is possible to +# recover to different points in time when incrementals were taken. Because +# redo logs are not archived, only full and incremental backups are available +# for restore and recovery. +# + +# It is assumed that you have all the configuration files like the server +# parameter file (spfile - equivalent of init.ora in 9i), tnsnames.ora, and +# listener.ora in the appropriate places, and that you can startup the Oracle +# instance in nomount mode and connect from RMAN to the target instance. + +# +# The steps are: +# - If not using a recovery catalog, or if the database name is ambiguous in, +# the recovery catalog you need to start RMAN without TARGET option and +# set the dbid before restoring the controlfile from autobackup. +# - Startup database in nomount mode (you should have restored initialization +# files for database, and listener files (only if connecting over SQLNET)). +# - restore controlfile. +# - restore all database files. Use CHECK READONLY, to make sure all read-only +# files are correct. If not RMAN will restore them. +# - apply all incrementals. +# - open database with resetlogs mode to re-create online logs. + + +SET DBID ; +CONNECT TARGET ; +STARTUP NOMOUNT; +RUN +{ + # uncomment the SET UNTIL command to restore database to the incremental + # backup taken three days ago. + # SET UNTIL TIME 'SYSDATE-3'; + SET CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '/backup/ora_cf%F'; + RESTORE CONTROLFILE FROM AUTOBACKUP; + ALTER DATABASE MOUNT; + RESTORE DATABASE CHECK READONLY; + RECOVER DATABASE NOREDO; + ALTER DATABASE OPEN RESETLOGS; +} + +#-end of file- diff --git a/case2.rcv b/case2.rcv new file mode 100644 index 0000000..1b3a9ab --- /dev/null +++ b/case2.rcv @@ -0,0 +1,480 @@ +# +# $Header: case2.rcv 27-apr-2001.12:41:14 banand Exp $ +# +# Copyright (c) 1995, 2001, Oracle Corporation. All rights reserved. */ +# +# NAME +# case2.rcv +# +# DESCRIPTION +# This case study can be used as basis for developing your own backup, +# maintenance, restore, and recovery scripts for a single instance database +# running in archivelog mode. +# +# The examples provided in this case study will use a disk area (/backup +# directory) to hold the most recent one week of backups, in order to +# expedite backup/restore operations. The size of this area may vary +# depending on database size, redo generated, etc. If you want all backups +# to go to tape, remove DEVICE TYPE DISK option from the BACKUP commands +# given in this case study. + +# Only the incremental backups are stored on disk for one week. The level 0 +# backup goes immediately to tape. This means that RMAN will always have to +# read tape for recovery. + +# +# NOTES +# You should not run all of the commands in this file in a single RMAN +# session. Rather, the various sections in this file should be separated +# into individual RMAN scripts which can be run to configure, backup, +# restore, and recover the database. +# +# +# MODIFIED (MM/DD/YY) +# banand 04/11/01 - re-write this case for archivelog mode database +# banand 04/11/01 - Creation +# +# Organization: +# +# This case study is divided into the following sections: +# 1. Configuring RMAN parameters +# 2. Backup +# - start script for backup cycle +# (full database backup and archivelog backups) +# - script for other days of backup cycle +# (cumulative incremental level 1 backups and archivelog backups) +# 3. Restore validation +# - verify that the database/tablespace is restorable +# 4. Maintenance commands +# 5. Restore and Recovery +# - Datafile recovery +# - Tablespace recovery +# - Controlfile recovery +# - Block recovery +# - Disaster recovery +# - Database Point-in-time recovery +# +# How to run the file containing RMAN commands: +# +# Here is an example of how to run the file that contains RMAN commands: +# +# rman target internal/pwd@prod1 catalog rman/rman@rcat cmdfile command.rcv +# +# See the Recovery Manager readme.doc and the Oracle8 Backup and +# Recovery Guide for more options on how to connect. +# +# + +# Section 1 - CONFIGURATION +# ---------------------------------------------------------------------------- + +# There are various parameters that can be used to configure RMAN operations +# to suit your needs. Some of the things that you can configure are: +# - the recovery window, to keep backups so that it is possible to recover +# the database to any point in time during last X days. +# - the number of server processes that can do backups/restore operations +# in parallel +# - default device type for backups +# - the directory where on-disk backups will be stored +# +# This case study assumes that you +# - have 1 tape drive +# - want parallelization for disk to two and for tape to one +# - want to be able to recover your database to any point in time during the +# last 30 days +# - want all full database backups to go only to tape +# - want to keep incrementals on disk for seven days +# - want to leave archivelogs on disk for seven days +# - want one copy of each archivelog backup saved on tape +# - want to back up archivelogs once per day +# - want to exclude tablespace tbl_exclude from database backups and +# restores because it is easier to re-create it than to restore and +# recover it. +# +# It should be noted that configuration setting is done just once, and these +# settings are used by RMAN to perform all subsequent backup, restore, +# recovery, and maintenance operations. + +# Configure backups to be written to tape, via a 3rd-party media managment +# product. +CONFIGURE DEFAULT DEVICE TYPE TO SBT; + +# If the media manager requires an RMAN PARMS string, configure it here. +# The media manager documentation will specify whether this configuration is +# needed. +CONFIGURE CHANNEL DEVICE TYPE SBT PARMS ''; + +# Configure the number of server processes (channels) that write backups to +# DISK. You can delete these three lines if you want to only back up to tape. +CONFIGURE DEVICE TYPE DISK PARALLELISM 2; +CONFIGURE CHANNEL DEVICE TYPE DISK FORMAT '/backup/ora_df%t_s%s_s%p'; +CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '/backup/%F'; + +# Set the retention policy to a recovery window of 30 days. This ensures that +# RMAN retains all backups needed to recover the database to any point in time +# in the last 30 days. You can use the DELETE OBSOLETE command to delete +# backups that are no longer required by the retention policy. To exclude a +# backup from consideration by the policy, you can use KEEP option with the +# BACKUP command. +CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF 30 DAYS; + +# Enable the autobackup feature to backup the controlfile after each database +# or archivelog backup. +CONFIGURE CONTROLFILE AUTOBACKUP ON; + +# Enable the backup optimization feature introduced in 9i to make sure that +# RMAN won't backup an archivelog or datafile if there already exists a backup +# of that file. The FORCE option can be used to override optimization on a +# specific BACKUP command. +CONFIGURE BACKUP OPTIMIZATION ON; + +# Exclude tbs_exclude from full database backups. NOEXCLUDE can be specified +# with backup command to override this configuration. +CONFIGURE EXCLUDE FOR TABLESPACE tbl_exclude; + +# IMPORTANT: Save the database id displayed in the RMAN output if you are +# operating RMAN backups in nocatalog mode, since it is required during +# disaster recovery. You will see the database id in output from RMAN on +# connecting to target database like: +# +# connected to target database: INVENTORY (DBID=1670954628) + +# Use the SHOW ALL command to see the current configuration settings. + +# Section 2 - BACKUP +#----------------------------------------------------------------------------- +# Running database in archivelog mode provides following advantages +# - high availability, i.e., database is available during backups. +# - point in time recovery within recovery window for database/tablespace. + +# You can also follow the procedure given in case1.rcv for taking consistent +# backups. Only disadvantage of taking consistent backups is that you have to +# close database cleanly, and open in restricted mode. Hence database is not +# available for general use during consistent backup. +# +# Following scenario assumes that you want to take one full database once a +# week, doing every day incrementals. Backup cycle starts on friday, +# i.e., every friday full backup, and on other days incrementals. + + +# Section 2.1 - Start script for backup cycle +# ------------------------------------------- +# The following commands are run each Friday to start the backup cycle. +# The steps are: +# - Take an incremental level 0 backup of the database. A level 0 backup is +# a complete backup of the entire file which can be used as the basis +# for a subsequent incremental backup. +# - Backup all archivelogs that have not already been backed up. +# - Delete on-disk archivelogs older than seven days. + +BACKUP INCREMENTAL LEVEL 0 DATABASE FILESPERSET 4; +BACKUP ARCHIVELOG ALL; +DELETE ARCHIVELOG UNTIL TIME 'SYSDATE-7'; + +# If the above backup fails for any reaon, you can use the NOT BACKED UP SINCE +# option on the BACKUP command (9i restartable backup feature) to continue +# from the point of failure. The small value of FILESPERSET is good for +# restartable backups. However you should note that smaller FILESPERSET +# produces more backup sets. + +# Use the following commands to re-start backups after a failure: +BACKUP INCREMENTAL LEVEL 0 DATABASE FILESPERSET 4 + NOT BACKED UP SINCE TIME 'SYSDATE-1'; +BACKUP ARCHIVELOG ALL; +DELETE ARCHIVELOG UNTIL TIME 'SYSDATE-7'; + +# Section 2.2 - script for other days of backup cycle +# ----------------------------------------------------- +# The following commands can be run from Saturday through Thursday to take +# cumulative incremental backups. +# The steps are: +# - delete incrementals on disk that were taken before 7 days. +# - take differential incremental backup of complete database. +# - copy incrementals to tape. +# - backup all archiveogs that are not backed up. +# - deletes any copies of archivelog on disk older than 7 days. + +DELETE BACKUP COMPLETED BEFORE 'SYSDATE-7' DEVICE TYPE DISK; +BACKUP INCREMENTAL LEVEL 1 CUMULATIVE DEVICE TYPE DISK DATABASE FILESPERSET 4; +BACKUP BACKUPSET ALL; # copies backups from disk to tape +BACKUP ARCHIVELOG ALL; +DELETE ARCHIVELOG UNTIL TIME 'SYSDATE-7'; + +# CONCEPT NOTE ON CUMULATIVE INCREMENTAL BACKUPS: Cumulative incremental level +# 1 backups will backup the blocks that changed since the last level 0 backup. +# Incremental backups are similar in function to archived logs and RMAN uses +# them in favor of archived logs during recovery. If the CUMULATIVE option +# was not specified, then only the blocks that have changed since the last +# level 1 backup will be backed up. The advantage of a cumulative backup is +# that only one incremental backup ever needs to be applied during recovery. + +# As in section 2.1, you can use the NOT BACKED UP SINCE option with the +# BACKUP command (9i re-startable backup feature) to continue from the point +# of failure. + +# Use the following commands to re-start backups after a failure: +DELETE BACKUP COMPLETED BEFORE 'SYSDATE-7' DEVICE TYPE DISK; +BACKUP INCREMENTAL LEVEL 1 CUMULATIVE DEVICE TYPE DISK DATABASE FILESPERSET 4 + NOT BACKED UP SINCE TIME 'SYSDATE -1 '; +BACKUP BACKUPSET ALL; # copies backups from disk to tape +BACKUP ARCHIVELOG ALL; +DELETE ARCHIVELOG UNTIL TIME 'SYSDATE-7'; + +# Section 3 - RESTORE VALIDATION +# ---------------------------------------------------------------------------- +# The following commands can be run any time to check if RMAN is capable of +# restoring the database/tablespace using existing backups. + +# check if database can be restored +RESTORE DATABASE VALIDATE; + +# check if tablespace tst_tbs can be restored +RESTORE TABLESPACE tst_tbs VALIDATE; + +# check if controlfile can be restored +RESTORE CONTROLFILE VALIDATE; + +# check if archivelogs for the past two weeks can be restored +RESTORE ARCHIVELOG FROM TIME 'SYSDATE-14' VALIDATE; + + +# Section 4 - MAINTENANCE COMMANDS +#----------------------------------------------------------------------------- +# The following commands can be run any time for maintenance of backups. + +# Verify that all backups which RMAN thinks are stored by the third-party +# media manager still exist, and generate a report of backups that need to be +# taken to satisy the retention policy. +CROSSCHECK BACKUP; +REPORT NEED BACKUP; + +# Delete backups that are no longer needed to satisfy the retention policy. +# Since we have set the retention policy to a recovery window of 30 days, any +# datafile backups (generated without the KEEP option) not required to recover +# within 30 days are deleted. After deciding which datafile backups are no +# longer needed, RMAN can then decide which archivelog backups are no longer +# needed. Archivelog backups are not needed if they are older than ANY +# existing datafile backup. +DELETE OBSOLETE; + +# get complete list of existing backups +LIST BACKUP SUMMARY; + + +# Section 5 - RESTORE AND RECOVERY +#----------------------------------------------------------------------------- +# +# Section 5.1 - Datafile recovery +#----------------------------------------------------- +# +# This section assumes that datafile 5 has been damaged and needs to be +# restored and recovered, and that the current controlfile and all other +# datafiles are intact. The database is open during the restore and recovery. +# +# The steps are: +# - offline the datafile that needs recovery +# - restore the datafile from backups +# - apply incrementals and archivelogs as necessary to recover. +# - make online recovered datafile + +RUN +{ + SQL 'ALTER DATABASE DATAFILE 5 OFFLINE'; + + # If you want to restore to a different location, uncomment the following + # command. + # SET NEWNAME FOR DATAFILE 5 TO '/newdirectory/new_filename.f'; + + RESTORE DATAFILE 5; + + # If you restored to a different location, uncomment the command below to + # switch the controlfile to point to the file in the new location. + # SWITCH DATAFILE ALL; + + RECOVER DATAFILE 5; + SQL 'ALTER DATABASE DATAFILE 5 ONLINE'; +} + +# Section 5.2 - Tablespace recovery +#------------------------------------------------------- +# +# This section assumes that tablespace tbs_5, containing datafiles 5, 6, and 7 +# has been damaged and needs to be restored and recovered, and that the +# current controlfile and all other datafiles are intact. The database is +# open during the restore and recovery. +# +# The steps are: +# - Offline the tablespace that needs recovery. +# - Restore the tablespace from backups. +# - Apply incrementals and archivelogs as necessary to recover. +# - Online the recovered tablespace. + +RUN +{ + SQL 'ALTER TABLESPACE TBS_5 OFFLINE'; + + # If you want to restore to a different location, uncomment the following + # commands. + # SET NEWNAME FOR DATAFILE 5 TO '/newdirectory/new_filename_for_5.f'; + # SET NEWNAME FOR DATAFILE 6 TO '/newdirectory/new_filename_for_6.f'; + # SET NEWNAME FOR DATAFILE 7 TO '/newdirectory/new_filename_for_7.f'; + + RESTORE TABLESPACE TBS_5; + + # If you restored to different locations, uncomment the commands below to + # switch the controlfile to point to the files in their new locations. + # SWITCH DATAFILE ALL; + + RECOVER TABLESPACE TBS_5; + SQL 'ALTER TABLESPACE TBS_5 ONLINE'; +} + +# Section 5.3 - Controlfile recovery +#----------------------------------- +# + +# Oracle strongly recommends that you specify multiple controlfiles, on +# separate physical disks and controllers, in the CONTROL_FILES initialization +# parameter. +# - If one copy is lost due to media failure, copy one of the others over the +# lost controlfile and restart the instance. +# - If you lose all copies of the controlfile, you must re-create it using +# the CREATE CONTROLFILE sql command. +# +# You should use RMAN to recover a backup controlfile only if you have lost +# all copies of the current controlfile, because after restoring a backup +# controlfile, you will have to open RESETLOGS and take a new whole database +# backup. +# +# This section assumes that all copies of the current controlfile have been +# lost, and that all initialization parameter files, datafiles and online logs +# are intact. +# +# Ensure you set your NLS_LANG environment variable. +# e.g. in unix (csh): +# > setenv NLS_LANG american_america.we8dec +# +# Start RMAN without the TARGET option, and use the following commands to +# restore and recover the database: + +SET DBID ; # use database id from RMAN output as + # explained in Section 2.1, + # not required if using recovery catalog +CONNECT TARGET ; +STARTUP NOMOUNT; +RUN +{ + # You need to allocate channels if not using recovery catalog. Media + # manager parameter string must be same as in Section 1. + ALLOCATE CHANNEL FOO TYPE SBT PARMS ''; + ALLOCATE CHANNEL FOO2 TYPE DISK; + + RESTORE CONTROLFILE FROM AUTOBACKUP; + ALTER DATABASE MOUNT; + RECOVER DATABASE; + ALTER DATABASE OPEN RESETLOGS; + + # You must take a new whole database backup after resetlogs (as + # in Section 2.1), since backups of previous incarnation are not easily + # usable. +} + + +# Section 5.4 - Block recovery +#----------------------------- +# Block recovery can be used to recover a corrupted block(s). It is not +# intended to recover complete datafile. +# Usually, the corruption is reported in alert logs, trace files or +# results of SQL commands +# +# For example, as a result of SQL command +# SQL> select * from emp; +# +#NAME +#------------------------------ +#ORA-01578: ORACLE data block corrupted (file # 7, block # 233) +#ORA-01578: ORACLE data block corrupted (file # 7, block # 235) +#ORA-01578: ORACLE data block corrupted (file # 4, block # 101) +#ORA-01110: data file 7: '/oracle/dbs/tbs_07.f' +#ORA-01110: data file 4: '/oracle/dbs/tbs_04.f' + +# Use the following BLOCKRECOVER command to recover the corrupted blocks +# listed above: +BLOCKRECOVER DATAFILE 7 BLOCK 233, 235 DATAFILE 4 BLOCK 101; + +# The BLOCKRECOVER command can also be used to repair all corrupted blocks +# listed in V$BACKUP_CORRUPTION and V$COPY_CORRUPTION. These views are +# populated whenever an RMAN process peforms a complete scan of a file for the +# purpose of backing it up, such as with the BACKUP or COPY command. Use the +# following command to repair all blocks listed in the V$xxx_CORRUPTION views: +# command: +BLOCKRECOVER CORRUPTION LIST; + +# Section 5.5 - Disaster recovery +#-------------------------------- +# A disaster recovery scenario assumes that you have lost everything. To +# perform recovery in this case, you would have to restore initialization +# parameters manually. Then use RMAN to restore and recover the database as +# described in this section. +# +# The commands below assume that all initialization parameter files are in +# place and the complete directory structure for datafiles is recreated. +# +# Ensure you set your NLS_LANG environment variable. +# e.g. in unix (csh): +# > setenv NLS_LANG american_america.we8dec +# +# Start RMAN without the TARGET option, and use the following commands to +# restore and recover the database: + +SET DBID ; # use database id from RMAN output as + # explained in Section 2.1, + # not required if using recovery catalog +CONNECT TARGET ; +STARTUP NOMOUNT; +RUN +{ + # You need to allocate channels if not using recovery catalog. Media + # manager parameter string must be same as in Section 1. + ALLOCATE CHANNEL FOO TYPE SBT PARMS ''; + ALLOCATE CHANNEL FOO2 TYPE DISK; + + # Optionally you can use SET NEWNAME and SWITCH commands as described in + # Section 5.2 to restore datafiles to a new location. + RESTORE CONTROLFILE FROM AUTOBACKUP; + ALTER DATABASE MOUNT; + RESTORE DATABASE; + RECOVER DATABASE; + ALTER DATABASE OPEN RESETLOGS; + + # You must take a new whole database backup after resetlogs (as + # in Section 2.1), since backups of previous incarnation are not easily + # usable. +} + + +# Section 5.6 - Database Point-in-time recovery +# --------------------------------------------- +# This scenario assumes that all initialization files and the current +# controlfile are in place and you want to recover to a point in time +# '2001-04-09:14:30:00'. +# +# Ensure you set your NLS_LANG environment variable. +# e.g. in unix (csh): +# > setenv NLS_LANG american_america.we8dec + +STARTUP MOUNT FORCE; +RUN +{ + SET UNTIL TIME "TO_DATE('2001-04-09:14:30:00','yyyy-dd-mm:hh24:mi:ss')"; + RESTORE DATABASE; + RECOVER DATABASE; + ALTER DATABASE OPEN RESETLOGS; + + # You must take a new whole database backup after resetlogs (as + # in Section 2.1), since backups of previous incarnation are not easily + # usable. +} + + +#-end of file- diff --git a/case3.rcv b/case3.rcv new file mode 100644 index 0000000..c9b62ae --- /dev/null +++ b/case3.rcv @@ -0,0 +1,261 @@ +# +# $Header: case3.rcv 26-apr-2001.12:18:39 banand Exp $ +# +# Copyright (c) 1995, 2001, Oracle Corporation. All rights reserved. +# +# NAME +# case3.rcv +# +# DESCRIPTION +# This case study outlines the basic steps to perform tablespace +# point-in-time recovery (TSPITR) using Recovery Manager. +# +# The examples in this case study assume that all backups are stored on +# disk. However if you have backups on tape and channels are configured as +# described in case2.rcv, Section 1, the same procedures will work. +# +# This case study assumes that +# - You want to recover tablespaces TBS1 and TBS2 to the point in time +# '2000-APR-01:07:05:30'. +# - TSPITR is performed on the same machine as the target database. +# - ORACLE_HOME is /oracle. +# - ORACLE_SID for the target database is PROD. +# - target database files and online logs are in $ORACLE_HOME/dbs/. +# - ORACLE_SID for the auxiliary instance is AUX. +# - all temporary files (except password file) for the auxiliary +# instance are created in $ORACLE_HOME/auxiliary. +# +# NOTES +# You should not run all of the commands in this file in a single RMAN +# session. Rather, the various sections in this file should be studied +# thoroughly before performing TSPITR. +# +# MODIFIED (MM/DD/YY) +# banand 04/17/01 - re-write case for tablespace point-in-time recovery +# banand 04/17/01 - Creation +# +# Organization: +# +# This case study is organized into the following sections: +# 1. TSPITR usage and restrictions +# 2. Resolving referential dependencies +# 3. Preparing for TSPITR - setup auxiliary instance +# 4. Performing TSPITR +# 5. Preparing the target database to use recovered files +# 6. Cleaning up the auxiliary instance and temporary files +# + +Section 1 - TSPITR usage and restrictions +----------------------------------------- + +Section 1.1 - When to do TSPITR +------------------------------- + TSPITR can be performed: + - to recover from an erroneous drop or truncate table operation + - to recover a table that has become logically corrupted + - to recover from a batch job or DML that has affected only a subset of the + database + +Section 1.2 - Restrictions of TSPITR +------------------------------------ + It should be noted that TSPITR: + - cannot recover a dropped tablespace + - cannot recover a tablespace that was dropped and recreated with same name + - will not recover optimizer statistics; statistics must be recalculated + after TSPITR + - cannot recover a tablespace containing any of the following object types: + - replicated master tables + - tables with varray columns + - tables with nested tables + - tables with external bfiles + - snapshot logs + - snapshot tables + - IOTs + - objects owned by SYS (including rollback segments) + + After TSPITR you should take a new backup of the recovered tablespace(s), + since it is not possible to recover using the pre-TSPITR backups. + +Section 1.3 - RMAN specific restrictions for TSPITR +--------------------------------------------------- + RMAN specific TSPITR restrictions are : + - cannot recover partitioned tables unless all partitions are contained + in the recovery set + - cannot recover tablespaces containing rollback segments + +Section 2. Resolving referential dependencies +----------------------------------------------------------------------------- + The main issue to consider when deciding whether or not to proceed with + TSPITR is the possibility of application-level inconsistencies between + tables in recovered and unrecovered tablespaces due to implicit rather than + explicit referential dependencies. You should understand these dependencies + and have means to resolve any possible inconsistencies before proceeding. + + Oracle provides the TS_PITR_CHECK view to assert that no referential + integrity constraints will be broken after TSPITR. If this view returns + rows when queried then the reason should be investigated and resolved. Only + when TS_PITR_VIEW returns no rows TSPITR will be able to proceed (since + this view is checked by imp/exp utilities called by RMAN during + TSPITR). All actions taken at this stage should be noted in order that + these relationship can be rebuilt after TSPITR is complete. + + You should check view TS_PITR_OBJECTS_TO_BE_DROPPED to see which objects + will be lost after TSPITR. If you want certain object listed by this view, + then TSPITR should not be performed. + + Run the following queries to prepare for performing TSPITR on TBS1 and TBS2 + to time '2000-APR-01:07:05:30': + + SELECT OWNER, NAME, TABLESPACE_NAME FROM SYS.TS_PITR_OBJECTS_TO_BE_DROPPED + WHERE TABLESPACE_NAME IN ('TBS1', 'TBS2') AND + CREATION_TIME > TO_DATE('2000-APR-01:07:05:30', + 'YYYY-MON-DD:HH24:MI:SS') + ORDER BY TABLESPACE_NAME, CREATION_TIME; + + SELECT * FROM SYS.TS_PITR_CHECK + WHERE (TS1_NAME IN ('TBS1', 'TBS2') AND + TS2_NAME NOT IN ('TBS1', 'TBS2')) OR + (TS1_NAME NOT IN ('TBS1', 'TBS2') AND + TS2_NAME IN ('TBS1', 'TBS2')); + +Section 3 - Preparing for TSPITR +----------------------------------------------------------------------------- + This section shows how to set up the auxiliary instance which will be used + by RMAN to perform TSPITR on the desired tablespaces. RMAN will connect + to this database using the AUXILIARY connect option. + +Section 3.1 - Setting up the auxiliary instance +----------------------------------------------- + +Section 3.1.1 - Preparing to connect to the auxiliary instance +-------------------------------------------------------------- + The following steps should be followed to connect to the auxiliary + instance: + + - create a password file for the auxiliary instance using the + orapwd utility: + + orapwd file=/oracle/dbs/orapwAUX password=auxpwd entries=100 + + - Add listener.ora and tnsnames.ora entries so that RMAN can connect to + the auxiliary database. + +Section 3.1.2 - Preparing the parameter file for the auxiliary instance +----------------------------------------------------------------------- + You can use the production instance parameter file as the basis for the + auxiliary instance. However certain parameters like db_block_buffers, + shared_pool_size, large_pool_size, enqueue_resources, etc which allocate + shared memory can probably be reduced, because the auxiliary instance + does not have the same memory requirements as the production instance. + + The following parameters must be set for the auxiliary instance: + + # db_name must be the same as in the production instance + db_name=PROD + + # control_files must be different than the production instance + control_files=/oracle/auxiliary/ctl.f + + # lock_name_space must be different than the production instance + lock_name_space=_PROD + + # db_file_name_convert and log_file_name_convert are used only in + # the parameter file of the auxiliary instance. They establish + # the rules that are used to convert the datafile and log file + # names from the production to the auxiliary database. Note that + # starting in Oracle9i, more than one pair of substitutions can + # be specified in both of these parameters, which allows more + # flexibility in converting file names. Use the RMAN SET NEWNAME + # command to convert any file names that cannot be converted with + # the xxx_file_name_convert parameters. + db_file_name_convert=('/dbs/', '/auxiliary/') + log_file_name_convert=('/dbs/', '/auxiliary/') + + # log_archive_dest_n and log_archive_format can be the same as the + # target instance + log_archive_dest_1='LOCATION=/oracle/log' + log_archive_format=r_%t_%s.arc + + It is important to note that ALL controlfiles, online logs, and datafiles + must have different names at the auxiliary instance than they have at the + production instance, otherwise RMAN may restore files to those locations, + and overwrite the production files. Use the control_files, + db_file_name_convert, and log_file_name_convert parameters to make sure + that the files at the auxiliary instance all have different names. + +Section 3.1.3 - Starting the auxiliary instance +----------------------------------------------- + You should start the auxiliary instance in nomount mode before performing + TSPITR. You can connect using SQLPLUS and start the auxiliary using the + following commands : + + CONNECT sys/syspwd@auxiliary_db_connect_string as sysdba; + STARTUP PFILE=/oracle/auxiliary/initAUX.ora NOMOUNT; + +Section 4 - Performing TSPITR using RMAN +------------------------------------------------------------------------------ + The auxiliary database must be in nomount state and the target instance + must be mounted or open state to perform TSPITR. The steps in RMAN TSPITR + are: + - connect to auxiliary instance + - connect to target database + - connect to recovery catalog (optional) + - recover tablespace TBS1 and TBS2 + + CONNECT AUXILIARY + CONNECT TARGET + CONNECT CATALOG + + RUN + { + # optionally, use SET NEWNAME here for file name translation + # SET NEWNAME FOR DATAFILE 1 TO '/oracle/auxiliary/file1.f' + # SET NEWNAME FOR DATAFILE 2 TO '/oracle/auxiliary/file2.f' + + RECOVER TABLESPACE TBS1, TBS2 UNTIL TIME + "TO_DATE('2000-APR-01:07:05:30', 'YYYY-MON-DD:HH24:MI:SS')"; + } + + All the recovered tablespaces will be OFFLINE in target database on + successful execution of RECOVER command. If the RECOVER command fails, + then after resolving the error you can re-execute the commands. + + If export fails due to lack of temporary space, you can create a temporary + tablespace. Search for tspitr_7 in /oracle/rdbms/admin/recover.bsq and + see comments to create temporary tablespace. + + If import fails because of import tables not existing, you can run + CATEXP.SQL on target database to create import schema. + +Section 5 - Preparing the target database to use the recovered tablespaces +-------------------------------------------------------------------------- + + After the RECOVER command in Section 4 runs successfully, you should backup + the recovered tablespaces, because after they are brought online, they can + no longer be recovered using backups taken prior to the TSPITR. + + CONNECT TARGET sys/syspwd@target_db_connect_string; + BACKUP TABLESPACE TBS1, TBS2; + SQL 'ALTER TABLESPACE TBS1, TBS2 ONLINE'; + +Section 6 - Cleanup auxiliary instance +-------------------------------------- + The auxiliary instance is not usable after successful completion of + TSPITR. This instance must be cleaned using following steps: + + - Connect to the auxiliary instance as explained in Section 3.1.3 + - mount the database using 'ALTER DATABASE MOUNT CLONE DATABASE' + - Delete the temporary files restored by RMAN when performing TSPITR. + You can use following queries to list them: + + SELECT d.name FROM v$datafile d, v$tablespace t + WHERE d.ts#=t.ts# AND status in ('SYSTEM', 'ONLINE') AND + t.name not in ('TBS1', 'TBS2'); + SELECT member FROM v$logfile; + SELECT name FROM v$controlfile; + + - Shutdown the auxiliary instance and delete the above files. + All these files in this case should be in the /oracle/auxiliary directory. + - You can also delete initAUX.ora and orapwAUX + +#-end of file- diff --git a/case4.rcv b/case4.rcv new file mode 100644 index 0000000..830cd88 --- /dev/null +++ b/case4.rcv @@ -0,0 +1,157 @@ +# +# $Header: case4.rcv 13-sep-2000.13:30:16 molagapp Exp $ +# +# Copyright (c) 1995, 2000 Oracle Corporation. All rights reserved. +# +# NAME +# case4.rcv +# +# DESCRIPTION +# Example of how to duplicate a database using Recovery Manager +# +# NOTES +# +# MODIFIED (MM/DD/YY) +# banand 04/23/01 - rename case5 to case4 +# molagapp 09/13/00 - fix for 8.2 +# mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +# rlu 02/18/99 - fix typo +# fsanchez 11/06/98 - Creation +# +# +# The following script creates a duplicate database that you can use +# for testing purposes. This scenario assumes: +# - You wish to duplicate the target database to a new database +# named newdb. +# - The target database is mounted or open. +# - The auxiliary instance is started in NOMOUNT state. +# - The INIT.ORA file of the duplicate database must contain: +# - DB_NAME = newdb +# - CONTROL_FILES = ... (see script) +# - The INIT.ORA file of the duplicate database can also contain: +# - DB_FILE_NAME_CONVERT = ... (see script) +# - LOG_FILE_NAME_CONVERT = ... (see script) +# - Any other parameters required by the auxiliary database. +# +# The following script creates a duplicate database using the most recent +# backup. After the DUPLICATE command has finished succesfully, +# you can register the duplicate database (if using a recovery catalog) +# and perform backups as with any other database. +# +# Make sure to set your NLS_LANG and NLS_DATE_FORMAT environment variables. +# You can set these values to whatever you wish. The UNIX example +# below keeps the date format to the standard date format used +# for recovery: +# +# %> setenv NLS_LANG AMERICAN +# %> setenv NLS_DATE_FORMAT 'YYYY-MM-DD:hh24:mi:ss' +# +# +# Connect to RMAN and run the script by executing the following at +# the O/S command line +# (a single-line command is shown here on multiple lines for the +# sake of clarity): +# rman +# TARGET +# @ +# CATALOG +# /@ +# AUXILIARY +# /@ +# @case4.rcv +# LOG case4.log +# +# For more information about the commands in this script, see the "Recovery +# Manager Command Syntax" in the Oracle8i Backup and Recovery Guide. +# For a description of the procedures for creating a duplicate database, +# see the chapter "Creating a Duplicate Database." + +RUN +{ + +# The target database can be mounted with the following command +# if not already opened or mounted: + +# STARTUP MOUNT ; + +# By default the DUPLICATE command will try to create the duplicate database +# using the most recent backup of the target database. If you wish to +# recover the duplicate database to a non-current time issue a SET UNTIL +# command to speceify the time. + +# SET UNTIL TIME '1998-10-31:14:30:00'; + +# There are several ways to convert the filenames for the duplicate +# database. For a complete account, see the chapter "Creating a +# Duplicate Database" in the Oracle8i Backup and Recovery Guide. Note +# the following guidelines: + +# (1) If the duplicate database is in the same host as the target, +# and the target datafiles cannot be transformed with +# DB_FILE_NAME_CONVERT rule from the INIT.ORA file of the +# duplicate database, then issue a SET NEWNAME command for each +# datafile that cannot be converted automatically. +# +# (2) If you are connected to a recovery catalog database and have issued +# SET AUXNAME commands for some datafiles, the DUPLICATE command +# will use the AUXNAME value. Disable the use of the AUXNAME +# with the command: SET AUXNAME FOR DATAFILE ... TO NULL; +# +# (3) When the duplicate database is in a different host from the +# target database, the same disk structure is present at the new +# host, and you want to keep the same datafile names, then use +# the NOFILENAMECHECK clause + +# SET NEWNAME FOR DATAFILE 1 TO '?/dbs/newdb_datafile1.dbf'; +# SET NEWNAME FOR DATAFILE 2 TO '?/dbs/newdb_datafile2.dbf'; +# ... +# SET NEWNAME FOR DATAFILE 10 TO '?/dbs/newdb_datafile10.dbf'; +# ... + +# You must allocate at least one auxiliary channel needs before issuing +# the DUPLICATE command. The channel type (DISK or SBT) must match +# the media where the backups of the target database are stored. If you +# allocate TYPE DISK, then the more channels that are allocated, the +# faster the duplicate process will be. For other types the number of +# channels should be limited to the actual number of devices available +# for the operation: + + ALLOCATE AUXILIARY CHANNEL ch1 TYPE DISK; +# ALLOCATE AUXILIARY CHANNEL ch2 TYPE SBT; + +# newdb is the name of the auxiliary database as specified in the +# INIT.ORA parameter DB_NAME: + + DUPLICATE TARGET DATABASE TO newdb; + +# The LOGFILE clause is needed if the online logs cannot be +# automatically generated from the target datafile names after +# applying the LOG_FILE_NAME_CONVERT parameter of the +# auxiliary database. +# for example, for two groups each with two members of 512K bytes: + +# LOGFILE +# GROUP 1 ('?/dbs/new_g1_l1.dbf', +# '?/dbs/new_g1_l2.dbf') SIZE 512K, +# GROUP 2 ('?/dbs/new_g2_l1.dbf', +# '?/dbs/new_g2_l2.dbf') SIZE 512K + +# If restoring to a host with the same structure as the target host, use the +# NOFILENAMECHECK clause: + +# NOFILENAMECHECK + +# Note that read-only datafiles are duplicated by default. If this is not +# desired, use the SKIP READONLY clause: + +# SKIP READONLY + + ; + +# release the auxiliary channel + + RELEASE CHANNEL ch1; +# RELEASE CHANNEL ch2; + +} + diff --git a/cbdem1.cob b/cbdem1.cob new file mode 100644 index 0000000..4e58885 --- /dev/null +++ b/cbdem1.cob @@ -0,0 +1,481 @@ + * + * $Header: cbdem1.cob 14-jul-99.14:30:27 mjaeger Exp $ + * + * Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. + * + * NAME + * cbdem1.cob - Cobol demo program # 1 + * MODIFIED (MM/DD/YY) + * mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + * plocke 11/14/95 - to update for v7.3 + * dchatter 07/20/95 - merge changes from branch 1.1.720.1 + * dchatter 04/14/95 - fix test to work on sun + * sjain 03/16/92 - Creation + * --------------------------------------------------------- + * CBDEM1 IS A SIMPLE EXAMPLE PROGRAM WHICH ADDS + * NEW EMPLOYEE ROWS TO THE PERSONNEL DATA BASE. CHECKING + * IS DONE TO INSURE THE INTEGRITY OF THE DATA BASE. + * THE EMPLOYEE NUMBERS ARE AUTOMATICALLY SELECTED USING + * THE CURRENT MAXIMUM EMPLOYEE NUMBER AS THE START. + * IF ANY EMPLOYEE NUMBER IS A DUPLICATE, IT IS SKIPPED. + * THE PROGRAM QUERIES THE USER FOR DATA AS FOLLOWS: + * + * Enter employee name : + * Enter employee job : + * Enter employee salary: + * Enter employee dept : + * + * TO EXIT THE PROGRAM, ENTER A CARRIAGE RETURN AT THE + * PROMPT FOR EMPLOYEE NAME. + * + * IF THE ROW IS SUCCESSFULLY INSERTED, THE FOLLOWING + * IS PRINTED: + * + * ENAME added to DNAME department as employee # NNNNN + * + * THE MAXIMUM LENGTHS OF THE 'ENAME', 'JOB', AND 'DNAME' + * COLUMNS WILL BE DETERMINED BY THE ODESCR CALL. + * + *---------------------------------------------------------- + + + IDENTIFICATION DIVISION. + PROGRAM-ID. CBDEM1. + ENVIRONMENT DIVISION. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 LDA. + 02 LDA-V2RC PIC S9(4) COMP. + 02 FILLER PIC X(10). + 02 LDA-RC PIC S9(4) COMP. + 02 FILLER PIC X(50). + 01 HDA PIC X(512). + + 01 CURSOR-1. + 02 C-V2RC PIC S9(4) COMP. + 02 C-TYPE PIC S9(4) COMP. + 02 C-ROWS PIC S9(9) COMP. + 02 C-OFFS PIC S9(4) COMP. + 02 C-FNC PIC S9(4) COMP. + 02 C-RC PIC S9(4) COMP. + 02 FILLER PIC X(50). + 01 CURSOR-2. + 02 C-V2RC PIC S9(4) COMP. + 02 C-TYPE PIC S9(4) COMP. + 02 C-ROWS PIC S9(9) COMP. + 02 C-OFFS PIC S9(4) COMP. + 02 C-FNC PIC S9(4) COMP. + 02 C-RC PIC S9(4) COMP. + 02 FILLER PIC X(50). + + 77 USER-ID PIC X(5) VALUE "SCOTT". + 77 USER-ID-L PIC S9(9) VALUE 5 COMP. + 77 PSW PIC X(5) VALUE "tiger". + 77 PSW-L PIC S9(9) VALUE 5 COMP. + 77 CONN PIC S9(9) VALUE 0 COMP. + 77 CONN-L PIC S9(9) VALUE 0 COMP. + 77 CONN-MODE PIC S9(9) VALUE 0 COMP. + + 77 SQL-SEL PIC X(38) VALUE + "SELECT DNAME FROM DEPT WHERE DEPTNO=:1". + 77 SQL-SEL-L PIC S9(9) VALUE 38 COMP. + + 77 SQL-INS PIC X(150) VALUE + "INSERT INTO EMP (EMPNO,ENAME,JOB,SAL,DEPTNO) + - " VALUES (:EMPNO,:ENAME,:JOB,:SAL,:DEPTNO)". + 77 SQL-INS-L PIC S9(9) VALUE 150 COMP. + + 77 SQL-SELMAX PIC X(33) VALUE + "SELECT NVL(MAX(EMPNO),0) FROM EMP". + 77 SQL-SELMAX-L PIC S9(9) VALUE 33 COMP. + + 77 SQL-SELEMP PIC X(26) VALUE + "SELECT ENAME,JOB FROM EMP". + 77 SQL-SELEMP-L PIC S9(9) VALUE 26 COMP. + + 77 EMPNO PIC S9(9) COMP. + 77 EMPNO-D PIC ZZZZ9. + 77 ENAME PIC X(12). + 77 JOB PIC X(12). + 77 SAL PIC X(10). + 77 DEPTNO PIC X(10). + 77 FMT PIC X(6). + 77 CBUF PIC X(10). + 77 DNAME PIC X(15). + 77 ENAME-L PIC S9(9) VALUE 12 COMP. + 77 ENAME-SIZE PIC S9(4) COMP. + 77 JOB-L PIC S9(9) VALUE 12 COMP. + 77 JOB-SIZE PIC S9(4) COMP. + 77 SAL-L PIC S9(9) VALUE 10 COMP. + 77 DEPTNO-L PIC S9(9) VALUE 10 COMP. + 77 DNAME-L PIC S9(9) VALUE 15 COMP. + 77 DNAME-SIZE PIC S9(4) COMP. + + 77 EMPNO-N PIC X(6) VALUE ":EMPNO". + 77 ENAME-N PIC X(6) VALUE ":ENAME". + 77 JOB-N PIC X(4) VALUE ":JOB". + 77 SAL-N PIC X(4) VALUE ":SAL". + 77 DEPTNO-N PIC X(7) VALUE ":DEPTNO". + + 77 EMPNO-N-L PIC S9(9) VALUE 6 COMP. + 77 ENAME-N-L PIC S9(9) VALUE 6 COMP. + 77 JOB-N-L PIC S9(9) VALUE 4 COMP. + 77 SAL-N-L PIC S9(9) VALUE 4 COMP. + 77 DEPTNO-N-L PIC S9(9) VALUE 7 COMP. + + 77 INTEGER PIC S9(9) COMP VALUE 3. + 77 ASC PIC S9(9) COMP VALUE 1. + 77 ZERO-A PIC S9(9) COMP VALUE 0. + 77 ZERO-B PIC S9(4) COMP VALUE 0. + 77 ONE PIC S9(9) COMP VALUE 1. + 77 TWO PIC S9(9) COMP VALUE 2. + 77 FOUR PIC S9(9) COMP VALUE 4. + 77 SIX PIC S9(9) COMP VALUE 6. + 77 EIGHT PIC S9(9) COMP VALUE 8. + 77 ERR-RC PIC S9(4) COMP. + 77 ERR-FNC PIC S9(4) COMP. + 77 ERR-RC-D PIC ZZZ9. + 77 ERR-FNC-D PIC ZZ9. + 77 MSGBUF PIC X(160). + 77 MSGBUF-L PIC S9(9) COMP VALUE 160. + + 77 ASK-EMP PIC X(25) VALUE + "Enter employee name: ". + 77 ASK-JOB PIC X(25) VALUE + "Enter employee job: ". + 77 ASK-SAL PIC X(25) VALUE + "Enter employee salary: ". + 77 ASK-DEPTNO PIC X(25) VALUE + "Enter employee dept: ". + + PROCEDURE DIVISION. + BEGIN. + + *---------------------------------------------------------- + * CONNECT TO ORACLE IN NON-BLOCKING MODE. + * HDA MUST BE INITIALIZED TO ALL ZEROS BEFORE CALL TO OLOG. + *---------------------------------------------------------- + + MOVE LOW-VALUES TO HDA. + + CALL "OLOG" USING LDA, HDA, USER-ID, USER-ID-L, + PSW, PSW-L, CONN, CONN-L, CONN-MODE. + + IF LDA-RC NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-STOP. + + DISPLAY "Connected to ORACLE as user ", USER-ID. + + *---------------------------------------------------------- + * OPEN THE CURSORS. + *---------------------------------------------------------- + + CALL "OOPEN" USING CURSOR-1, LDA. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOF. + + CALL "OOPEN" USING CURSOR-2, LDA. + IF C-RC IN CURSOR-2 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOF. + + *---------------------------------------------------------- + * DISABLE AUTO-COMMIT. + * NOTE: THE DEFAULT IS OFF, SO THIS COULD BE OMITTED. + *---------------------------------------------------------- + + CALL "OCOF" USING LDA. + IF LDA-RC NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * RETRIEVE THE CURRENT MAXIMUM EMPLOYEE NUMBER. + *---------------------------------------------------------- + + CALL "OPARSE" USING CURSOR-1, SQL-SELMAX, SQL-SELMAX-L, + ZERO-A, TWO. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "ODEFIN" USING CURSOR-1, ONE, EMPNO, FOUR, + INTEGER, ZERO-A, ZERO-B, FMT, ZERO-A, ZERO-A, + ZERO-B, ZERO-B. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "OEXEC" USING CURSOR-1. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "OFETCH" USING CURSOR-1. + IF C-RC IN CURSOR-1 NOT = 0 + IF C-RC IN CURSOR-1 NOT = 1403 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE + ELSE + MOVE 10 TO EMPNO. + + *---------------------------------------------------------- + * DETERMINE THE MAX LENGTH OF THE EMPLOYEE NAME AND + * JOB TITLE. PARSE THE SQL STATEMENT - + * IT WILL NOT BE EXECUTED. + * DESCRIBE THE TWO FIELDS SPECIFIED IN THE SQL STATEMENT. + *---------------------------------------------------------- + + CALL "OPARSE" USING CURSOR-1, SQL-SELEMP, SQL-SELEMP-L, + ZERO-A, TWO. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "ODESCR" USING CURSOR-1, ONE, ENAME-SIZE, ZERO-B, + CBUF, ZERO-A, ZERO-A, ZERO-B, ZERO-B, ZERO-B. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "ODESCR" USING CURSOR-1, TWO, JOB-SIZE, ZERO-B, + CBUF, ZERO-A, ZERO-A, ZERO-B, ZERO-B, ZERO-B. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + IF ENAME-SIZE > ENAME-L + DISPLAY "ENAME too large for buffer." + GO TO EXIT-CLOSE. + IF JOB-SIZE > JOB-L + DISPLAY "JOB too large for buffer." + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * PARSE THE INSERT AND SELECT STATEMENTS. + *---------------------------------------------------------- + + CALL "OPARSE" USING CURSOR-1, SQL-INS, SQL-INS-L, + ZERO-A, TWO. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "OPARSE" USING CURSOR-2, SQL-SEL, SQL-SEL-L, + ZERO-A, TWO. + IF C-RC IN CURSOR-2 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * BIND ALL SQL SUBSTITUTION VARIABLES. + *---------------------------------------------------------- + + CALL "OBNDRV" USING CURSOR-1, EMPNO-N, EMPNO-N-L, + EMPNO, FOUR, INTEGER, ZERO-A. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "OBNDRV" USING CURSOR-1, ENAME-N, ENAME-N-L, + ENAME, ENAME-L, ASC. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "OBNDRV" USING CURSOR-1, JOB-N, JOB-N-L, + JOB, JOB-L, ASC. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "OBNDRV" USING CURSOR-1, SAL-N, SAL-N-L, SAL, + SAL-L, ASC. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "OBNDRV" USING CURSOR-1, DEPTNO-N, DEPTNO-N-L, + DEPTNO, DEPTNO-L, ASC. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * BIND THE DEPTNO SUBSTITUTION VAR IN THE SELECT STATEMENT. + *---------------------------------------------------------- + + CALL "OBNDRN" USING CURSOR-2, ONE, DEPTNO, + DEPTNO-L, ASC. + IF C-RC IN CURSOR-2 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * DESCRIBE THE 'DNAME' COLUMN - ONLY THE LENGTH. + *---------------------------------------------------------- + + CALL "ODSC" USING CURSOR-2, ONE, DNAME-SIZE. + IF C-RC IN CURSOR-2 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + IF DNAME-SIZE > DNAME-L + DISPLAY "DNAME is to large for buffer." + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * DEFINE THE BUFFER TO RECEIVE 'DNAME'. + *---------------------------------------------------------- + + CALL "ODEFIN" USING CURSOR-2, ONE, DNAME, + DNAME-L, ASC. + IF C-RC IN CURSOR-2 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * ASK THE USER FOR EMPLOYEE NAME, JOB, SAL, AND DEPTNO. + *---------------------------------------------------------- + + NEXT-EMP. + + DISPLAY ASK-EMP WITH NO ADVANCING. + ACCEPT ENAME. + IF ENAME = " " + GO TO EXIT-CLOSE. + + DISPLAY ASK-JOB WITH NO ADVANCING. + ACCEPT JOB. + + DISPLAY ASK-SAL WITH NO ADVANCING. + ACCEPT SAL. + + ASK-DPT. + DISPLAY ASK-DEPTNO WITH NO ADVANCING. + ACCEPT DEPTNO. + + *---------------------------------------------------------- + * CHECK FOR A VALID DEPARTMENT NUMBER BY EXECUTING. + * THE SELECT STATEMENT. + *---------------------------------------------------------- + + CALL "OEXEC" USING CURSOR-2. + IF C-RC IN CURSOR-2 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * FETCH THE ROWS - DEPTNO IS A PRIMARY KEY SO A MAX. + * OF 1 ROW WILL BE FETCHED. + * IF THE CURSOR RETURN CODE IS 1403 THEN + * NO SUCH DEPARTMENT EXISTS. + *---------------------------------------------------------- + + MOVE SPACES TO DNAME. + + CALL "OFETCH" USING CURSOR-2. + IF C-RC IN CURSOR-2 = 0 THEN GO TO ADD-ROW. + IF C-RC IN CURSOR-2 = 1403 + DISPLAY "No such department." + GO TO ASK-DPT. + + *---------------------------------------------------------- + * INCREMENT EMPNO BY 10. + * EXECUTE THE INSERT STATEMENT. + *---------------------------------------------------------- + + ADD-ROW. + + ADD 10 TO EMPNO. + IF EMPNO > 9999 + MOVE EMPNO TO EMPNO-D + DISPLAY "Employee number " EMPNO-D " too large." + GO TO EXIT-CLOSE. + + CALL "OEXEC" USING CURSOR-1. + IF C-RC IN CURSOR-1 = 0 THEN GO TO PRINT-RESULT. + + *---------------------------------------------------------- + * IF THE RETURN CODE IS 1 (DUPLICATE VALUE IN INDEX), + * THEN GENERATE THE NEXT POSSIBLE EMPLOYEE NUMBER. + *---------------------------------------------------------- + + IF C-RC IN CURSOR-1 = 1 + ADD 10 TO EMPNO + GO TO ADD-ROW + ELSE + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + PRINT-RESULT. + + MOVE EMPNO TO EMPNO-D. + DISPLAY ENAME " added to the " DNAME + " department as employee number " EMPNO-D. + + *---------------------------------------------------------- + * THE ROW HAS BEEN ADDED - COMMIT THIS TRANSACTION. + *---------------------------------------------------------- + + CALL "OCOM" USING LDA. + IF LDA-RC NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + GO TO NEXT-EMP. + + *---------------------------------------------------------- + * CLOSE CURSORS AND LOG OFF. + *---------------------------------------------------------- + + EXIT-CLOSE. + + CALL "OCLOSE" USING CURSOR-1. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR. + + CALL "OCLOSE" USING CURSOR-2. + IF C-RC IN CURSOR-2 NOT = 0 + PERFORM ORA-ERROR. + + EXIT-LOGOF. + + CALL "OLOGOF" USING LDA. + IF LDA-RC NOT = 0 + PERFORM ORA-ERROR. + + EXIT-STOP. + + DISPLAY "End of the OCIDEMO1 program." + STOP RUN. + + *---------------------------------------------------------- + * DISPLAY ORACLE ERROR NOTICE. + *---------------------------------------------------------- + + ORA-ERROR. + + IF LDA-RC NOT = 0 + DISPLAY "OLOGON error" + MOVE LDA-RC TO ERR-RC + MOVE "0" TO ERR-FNC + ELSE IF C-RC IN CURSOR-1 NOT = 0 + MOVE C-RC IN CURSOR-1 TO ERR-RC + MOVE C-FNC IN CURSOR-1 TO ERR-FNC + ELSE + MOVE C-RC IN CURSOR-2 TO ERR-RC + MOVE C-FNC IN CURSOR-2 TO ERR-FNC. + + DISPLAY "ORACLE error" WITH NO ADVANCING. + IF ERR-FNC NOT = 0 + MOVE ERR-FNC TO ERR-FNC-D + DISPLAY " processing OCI function" + ERR-FNC-D "." + ELSE + DISPLAY ".". + + MOVE " " TO MSGBUF. + CALL "OERHMS" USING LDA, ERR-RC, MSGBUF, MSGBUF-L. + DISPLAY MSGBUF. diff --git a/cbdem2.cob b/cbdem2.cob new file mode 100644 index 0000000..d99bed0 --- /dev/null +++ b/cbdem2.cob @@ -0,0 +1,446 @@ + * + * $Header: cbdem2.cob 14-jul-99.14:31:06 mjaeger Exp $ + * + * Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. + * + * NAME + * cbdem2.cob - Cobol demo program #2 + * MODIFIED (MM/DD/YY) + * mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + * plocke 11/14/95 - to update for v7.3 + * dchatter 07/20/95 - merge changes from branch 1.1.720.1 + * dchatter 04/14/95 - fix test to work on sun + * sjain 03/16/92 - Creation + * + * The program CBDEM2 accepts SQL statements from the + * user at run time and processes them. + + * If the statement was a Data Definition Language (DDL), + * Data Control Language (DCL), or Data Manipulation + * Language (DML) statement, it is parsed and executed, + * and the next statement is retrieved. (Note that + * performing the execute step for a DDL or DCL statement + * is not necessary, but it does no harm, and simplifies + * the program logic.) + + * If the statement was a query, the program describes + * the select list, and defines output variables of the + * appropriate type and size, depending on the internal + * datatype of the select-list item. + + * Then, each row of the query is fetched, and the results + * are displayed. + + * To keep the size of this example program to a + * reasonable limit for this book, the following + * restrictions are present: + + * (1) The SQL statement can contain only 25 elements (words + * and punctuation), and must be entered on a single line. + * There is no terminating ';'. + * (2) A maximum of 8 bind (input) variables is permitted. + * Additional input variables are not bound, which will + * cause an error at execute time. Input values must be + * enterable as character strings + * (numeric or alphanumeric). + * Placeholders for bind variables are :bv, + * as for OBNDRV. + * (3) A maximum of 8 select-list items per table are + * described and defined. Additional columns are + * not defined, which will cause unpredictable behavior + * at fetch time. + * (4) Not all internal datatypes are handled for queries. + * Selecting a RAW or LONG column could cause problems. + + + IDENTIFICATION DIVISION. + PROGRAM-ID. CBDEM2. + ENVIRONMENT DIVISION. + DATA DIVISION. + WORKING-STORAGE SECTION. + + * Logon, cursor, and host data areas. + 01 LDA. + 02 LDA-V2RC PIC S9(4) COMP. + 02 FILLER PIC X(10). + 02 LDA-RC PIC S9(4) COMP. + 02 FILLER PIC X(50). + 01 CDA. + 02 C-V2RC PIC S9(4) COMP. + 02 C-TYPE PIC S9(4) COMP. + 02 C-ROWS PIC S9(9) COMP. + 02 C-OFFS PIC S9(4) COMP. + 02 C-FNC PIC S9(4) COMP. + 02 C-RC PIC S9(4) COMP. + 02 FILLER PIC X(50). + 01 HDA PIC X(512). + + * Error message variables for the OERHMS routine. + 01 MSGBUF PIC X(256). + 01 MSGBUF-L PIC S9(9) VALUE 256 COMP. + 01 ERR-FNC-D PIC ZZZ. + + * Connect info. Link the program single-task, or + * modify to use a SQL*Net connect string appropriate + * to your site. + 01 USER-ID PIC X(5) VALUE "SCOTT". + 01 USER-ID-L PIC S9(9) VALUE 5 COMP. + 01 PSW PIC X(5) VALUE "TIGER". + 01 PSW-L PIC S9(9) VALUE 5 COMP. + 01 CONN PIC S9(9) VALUE 0 COMP. + 01 CONN-L PIC S9(9) VALUE 0 COMP. + 01 CONN-MODE PIC S9(9) VALUE 0 COMP. + + * Parameters for OPARSE. + 01 SQL-STMT PIC X(132). + 01 SQLL PIC S9(9) COMP. + 01 DEF-MODE PIC S9(9) VALUE 1 COMP. + 01 NO-DEF-MODE PIC S9(9) VALUE 0 COMP. + 01 V7-FLG PIC S9(9) VALUE 2 COMP. + + * Parameters for OBNDRV. + 01 BVNX. + 03 BV-NAME OCCURS 25 TIMES. + 05 BV-NAMEX OCCURS 10 TIMES PIC X. + 01 BVVX. + 03 BV-VAL OCCURS 10 TIMES PIC X(10). + 01 BV-VAL-L PIC S9(9) VALUE 10 COMP. + 01 N-BV PIC S9(9) COMP. + + * Parameters for ODESCR. Note: some are two bytes (S9(4)) + * some are four bytes (S9(9)). + 01 DBSIZEX. + 03 DBSIZE OCCURS 8 TIMES PIC S9(9) COMP. + 01 DBTYPEX. + 03 DBTYPE OCCURS 8 TIMES PIC S9(4) COMP. + 01 NAMEX. + 03 DBNAME OCCURS 8 TIMES PIC X(10). + 01 NAME-LX. + 03 NAME-L OCCURS 8 TIMES PIC S9(9) COMP. + 01 DSIZEX. + 03 DSIZE OCCURS 8 TIMES PIC S9(9) COMP. + 01 PRECX. + 03 PREC OCCURS 8 TIMES PIC S9(4) COMP. + 01 SCALEX. + 03 SCALE OCCURS 8 TIMES PIC S9(4) COMP. + 01 NULL-OKX. + 03 NULL-OK OCCURS 8 TIMES PIC S9(4) COMP. + + * Parameters for ODEFIN. + 01 OV-CHARX. + 03 OV-CHAR OCCURS 8 TIMES PIC X(10). + 01 OV-NUMX. + 03 OV-NUM OCCURS 8 TIMES + PIC S99999V99 COMP-3. + 01 INDPX. + 03 INDP OCCURS 8 TIMES PIC S9(4) COMP. + 01 N-OV PIC S9(9) COMP. + 01 N-ROWS PIC S9(9) COMP. + 01 N-ROWS-D PIC ZZZ9 DISPLAY. + 01 OV-CHAR-L PIC S9(9) VALUE 10 COMP. + 01 SEVEN PIC S9(9) VALUE 7 COMP. + 01 PACKED-DEC-L PIC S9(9) VALUE 4 COMP. + 01 PACKED-DEC-T PIC S9(9) VALUE 7 COMP. + 01 NUM-DISP PIC ZZZZZ.ZZ. + 01 FMT PIC X(6) VALUE "08.+02". + 01 FMT-L PIC S9(9) VALUE 6 COMP. + 01 FMT-NONE PIC X(6). + + * Miscellaneous parameters. + 01 ZERO-A PIC S9(9) VALUE 0 COMP. + 01 ZERO-B PIC S9(9) VALUE 0 COMP. + 01 ZERO-C PIC S9(4) VALUE 0 COMP. + 01 ONE PIC S9(9) VALUE 1 COMP. + 01 TWO PIC S9(9) VALUE 2 COMP. + 01 FOUR PIC S9(9) VALUE 4 COMP. + 01 INDX PIC S9(9) COMP. + 01 NAME-D8 PIC X(8). + 01 NAME-D10 PIC X(10). + 01 VARCHAR2-T PIC S9(9) VALUE 1 COMP. + 01 NUMBER-T PIC S9(9) VALUE 2 COMP. + 01 INTEGER-T PIC S9(9) VALUE 3 COMP. + 01 DATE-T PIC S9(9) VALUE 12 COMP. + 01 CHAR-T PIC S9(9) VALUE 96 COMP. + + + + PROCEDURE DIVISION. + BEGIN. + + * Connect to ORACLE in non-blocking mode. + * HDA must be initialized to all zeros before call to OLOG. + + MOVE LOW-VALUES TO HDA. + + CALL "OLOG" USING LDA, HDA, USER-ID, USER-ID-L, + PSW, PSW-L, CONN, CONN-L, CONN-MODE. + + * Check for error, perform error routine if required. + IF LDA-RC NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-STOP. + + DISPLAY "Logged on to ORACLE as user " USER-ID ".". + DISPLAY "Type EXIT at SQL prompt to quit." + + * Open a cursor. Only the first two parameters are + * used, the remainder (for V2 compatibility) are ignored. + CALL "OOPEN" USING CDA, LDA, USER-ID, ZERO-A, + ZERO-A, USER-ID, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + * Process each SQL statement. + STMT-LOOP. + PERFORM DO-SQL-STMT. + GO TO STMT-LOOP. + + EXIT-CLOSE. + CALL "OCLOSE" USING CDA. + EXIT-LOGOFF. + CALL "OLOGOF" USING LDA. + EXIT-STOP. + STOP RUN. + + * Perform paragraphs. + + DO-SQL-STMT. + MOVE " " TO SQL-STMT. + DISPLAY " ". + DISPLAY "SQL > " NO ADVANCING. + ACCEPT SQL-STMT. + * Get first word of statement. + UNSTRING SQL-STMT DELIMITED BY ALL " " + INTO BV-NAME(1). + IF (BV-NAME(1) = "exit" OR BV-NAME(1) = "EXIT") + GO TO EXIT-CLOSE. + MOVE 132 TO SQLL. + * Use non-deferred parse, to catch syntax errors + * right after the parse. + CALL "OPARSE" USING CDA, SQL-STMT, SQLL, + NO-DEF-MODE, V7-FLG. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO DO-SQL-STMT. + + PERFORM BIND-VARS. + DISPLAY " ". + MOVE N-BV TO ERR-FNC-D. + + DISPLAY "There were" ERR-FNC-D + " bind variables.". + + * Execute the statement. + CALL "OEXN" USING CDA, ONE, ZERO-B. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO DO-SQL-STMT. + + * Describe the SQL statement, and define output + * variables if it is a query. Limit output variables + * to eight. + PERFORM DESCRIBE-DEFINE THRU DESCRIBE-DEFINE-EXIT. + + SUBTRACT 1 FROM N-OV. + IF (N-OV > 0) + MOVE N-OV TO ERR-FNC-D + DISPLAY "There were" ERR-FNC-D + " define variables." + DISPLAY " " + PERFORM VARYING INDX FROM 1 BY 1 UNTIL INDX > N-OV + IF (DBTYPE(INDX) NOT = 2) + MOVE DBNAME(INDX) TO NAME-D10 + DISPLAY NAME-D10 NO ADVANCING + ELSE + MOVE DBNAME(INDX) TO NAME-D8 + DISPLAY NAME-D8 NO ADVANCING + END-IF + DISPLAY " " NO ADVANCING + END-PERFORM + DISPLAY " " + PERFORM VARYING INDX FROM 1 BY 1 UNTIL INDX > N-OV + DISPLAY "--------" NO ADVANCING + IF DBTYPE(INDX) NOT = 2 + DISPLAY "--" NO ADVANCING + END-IF + DISPLAY " " NO ADVANCING + END-PERFORM + DISPLAY " " + END-IF. + + * If the statement was a query, fetch the rows and + * display them. + IF (C-TYPE IN CDA = 4) + PERFORM FETCHN THRU FETCHN-EXIT + MOVE N-ROWS TO N-ROWS-D + DISPLAY " " + DISPLAY N-ROWS-D " rows returned.". + * End of DO-SQL-STMT. + + BIND-VARS. + MOVE 0 TO N-BV. + PERFORM VARYING INDX FROM 1 BY 1 UNTIL INDX > 25 + MOVE " " TO BV-NAME(INDX) + END-PERFORM. + UNSTRING SQL-STMT + DELIMITED BY "(" OR "," OR ";" OR "=" + OR ")" OR ALL " " + INTO BV-NAME(1) + BV-NAME(2) + BV-NAME(3) + BV-NAME(4) + BV-NAME(5) + BV-NAME(6) + BV-NAME(7) + BV-NAME(8) + BV-NAME(9) + BV-NAME(10) + BV-NAME(11) + BV-NAME(12) + BV-NAME(13) + BV-NAME(14) + BV-NAME(15) + BV-NAME(16) + BV-NAME(17) + BV-NAME(18) + BV-NAME(19) + BV-NAME(20) + BV-NAME(21) + BV-NAME(22) + BV-NAME(23) + BV-NAME(24) + BV-NAME(25). + + * Scan the words in the SQL statement. If the + * word begins with ':', it is a placeholder for + * a bind variable. Get a value for it (as a string) + * and bind using the OBNDRV routine, datatype 1. + MOVE 0 TO INDP(1). + + PERFORM VARYING INDX FROM 1 BY 1 UNTIL INDX > 25 + IF BV-NAMEX(INDX,1) = ':' + ADD 1 TO N-BV + MOVE 0 TO SQLL + INSPECT BV-NAME(INDX) TALLYING SQLL + FOR CHARACTERS BEFORE INITIAL ' ' + DISPLAY "Enter value for " BV-NAME(INDX) " --> " + NO ADVANCING + ACCEPT BV-VAL(N-BV) + CALL "OBNDRV" USING CDA, BV-NAME(INDX), SQLL, + BV-VAL(N-BV), BV-VAL-L, VARCHAR2-T, + ZERO-A, INDP(1), FMT-NONE, ZERO-A, ZERO-A + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE + ELSE + DISPLAY "Bound " BV-VAL(N-BV) + END-IF + END-IF + END-PERFORM. + + DESCRIBE-DEFINE. + MOVE 0 TO N-OV. + PERFORM 9 TIMES + ADD 1 TO N-OV + IF (N-OV > 8) + GO TO DESCRIBE-DEFINE-EXIT + END-IF + MOVE 10 TO NAME-L(N-OV) + MOVE " " TO DBNAME(N-OV) + + CALL "ODESCR" USING CDA, N-OV, DBSIZE(N-OV), + DBTYPE(N-OV), + DBNAME(N-OV), NAME-L(N-OV), DSIZE(N-OV), + PREC(N-OV), SCALE(N-OV), NULL-OK(N-OV) + * Check for end of select list. + IF (C-RC IN CDA = 1007) + GO TO DESCRIBE-DEFINE-EXIT + END-IF + + * Check for error. + IF (C-RC IN CDA NOT = 0) + PERFORM ORA-ERROR + GO TO DESCRIBE-DEFINE-EXIT + END-IF + * Define an output variable for the select-list item. + * If it is a number, define a packed decimal variable, + * and create a format string for it. + + IF (DBTYPE(N-OV) = 2) + CALL "ODEFIN" USING CDA, N-OV, OV-NUM(N-OV), + PACKED-DEC-L, PACKED-DEC-T, TWO, + INDP(N-OV), FMT, FMT-L, PACKED-DEC-T, + ZERO-C, ZERO-C + ELSE + * For all other types, convert to a VARCHAR2 of length 10. + CALL "ODEFIN" USING CDA, N-OV, OV-CHAR(N-OV), + OV-CHAR-L, VARCHAR2-T, ZERO-A, INDP(N-OV), + FMT, ZERO-A, ZERO-A, ZERO-C, ZERO-C + END-IF + IF (C-RC IN CDA NOT = 0) + PERFORM ORA-ERROR + GO TO DESCRIBE-DEFINE-EXIT + END-IF + END-PERFORM. + DESCRIBE-DEFINE-EXIT. + + + FETCHN. + + MOVE 0 TO N-ROWS. + + PERFORM 10000 TIMES + + * Clear any existing values from storage buffers + MOVE SPACES TO OV-CHARX + MOVE LOW-VALUES TO OV-NUMX + + CALL "OFETCH" USING CDA + + * Check for end of fetch ("no data found") + IF C-RC IN CDA = 1403 + GO TO FETCHN-EXIT + END-IF + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO FETCHN-EXIT + END-IF + ADD 1 TO N-ROWS + PERFORM VARYING INDX FROM 1 + BY 1 UNTIL INDX > N-OV + IF (DBTYPE(INDX) = 2) + MOVE OV-NUM(INDX) TO NUM-DISP + INSPECT NUM-DISP REPLACING ALL ".00" BY " " + DISPLAY NUM-DISP NO ADVANCING + ELSE + DISPLAY OV-CHAR(INDX) NO ADVANCING + END-IF + DISPLAY " " NO ADVANCING + END-PERFORM + DISPLAY " " + END-PERFORM. + DISPLAY "LEAVING FETCHN...". + FETCHN-EXIT. + + + * Report an error. Obtain the error message + * text using the OERHMS routine. + ORA-ERROR. + IF LDA-RC IN LDA NOT = 0 + DISPLAY "OLOGON error" + MOVE 0 TO C-FNC IN CDA + MOVE LDA-RC IN LDA TO C-RC IN CDA. + DISPLAY "ORACLE error " NO ADVANCING. + IF C-FNC NOT = 0 + DISPLAY "processing OCI function" NO ADVANCING + MOVE C-FNC IN CDA TO ERR-FNC-D + DISPLAY ERR-FNC-D + ELSE + DISPLAY ":". + + MOVE " " TO MSGBUF. + CALL "OERHMS" USING LDA, C-RC IN CDA, MSGBUF,MSGBUF-L. + DISPLAY MSGBUF. + + diff --git a/cbdem3.cob b/cbdem3.cob new file mode 100644 index 0000000..4825ee9 --- /dev/null +++ b/cbdem3.cob @@ -0,0 +1,303 @@ + * + * $Header: cbdem3.cob 14-jul-99.14:31:45 mjaeger Exp $ + * + * Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. + * + * NAME + * cbdem3.cob - Cobol demo program # 3 + * MODIFIED (MM/DD/YY) + * mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + * plocke 11/14/95 - to update for v7.3 + * dchatter 07/20/95 - merge changes from branch 1.1.720.1 + * dchatter 04/14/95 - fix test to work on sun + * sjain 03/16/92 - Creation + * + * The program CBDEM3 creates a table called + * "VOICE_MAIL" that contains three fields: + * a message ID, and message length, and a LONG RAW + * column that contains a digitized voice + * message. The program fills one row of the table with a + * (simulated) message, then plays the message by + * extracting 64 kB chunks of it using the OFLNG routine, + * and sending them to a (simulated) digital-to-analog + * (DAC) converter routine. + + IDENTIFICATION DIVISION. + PROGRAM-ID. CBDEM3. + ENVIRONMENT DIVISION. + DATA DIVISION. + WORKING-STORAGE SECTION. + + 01 LDA. + 02 LDA-V2RC PIC S9(4) COMP. + 02 FILLER PIC X(10). + 02 LDA-RC PIC S9(4) COMP. + 02 FILLER PIC X(50). + 01 CDA. + 02 C-V2RC PIC S9(4) COMP. + 02 C-TYPE PIC S9(4) COMP. + 02 C-ROWS PIC S9(9) COMP. + 02 C-OFFS PIC S9(4) COMP. + 02 C-FNC PIC S9(4) COMP. + 02 C-RC PIC S9(4) COMP. + 02 FILLER PIC X(50). + 01 HDA PIC X(512). + + 01 ERRMSG PIC X(256). + 01 ERRMSG-L PIC S9(9) VALUE 256 COMP. + 01 ERR-RC PIC S9(9) COMP. + 01 ERR-FNC-D PIC ZZ9. + + 01 USER-ID PIC X(5) VALUE "SCOTT". + 01 USER-ID-L PIC S9(9) VALUE 5 COMP. + 01 PSW PIC X(5) VALUE "tiger". + 01 PSW-L PIC S9(9) VALUE 5 COMP. + 01 CONN PIC S9(9) VALUE 0 COMP. + 01 CONN-L PIC S9(9) VALUE 0 COMP. + 01 CONN-MODE PIC S9(9) VALUE 0 COMP. + + 01 SQL-STMT PIC X(132). + 01 SQLL PIC S9(9) COMP. + 01 ZERO-A PIC S9(9) VALUE 0 COMP. + 01 ZERO-B PIC S9(9) VALUE 0 COMP. + 01 FMT PIC X(6). + + * Establish a 200000 byte buffer. (On most systems, + * including the VAX, a PIC 99 reserves one byte.) + 01 MSGX. + 02 MSG OCCURS 200000 TIMES PIC 99. + 01 MSGX-L PIC S9(9) VALUE 200000 COMP. + 01 MSG-L PIC S9(9) COMP. + 01 MSG-L-D PIC ZZZZZZ. + 01 MSG-ID PIC S9(9) COMP. + 01 MSG-ID-L PIC S9(9) VALUE 4 COMP. + 01 MSG-ID-D PIC ZZZZ. + 01 LEN PIC 9(9) COMP. + 01 LEN-D PIC ZZZZ9. + 01 INDX PIC S9(9) COMP. + 01 INTEGER-T PIC S9(9) VALUE 3 COMP. + 01 DEF-MODE PIC S9(9) VALUE 1 COMP. + 01 LONG-RAW PIC S9(9) VALUE 24 COMP. + 01 ONE PIC S9(9) VALUE 1 COMP. + 01 TWO PIC S9(9) VALUE 2 COMP. + 01 THREE PIC S9(9) VALUE 3 COMP. + + 01 ANSX. + 02 ANSWER OCCURS 6 TIMES PIC X. + 01 VERSION-7 PIC S9(9) VALUE 2 COMP. + 01 INDP PIC S9(4) COMP. + 01 RCODE PIC S9(4) COMP. + 01 RLEN PIC S9(4) COMP. + 01 RETL PIC S9(9) COMP. + 01 OFF1 PIC S9(9) COMP. + + + PROCEDURE DIVISION. + BEGIN. + + * Connect to ORACLE in non-blocking mode. + * HDA must be initialized to all zeros before call to OLOG. + + MOVE LOW-VALUES TO HDA. + + CALL "OLOG" USING LDA, HDA, USER-ID, USER-ID-L, + PSW, PSW-L, CONN, CONN-L, CONN-MODE. + + IF LDA-RC NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-STOP. + + DISPLAY "Logged on to ORACLE as user ", USER-ID. + + * Open a cursor. + CALL "OOPEN" USING CDA, LDA, USER-ID, ZERO-A, + ZERO-A, USER-ID, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + * Drop the VOICE_MAIL table. + DISPLAY "OK to drop VOICE_MAIL table (Y or N)? : " + - WITH NO ADVANCING. + ACCEPT ANSX. + IF (ANSWER(1) NOT = 'y' AND ANSWER(1) NOT = 'Y') + DISPLAY "Exiting program now." + GO TO EXIT-CLOSE. + MOVE "DROP TABLE VOICE_MAIL" TO SQL-STMT. + MOVE 132 TO SQLL. + + * Call OPARSE with no deferred parse to execute the DDL + * statement immediately. + CALL "OPARSE" USING CDA, SQL-STMT, SQLL, + ZERO-A, VERSION-7. + IF C-RC IN CDA NOT = 0 + IF (C-RC IN CDA = 942) + DISPLAY "Table did not exist." + ELSE + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF + END-IF + ELSE + DISPLAY "Table dropped." + END-IF + + * Create the VOICE_MAIL table anew. + MOVE "CREATE TABLE VOICE_MAIL (MSG_ID NUMBER(6), + - "MSG_LEN NUMBER(12), MSG LONG RAW)" TO SQL-STMT. + MOVE 132 TO SQLL. + + * Non-deferred parse to execute the DDL SQL statement. + DISPLAY "Table VOICE_MAIL " NO ADVANCING. + + CALL "OPARSE" USING CDA, SQL-STMT, SQLL, + ZERO-A, VERSION-7. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + DISPLAY "created.". + + * Insert some data into the table. + MOVE "INSERT INTO VOICE_MAIL VALUES (:1, :2, :3)" + TO SQL-STMT. + MOVE 132 TO SQLL. + CALL "OPARSE" USING CDA, SQL-STMT, SQLL, + ZERO-A, VERSION-7. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + * Bind the inputs. + MOVE 0 TO INDP. + CALL "OBNDRN" USING CDA, ONE, MSG-ID, MSG-ID-L, + INTEGER-T, ZERO-A, INDP, FMT, ZERO-A, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + CALL "OBNDRN" USING CDA, TWO, MSG-L, MSG-ID-L, + INTEGER-T, ZERO-A, INDP, FMT, ZERO-A, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + CALL "OBNDRN" USING CDA, THREE, MSGX, MSGX-L, + LONG-RAW, ZERO-A, INDP, FMT, ZERO-A, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + * Set input variables, then execute the INSERT statement. + MOVE 100 TO MSG-ID. + MOVE 200000 TO MSG-L. + PERFORM VARYING INDX FROM 1 BY 1 UNTIL INDX > MSG-L + MOVE 42 TO MSG(INDX) + END-PERFORM. + CALL "OEXN" USING CDA, ONE, ZERO-B. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + MOVE "SELECT MSG_ID, MSG_LEN, MSG FROM VOICE_MAIL + - " WHERE MSG_ID = 100" TO SQL-STMT. + + * Call OPARSE in deferred mode to select a message. + CALL "OPARSE" USING CDA, SQL-STMT, SQLL, + DEF-MODE, VERSION-7. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + * Define the output variables. + CALL "ODEFIN" USING CDA, ONE, MSG-ID, + MSG-ID-L, INTEGER-T, ZERO-A, ZERO-A, ZERO-A, + ZERO-A, ZERO-A, ZERO-A, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + CALL "ODEFIN" USING CDA, TWO, MSG-L, + MSG-ID-L, INTEGER-T, ZERO-A, ZERO-A, ZERO-A, + ZERO-A, ZERO-A, ZERO-A, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + MOVE 100 TO MSG-ID-L. + CALL "ODEFIN" USING CDA, THREE, MSGX, + MSG-ID-L, LONG-RAW, ZERO-A, INDP, ANSX, ZERO-A, ZERO-A, + RLEN, RCODE. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + * Do the query, getting the message ID and just the first + * 100 bytes of the message. This query basically just sets + * the cursor to the right row. The message contents are + * fetched by the OFLNG routine. + + CALL "OEXFET" USING CDA, ONE, ZERO-A, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + MOVE MSG-ID TO MSG-ID-D. + DISPLAY " ". + DISPLAY "Message " MSG-ID-D " is available.". + MOVE MSG-L TO MSG-L-D. + DISPLAY "The length is " MSG-L-D " bytes.". + + PERFORM VARYING OFF1 FROM 0 BY 65536 + UNTIL MSG-L <= 0 + IF (MSG-L < 65536) + MOVE MSG-L TO LEN + ELSE + MOVE 65536 TO LEN + END-IF + PERFORM PLAY-MSG THRU PLAY-MSG-EXIT + SUBTRACT LEN FROM MSG-L + * IF (MSG-L < 0 OR MSG-L = 0) + * GO TO END-LOOP + * END-IF + END-PERFORM. + + END-LOOP. + DISPLAY " ". + DISPLAY "End of message.". + + + EXIT-CLOSE. + CALL "OCLOSE" USING CDA. + EXIT-LOGOFF. + CALL "OLOGOF" USING LDA. + EXIT-STOP. + STOP RUN. + + + PLAY-MSG. + MOVE LEN TO LEN-D. + DISPLAY "Playing " LEN-D " bytes.". + PLAY-MSG-EXIT. + + + + * Report an error. Obtain the error message + * text using the OERHMS routine. + ORA-ERROR. + IF LDA-RC IN LDA NOT = 0 + DISPLAY "OLOGON error" + MOVE 0 TO C-FNC IN CDA + MOVE LDA-RC IN LDA TO C-RC IN CDA. + DISPLAY "ORACLE error" NO ADVANCING. + IF C-FNC NOT = 0 + DISPLAY " processing OCI function " NO ADVANCING + MOVE C-FNC IN CDA TO ERR-FNC-D + DISPLAY ERR-FNC-D + ELSE + DISPLAY ".". + + MOVE " " TO ERRMSG. + CALL "OERHMS" USING LDA, C-RC IN CDA, + ERRMSG, ERRMSG-L. + DISPLAY ERRMSG. + + + diff --git a/cdcdemo.sql b/cdcdemo.sql new file mode 100644 index 0000000..dda6c2a --- /dev/null +++ b/cdcdemo.sql @@ -0,0 +1,455 @@ +Rem +Rem $Header: cdcdemo.sql 22-may-2006.07:34:50 bpanchap Exp $ +Rem +Rem cdcdemo.sql +Rem +Rem Copyright (c) 2004, 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem cdcdemo.sql - Change Data Capture Demo +Rem +Rem DESCRIPTION +Rem This script is a demonstration of Change Data Capture (CDC) +Rem capabilities. It operates in asynchronous HotLog mode. +Rem +Rem This demo shows how CDC can be used to supplement information +Rem stored in the Human Resources (HR) sample schema without changing +Rem the tables already defined there. The HR schema tracks current +Rem salary for each employee but does not maintain a history of +Rem salary changes. This demo creates a new HR.SALARY_HISTORY table +Rem and uses CDC to populate it. HR.SALARY_HISTORY can be used to +Rem track information such as an employee's salary over time, or +Rem average amount and frequency of raises given by a particular +Rem department. +Rem +Rem This script creates a new user CDCPUB to be the CDC publisher. +Rem It uses the existing user HR as both the owner of the source +Rem table and as the CDC subscriber. +Rem +Rem NOTES +Rem This script must be run on a database that is set up for +Rem asynchronous HotLog Change Data Capture. The following should +Rem be verified before running this script: +Rem +Rem 1. Database initialization parameters are set according to the +Rem table "Initialization Parameters for Asynchronous HotLog +Rem Publishing" in the Change Data Capture chapter of the Oracle +Rem Data Warehousing Guide. +Rem +Rem 2. The database is running in archivelog mode, force logging mode +Rem and is performing at least minimal database-level supplemental +Rem logging. +Rem +Rem For more information about Change Data Capture, please refer to +Rem the Change Data Capture chapter in the Oracle Data Warehousing Guide. +Rem +Rem To run this script, do the following actions: +Rem sqlplus /nolog +Rem @cdcdemo +Rem +Rem MODIFIED (MM/DD/YY) +Rem bpanchap 05/22/06 - Adding ddl_markers to create_change_table +Rem pabingha 07/12/04 - increase subscrip window wait +Rem pabingha 03/26/04 - pabingha_cdc_demo +Rem pabingha 03/10/04 - Created +Rem + +set echo on +set pagesize 80 + +connect hr/hr + +-- +-- Create a copy of HR.EMPLOYEES so that this script can perform +-- employee DML operations without changing the original sample +-- schema data. This copy, HR.CDC_DEMO_EMPLOYEES, is the CDC source +-- table for this demo. +-- +create table cdc_demo_employees as select * from employees; + +-- +-- Create new HR.SALARY_HISTORY table. +-- +create table salary_history ( + employee_id number(6) not null, + job_id varchar2(10) not null, + department_id number(4), + old_salary number(8,2), + new_salary number(8,2), + percent_change number(4,2), + salary_action_date date +); + +-- +-- Instantiate the source table so that the underlying Oracle +-- Streams environment records the information it needs to capture +-- the source table's changes. +-- +connect / as sysdba +begin + dbms_capture_adm.prepare_table_instantiation( + table_name => 'HR.CDC_DEMO_EMPLOYEES'); +end; +/ + +-- +-- Create CDCPUB user to be the CDC publisher. +-- +connect / as sysdba +create user cdcpub identified BY cdcpub; +grant unlimited tablespace to cdcpub; +grant create session to cdcpub; +grant create table to cdcpub; +grant create sequence to cdcpub; +grant select_catalog_role to cdcpub; +grant execute_catalog_role to cdcpub; +grant connect, resource, dba to cdcpub; +execute dbms_streams_auth.grant_admin_privilege(grantee=>'CDCPUB'); + +-- +-- Connect as the CDC publisher and create the objects needed to publish +-- the changes to the HR.CDC_DEMO_EMPLOYEES source table. +-- +connect cdcpub/cdcpub + +-- +-- Create asynchronous HotLog change set CDC_DEMO_SET. +-- +begin + dbms_cdc_publish.create_change_set( + change_set_name => 'CDC_DEMO_SET', + description => 'change set for CDC demo', + change_source_name => 'HOTLOG_SOURCE', + stop_on_ddl => 'Y', + begin_date => NULL, + end_date => NULL); +end; +/ + +-- +-- Create change table CDCPUB.CDC_DEMO_EMP_CT and grant select access +-- on it to the subscriber. +-- +begin + dbms_cdc_publish.create_change_table( + owner => 'CDCPUB', + change_table_name => 'CDC_DEMO_EMP_CT', + change_set_name => 'CDC_DEMO_SET', + source_schema => 'HR', + source_table => 'CDC_DEMO_EMPLOYEES', + column_type_list => 'EMPLOYEE_ID NUMBER, FIRST_NAME VARCHAR2(20), + LAST_NAME VARCHAR2(25), EMAIL VARCHAR2(25), + PHONE_NUMBER VARCHAR2(20), HIRE_DATE DATE, + JOB_ID VARCHAR2(10), SALARY NUMBER, + COMMISSION_PCT NUMBER, MANAGER_ID NUMBER, + DEPARTMENT_ID NUMBER', + capture_values => 'BOTH', + rs_id => 'y', + row_id => 'n', + user_id => 'y', + timestamp => 'y', + object_id => 'n', + source_colmap => 'n', + target_colmap => 'y', + ddl_markers => 'n', + options_string => null); +end; +/ +grant select on cdc_demo_emp_ct to hr; + +-- +-- Enable capture for the CDC_DEMO_SET change set. +-- +begin + dbms_cdc_publish.alter_change_set( + change_set_name => 'CDC_DEMO_SET', + enable_capture => 'y'); +end; +/ + +-- +-- Connect as the CDC subscriber and create the CDC subscription that +-- will be used to populate the new HR.SALARY_HISTORY table. +-- +connect hr/hr + +-- +-- Create subscription CDC_DEMO_EMP_SUB. +-- +begin + dbms_cdc_subscribe.create_subscription( + change_set_name => 'CDC_DEMO_SET', + description => 'subscription to cdc_demo_employees', + subscription_name => 'CDC_DEMO_EMP_SUB'); +end; +/ + +-- +-- Create subscriber view HR.CDC_DEMO_EMP_SUB_VIEW to display +-- changes to the HR.CDC_DEMO_EMPLOYEES source table. +-- +begin + dbms_cdc_subscribe.subscribe( + subscription_name => 'CDC_DEMO_EMP_SUB', + source_schema => 'HR', + source_table => 'CDC_DEMO_EMPLOYEES', + column_list => 'EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, + PHONE_NUMBER, HIRE_DATE, JOB_ID, SALARY, + COMMISSION_PCT, MANAGER_ID, DEPARTMENT_ID', + subscriber_view => 'CDC_DEMO_EMP_SUB_VIEW'); +end; +/ + +-- +-- Activate subscription CDC_DEMO_EMP_SUB. +-- +begin + dbms_cdc_subscribe.activate_subscription( + subscription_name => 'CDC_DEMO_EMP_SUB'); +end; +/ + +-- +-- Create procedure HR.UPDATE_SALARY_HISTORY to populate the new +-- HR.SALARY_HISTORY table. This procedure extends the subscription +-- window of the CDC_DEMP_EMP_SUB subscription to get the most recent +-- set of source table changes. It uses the HR.CDC_DEMO_EMP_SUB_VIEW +-- subscriber view to scan the changes and insert them into the +-- HR.SALARY_HISTORY table. It then purges the subscription window to +-- indicate that it is finished with this set of changes. +-- +create or replace procedure update_salary_history is + cursor cur is + select * from ( + select 'I' opt, cscn$, rsid$, employee_id, job_id, department_id, + 0 old_salary, salary new_salary, commit_timestamp$ + from cdc_demo_emp_sub_view + where operation$ = 'I ' + union all + select 'D' opt, cscn$, rsid$, employee_id, job_id, department_id, + salary old_salary, 0 new_salary, commit_timestamp$ + from cdc_demo_emp_sub_view + where operation$ = 'D ' + union all + select 'U' opt , v1.cscn$, v1.rsid$, v1.employee_id, v1.job_id, + v1.department_id, v1.salary old_salary, v2.salary new_salaryi, + v1.commit_timestamp$ + from cdc_demo_emp_sub_view v1, cdc_demo_emp_sub_view v2 + where v1.operation$ = 'UO' and v2.operation$ = 'UN' and + v1.cscn$ = v2.cscn$ and v1.rsid$ = v2.rsid$ and + abs(v1.salary - v2.salary) > 0) + order by cscn$, rsid$; + percent number; + +begin + + -- Get the next set of changes to HR.CDC_DEMO_EMPLOYEES source table. + dbms_cdc_subscribe.extend_window( + subscription_name => 'CDC_DEMO_EMP_SUB'); + + -- Process each change. + for row in cur loop + if row.opt = 'I' then + insert into salary_history values ( + row.employee_id, row.job_id, row.department_id, 0, row.new_salary, + NULL, row.commit_timestamp$); + end if; + if row.opt = 'D' then + insert into salary_history values ( + row.employee_id, row.job_id, row.department_id, row.old_salary, 0, + NULL, row.commit_timestamp$); + end if; + if row.opt = 'U' then + percent := (row.new_salary - row.old_salary) / row.old_salary * 100; + insert into salary_history values ( + row.employee_id, row.job_id, row.department_id, row.old_salary, + row.new_salary, percent, row.commit_timestamp$); + end if; + end loop; + + -- Indicate subscriber is finished with this set of changes. + dbms_cdc_subscribe.purge_window( + subscription_name => 'CDC_DEMO_EMP_SUB'); + +end update_salary_history; +/ + +-- +-- Create procedure CDCPUB.WAIT_FOR_CHANGES to enable this demo to run +-- predictably. The asynchronous nature of CDC HotLog mode means that +-- there is a delay for source table changes to appear in the CDC +-- change table and the subscriber view. By default this procedure +-- waits up to 5 minutes for the change table and 1 additional minute +-- for the subscriber view. This can be adjusted if it is insufficient. +-- The caller must specify the name of the change table and the number +-- of rows expected to be in the change table. The caller may also +-- optionally specify a different number of seconds to wait for changes +-- to appear in the change table. +-- +connect cdcpub/cdcpub +create or replace function wait_for_changes( + change_table_name in varchar2, -- name of change table + rowcount in number, -- number of rows to wait for + maxwait_seconds in number := 300) -- maximum time to wait, in seconds +return varchar2 authid current_user as + + num_of_rows number := 0; -- number of rows in change table + slept number := 0; -- total time slept + sleep_time number := 3; -- number of seconds to sleep + return_msg varchar2(500); -- informational message + query_txt varchar2(200) := 'select count(*) from ' || change_table_name; + keep_waiting boolean := TRUE; -- whether to keep waiting + +begin + + while (keep_waiting) loop + dbms_lock.sleep(sleep_time); + slept := slept+sleep_time; + execute immediate query_txt into num_of_rows; + + -- Got expected number of rows. + if num_of_rows >= rowcount then + keep_waiting := FALSE; + return_msg := 'Change table ' || change_table_name || + ' contains at least ' || rowcount || ' rows.'; + goto DONE; + + -- Reached maximum number of seconds to wait. + elsif slept > maxwait_seconds then + return_msg := ' !!! - Timed out while waiting for ' || + change_table_name || + ' to reach ' || rowcount || ' rows !!! '; + goto DONE; + end if; + end loop; + + <> + -- additional wait time for changes to become available to subscriber view + dbms_lock.sleep(120); + + return return_msg; +end ; +/ + +-- +-- First set of DML operations on source table HR.CDC_DEMO_EMPLOYEES. +-- +connect hr/hr +update cdc_demo_employees set salary = salary + 500 where job_id = 'SH_CLERK'; +update cdc_demo_employees set salary = salary + 1000 where job_id = 'ST_CLERK'; +update cdc_demo_employees set salary = salary + 1500 where job_id = 'PU_CLERK'; +commit; + +insert into cdc_demo_employees values + (207, 'Mary', 'Lee', 'MLEE', '310.234.4590', + to_date('10-JAN-2003','DD-MON-YYYY'), 'SH_CLERK', 4000, NULL, 121, 50); +insert into cdc_demo_employees values + (208, 'Karen', 'Prince', 'KPRINCE', '345.444.6756', + to_date('10-NOV-2003','DD-MON-YYYY'), 'SH_CLERK', 3000, NULL, 111, 50); +insert into cdc_demo_employees values + (209, 'Frank', 'Gate', 'FGATE', '451.445.5678', + to_date('13-NOV-2003','DD-MON-YYYY'), 'IT_PROG', 8000, NULL, 101, 50); +insert into cdc_demo_employees values + (210, 'Paul', 'Jeep', 'PJEEP', '607.345.1112', + to_date('28-MAY-2003','DD-MON-YYYY'), 'IT_PROG', 8000, NULL, 101, 50); +commit; + +-- +-- Expecting 94 rows to appear in the change table CDCPUB.CDC_DEMO_EMP_CT. +-- This first capture may take a few minutes. Later captures should be +-- faster. +-- +connect cdcpub/cdcpub +select wait_for_changes('CDCPUB.CDC_DEMO_EMP_CT', 94, 1000) message from dual; + +-- +-- Execute subscriber routine to update HR.SALARY_HISTORY. +-- +connect hr/hr +execute update_salary_history; + +-- +-- Look at the contents of HR.SALARY_HISTORY. +-- +select employee_id, job_id, department_id, old_salary, new_salary, + percent_change +from salary_history +order by employee_id, old_salary, new_salary; + +-- +-- Second set of DML operations on source table HR.CDC_DEMO_EMPLOYEES. +-- +connect hr/hr +delete from cdc_demo_employees +where first_name = 'Mary' and last_name = 'Lee'; +delete from cdc_demo_employees +where first_name = 'Karen' and last_name = 'Prince'; +delete from cdc_demo_employees +where first_name = 'Frank' and last_name = 'Gate'; +delete from cdc_demo_employees +where first_name = 'Paul' and last_name = 'Jeep'; +commit; + +update cdc_demo_employees set salary = salary + 5000 +where job_id = 'AD_VP'; +update cdc_demo_employees set salary = salary - 1000 +where job_id = 'ST_MAN'; +update cdc_demo_employees set salary = salary - 500 +where job_id = 'FI_ACCOUNT'; +commit; + +-- +-- Expecting 122 rows to appear in the change table CDCPUB.CDC_DEMO_EMP_CT. +-- (94 rows from the first set of DMLs and 28 from the second set) +-- +connect cdcpub/cdcpub +select wait_for_changes('CDCPUB.CDC_DEMO_EMP_CT', 122, 1000) message from dual; + +-- +-- Execute subscriber routine to update HR.SALARY_HISTORY. +-- +connect hr/hr +execute update_salary_history; + +-- +-- Look at the contents of HR.SALARY_HISTORY. +-- +select employee_id, job_id, department_id, old_salary, new_salary, + percent_change +from salary_history +order by employee_id, old_salary, new_salary; + +-- +-- Clean up all objects created for this demo. +-- +connect hr/hr +begin + dbms_cdc_subscribe.drop_subscription( + subscription_name => 'CDC_DEMO_EMP_SUB'); +end; +/ + +connect cdcpub/cdcpub +begin + dbms_cdc_publish.drop_change_table( + owner => 'CDCPUB', + change_table_name => 'CDC_DEMO_EMP_CT', + force_flag => 'Y'); +end; +/ +begin + dbms_cdc_publish.drop_change_set( + change_set_name => 'CDC_DEMO_SET'); +end; +/ +drop function wait_for_changes; + +connect hr/hr +drop table salary_history purge; +drop table cdc_demo_employees; +drop procedure update_salary_history; + +connect / as sysdba +drop user cdcpub cascade; + +exit diff --git a/cdemdp9i.sql b/cdemdp9i.sql new file mode 100644 index 0000000..b3d22dd --- /dev/null +++ b/cdemdp9i.sql @@ -0,0 +1,112 @@ +Rem +Rem $Header: cdemdp9i.sql 15-aug-2006.11:46:52 jkaloger Exp $ +Rem +Rem cdemdp9i.sql +Rem +Rem+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem All Rights Reserved. +Rem+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +Rem +Rem +Rem NAME: +Rem +Rem Cdemdp9i.sql +Rem +Rem DESCRIPTION: +Rem +Rem Provides Oracle9i Objects for Direct Path API demo. +Rem +Rem NOTES: +Rem +Rem Objects and tables will be used by several DP API demo clients. +Rem +Rem Access the database with the oe/oe(Order Entry) user/password. +Rem +Rem The demo tables incorporate various "Sample Schema" types from the +Rem Order Entry schema scripts at $ORACLE_HOME/demo/schema. +Rem Refer to "Oracle9i Sample Schemas" documentation for schema layout and +Rem how to reinitialize the Sample Schema. +Rem +Rem This demo adds three tables to the Sample Schema. +Rem +Rem Sample Schemas can be built using the Database Configuration Assistant +Rem (DBCA). Refer to appropriate Oracle9i documentation for using DBCA. +Rem +Rem Refer to OCI Programmer Guide, Chapter 12, for complete DP API +Rem information and Appendix B for DP API demo information. +Rem +Rem Sample Schema types used for DP API demos: +Rem +Rem cust_address_type +Rem customer_typ +Rem corporate_cust_typ (derived from customer_typ) +Rem inventory_typ +Rem warehouse_typ (nested column object within inventory_typ) +Rem +Rem DP API Demo tables created for DP API demos: +Rem +Rem dp_api_demo1 +Rem dp_api_demo2 +Rem dp_api_demo3 +Rem +Rem +Rem Used by clients: +Rem +Rem Cdemdpco.c - Column object +Rem Cdemdpno.c - Nested Column object +Rem Cdemdpro.c - Reference column object +Rem Cdemdpss.c - Sql string +Rem Cdemdpin.c - Inheritance +Rem Cdemdpit.c - Table object with inheritance +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem jkaloger 08/15/06 - Lowercase passwords for secure verifiers project +Rem eegolf 04/04/01 - Merged eegolf_demo_update +Rem +Rem eegolf 04/27/01 - Creation +Rem +Rem------------------------------------------------------------------------ + +connect oe/oe + +set echo on + +drop table dp_api_demo1 force; +drop table dp_api_demo2 force; +drop table dp_api_demo3 force; + + +Rem -------------------------------------------- +Rem Create Column objects +Rem -------------------------------------------- + +Rem Place any DP API objects here + + +Rem -------------------------------------------- +Rem Create tables +Rem -------------------------------------------- + +create table dp_api_demo2 of warehouse_typ; +create table dp_api_demo3 of customer_typ +nested table cust_orders store as cust_orders2 +(nested table order_item_list store as invnt_oi_list); + +create table dp_api_demo1 +(cust_first_name varchar2(10), + cust_last_name varchar2(10), + cust_address cust_address_typ, + cust_more_info customer_typ, + current_inventory inventory_typ, + inventory_string varchar2(20), + inventory_string2 varchar2(20), + inventory_warehouse ref warehouse_typ, + inventory_stock_date varchar2(20)) +nested table cust_more_info.cust_orders store as cust_more_orders +(nested table order_item_list store as inventory_oi_list); + +exit; + + diff --git a/cdemdpco.c b/cdemdpco.c new file mode 100644 index 0000000..8c64734 --- /dev/null +++ b/cdemdpco.c @@ -0,0 +1,139 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemdpco.c 15-aug-2006.10:05:09 jkaloger Exp $ "; +#endif /* RCSID */ + +/* +** Copyright (c) 2001 Oracle Corporation. All rights reserved. +*/ + +/* +** Directions: +** 1. make -f demo_rdbms.mk build_dp EXE=cdemdpco OBJS=cdemdpco.o +** makes the cdemdpco executable +** 2. sqlplus oe/oe @cdemdp9i.sql +** creates the Oracle 9.0 types tbl +** 3. cdemdpco < cdemdpco.dat +** runs the executable +** 4. to retrieve data, select from "dp_api_demo1" as "oe/oe" +** +*/ + +/* + NAME + cdemdpco.c - An example C program that loads a column object + via Direct Path API. + + DESCRIPTION + A client module to be used with the cdemodp.c driver. + + NOTES + This module loads selected types as defined in the Sample Schema. + Refer to Cdemdp9i.sql for more information on the use of the + Sample Schema with the DP API demo modules. + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + cmlim 09/11/01 - fix lint + eegolf 04/04/01 - Merged eegolf_demo_update + eegolf 03/27/01 - Creation + */ + +#include +#include +#include + + +externdef struct col objx_01_col [] = +{ + { + (text *)"street_address", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"postal_code", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"city", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"state_province", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"country_id", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + } +}; + +externdef struct fld objx_01_fld [] = +{ + { 26, 65, 40, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* street_address */ + { 66, 75, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* postal_code */ + { 76,105, 30, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* city */ + {106,115, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* state_province */ + {116,117, 2, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* country_id */ +}; + +externdef struct obj cust_address_typ = +{ + (text *) "CUST_ADDRESS_TYP", 5, objx_01_col, objx_01_fld, 0, 0, + (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_OBJ}; + + +externdef struct col column[] = +{ + { + (text *)"cust_first_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"cust_last_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"cust_address", 0, SQLT_NTY, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, & cust_address_typ + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 10, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_first_name */ + { 11,20, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_last_name */ + { 21,25, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* cust_address */ +}; + + +externdef struct tbl table = +{ + (text *)"OE", /* table owner */ + (text *)"dp_api_demo1", /* table name */ + (text *)"" , /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024) /* transfer buffer size */ +}; + +externdef struct sess session = +{ + (text *)"oe", /* user */ + (text *)"oe", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemdpco.c */ + diff --git a/cdemdpco.dat b/cdemdpco.dat new file mode 100644 index 0000000..cfcee33 --- /dev/null +++ b/cdemdpco.dat @@ -0,0 +1,10 @@ +fredrich lawson 1 563 West Apple Orchard Road 1234567890Manchester New Hamp US +pamela smith 1 256 East Apple Orchard Road 1234567890Concord New Hamp US +james thyson 1 63 North Apple Orchard Road 1234567890Manchester New Hamp US +barbara sweeney 349 South Apple Orchard Road 1234567890Concord New Hamp US +richard jacobs 1 38 West Apple Orchard Road 1234567890Manchester New Hamp US +mary miller 1 20 East Apple Orchard Road 1234567890Concord New Hamp US +franklin ford 1 293 North Apple Orchard Road 1234567890Manchester New Hamp US +jessica patrick 1 843 South Apple Orchard Road 1234567890Concord New Hamp US +john wang 1 39 West Apple Orchard Road 1234567890Manchester New Hamp US +peter barnes 1 5 East Apple Orchard Road 1234567890Concord New Hamp US diff --git a/cdemdpin.c b/cdemdpin.c new file mode 100644 index 0000000..1f73140 --- /dev/null +++ b/cdemdpin.c @@ -0,0 +1,124 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemdpin.c 15-aug-2006.10:05:43 jkaloger Exp $ "; +#endif /* RCSID */ + +/* +** Copyright (c) 2001 Oracle Corporation. All rights reserved. +*/ + +/* +** Directions: +** 1. make -f demo_rdbms.mk build_dp EXE=cdemdpin OBJS=cdemdpin.o +** makes the cdemdpin executable +** 2. sqlplus OE/OE @cdemdp9i.sql +** creates the Oracle 9.0 types tbl +** 3. cdemdpin < cdemdpin.dat +** runs the executable +** 4. to retrieve data, select from "dp_api_demo1" as "OE/OE" +** +*/ + +/* + NAME + cdemdpin An example C program that loads a derived object type + via Direct Path API. + + DESCRIPTION + A client module to be used with the cdemodp.c driver. + + NOTES + This module loads selected types as defined in the Sample Schema. + Refer to Cdemdp9i.sql for more information on the use of the + Sample Schema with the DP API demo modules. + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + cmlim 09/11/01 - fix lint + eegolf 04/04/01 - Merged eegolf_demo_update + eegolf 03/29/01 - Creation + */ + +#include +#include +#include + + +externdef struct col objx_01_col [] = +{ + { + (text *)"customer_id", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"account_mgr_id", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + } +}; + +externdef struct fld objx_01_fld [] = +{ + { 26, 31, 6, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* customer_id */ + { 32, 37, 6, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* account_mgr_id */ +}; + +externdef struct obj corporate_customer_typ = +{ + (text *) "CORPORATE_CUSTOMER_TYP", 2, objx_01_col, objx_01_fld, 0, 0, + (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_OBJ}; + + +externdef struct col column[] = +{ + { + (text *)"cust_first_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"cust_last_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"cust_more_info", 0, SQLT_NTY, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, & corporate_customer_typ + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 10, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_first_name */ + { 11,20, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_last_name */ + { 21,25, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* cust_more_info */ +}; + + +externdef struct tbl table = +{ + (text *)"OE", /* table owner */ + (text *)"dp_api_demo1", /* table name */ + (text *)"" , /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024) /* transfer buffer size */ +}; + +externdef struct sess session = +{ + (text *)"oe", /* user */ + (text *)"oe", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemdpin .c */ + diff --git a/cdemdpin.dat b/cdemdpin.dat new file mode 100644 index 0000000..86524d5 --- /dev/null +++ b/cdemdpin.dat @@ -0,0 +1,10 @@ +fredrich lawson 1 123456123456 +pamela smith 1 121212909090 +james thyson 1 131313808080 +barbara sweeney 1 141414707070 +richard jacobs 1 151515606060 +mary miller 1 161616404040 +franklin ford 1 171717505050 +jessica patrick 181818303030 +john wang 1 191919202020 +peter barnes 1 101010101010 diff --git a/cdemdpit.c b/cdemdpit.c new file mode 100644 index 0000000..95347c2 --- /dev/null +++ b/cdemdpit.c @@ -0,0 +1,108 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemdpit.c 15-aug-2006.10:06:05 jkaloger Exp $ "; +#endif /* RCSID */ + +/* +** Copyright (c) 2001 Oracle Corporation. All rights reserved. +*/ + +/* +** Directions: +** 1. make -f demo_rdbms.mk build_dp EXE=cdemdpit OBJS=cdemdpit.o +** makes the cdemdpit executable +** 2. sqlplus OE/OE @cdemdp9i.sql +** creates the Oracle 9.0 types tbl +** 3. cdemdpit < cdemdpit.dat +** runs the executable +** 4. to retrieve data, select from "dp_api_demo3" as "OE/OE" +** +*/ + +/* + NAME + cdemdpit.c - An example C program that loads an object table, + of a non final type corporate_customer_typ, via direct path API. + In this example the OID is being loaded explicitly. + + DESCRIPTION + A client module to be used with the cdemodp.c driver. + + NOTES + This module loads selected types as defined in the Sample Schema. + Refer to Cdemdp9i.sql for more information on the use of the + Sample Schema with the DP API demo modules. + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + cmlim 09/11/01 - fix lint + cmlim 04/20/01 - remove TBL_SUBST_OBJ flg + eegolf 04/04/01 - Merged eegolf_demo_update + eegolf 03/29/01 - Creation + */ + +#include +#include +#include + + +externdef struct col column[] = +{ + { + (text *)"cust_oid", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0, (ub4)COL_OID + }, + { + (text *)"cust_first_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0, (ub4)0 + }, + { + (text *)"cust_last_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0, (ub4)0 + }, + { + (text *)"account_mgr_id", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0, (ub4)0 + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 32, 32, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_oid */ + { 33,52, 20, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_first_name */ + { 53,72, 20, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_last_name */ + { 73,78, 6, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* account_mgr_id */ +}; + + +externdef struct tbl table = +{ + (text *)"OE", /* table owner */ + (text *)"dp_api_demo3", /* table name */ + (text *)"" , /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024), /* transfer buffer size */ + (text *)"corporate_customer_typ" /* derived object type to be loaded */ +}; + +externdef struct sess session = +{ + (text *)"oe", /* user */ + (text *)"oe", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemdpit.c */ + diff --git a/cdemdpit.dat b/cdemdpit.dat new file mode 100644 index 0000000..7165693 --- /dev/null +++ b/cdemdpit.dat @@ -0,0 +1,10 @@ +78686CC3AEE95A4DE034080020A3EC15fredrick lawson 123456 +78686CC3AEE85A4DE034080020A3EC15pamela smith 101010 +78686CC3AEE75A4DE034080020A3EC15james thyson 202020 +78686CC3AEE65A4DE034080020A3EC15barbara sweeney 303030 +78686CC3AEE55A4DE034080020A3EC15richard jacobs 101010 +78686CC3AEE45A4DE034080020A3EC15mary miller 202020 +78686CC3AEE35A4DE034080020A3EC15franklin ford 303030 +78686CC3AEE25A4DE034080020A3EC15jessica patrick 101010 +78686CC3AEE15A4DE034080020A3EC15john wang 202020 +78686CC3AEE10A4DE034080020A3EC15peter barnes 303030 diff --git a/cdemdplp.c b/cdemdplp.c new file mode 100644 index 0000000..8d40027 --- /dev/null +++ b/cdemdplp.c @@ -0,0 +1,166 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemdplp.c 15-aug-2006.10:06:32 jkaloger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. */ + +/* + * -- cdemdplp.c -- + * An example program that loads data via direct path api. + * + * Directions: + * 1. make -f demo_rdbms.mk build_dp EXE=cdemdplp OBJS=cdemdplp.o + * makes the cdemdplp executable + * 2. sqlplus scott/tiger @cdemdplp.sql + * creates lineitem_dp tbl + * 3. cdemdplp < cdemdplp.dat + * runs executable + * 4. to retrieve data, select from "lineitem_dp" as "scott/tiger" + * + */ + +/* + NAME + cdemdplp.c - C Demo for Direct Path api for LineItem Partitioned + table. + + DESCRIPTION + - A client module describing lineitem partition table. + To be used with cdemodp.c driver prog. + + NOTES + Loads the lineitem1 partition of the lineitem table. + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + eegolf 12/01/03 - correct size 7 to 17 for l_shipinstruct + cmlim 09/11/01 - fix lint + eegolf 04/04/01 - Merged eegolf_demo_update + eegolf 03/04/01 - Updated for 9i + cmlim 09/16/98 - Creation + */ + +#include +#include +#include + +externdef struct col column[] = +{ + { + (text *)"l_orderkey", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_partkey", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_suppkey", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_linenumber", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_quantity", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_extendedprice", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_discount", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_tax", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_returnflag", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_linestatus", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_shipdate", 0, SQLT_CHR, (text *) "DD-MON-RR", + (sword)0, (sword)0, (ub2)0, (ub1)1 + }, + { + (text *)"l_commitdate", 0, SQLT_CHR, (text *) "DD-MON-RR", + (sword)0, (sword)0, (ub2)0, (ub1)1 + }, + { + (text *)"l_receiptdate", 0, SQLT_CHR, (text *) "DD-MON-RR", + (sword)0, (sword)0, (ub2)0, (ub1)1 + }, + { + (text *)"l_shipinstruct", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_shipmode", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_comment", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 6, 6, FLD_INLINE }, /* l_orderkey */ + { 7, 11, 5, FLD_INLINE }, /* l_partkey */ + { 12, 15, 4, FLD_INLINE }, /* l_suppkey */ + { 16, 16, 1, FLD_INLINE }, /* l_linenumber */ + { 17, 18, 2, FLD_INLINE }, /* l_quantity */ + { 19, 26, 8, FLD_INLINE }, /* l_extendedprice */ + { 27, 29, 3, FLD_INLINE }, /* l_discount */ + { 30, 32, 3, FLD_INLINE }, /* l_tax */ + { 33, 33, 1, FLD_INLINE }, /* l_returnflag */ + { 34, 34, 1, FLD_INLINE }, /* l_linestatus */ + { 35, 43, 9, FLD_INLINE }, /* l_shipdate */ + { 44, 52, 9, FLD_INLINE }, /* l_commitdate */ + { 53, 61, 9, FLD_INLINE }, /* l_receiptdate */ + { 62, 78, 17, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* l_shipinstruct */ + { 79, 85, 7, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* l_shipmode */ + { 86,128, 43, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* l_comment */ +}; + +/* Note setting of subname field */ +externdef struct tbl table = +{ + (text *)"scott", /* table owner */ + (text *)"lineitem_dp", /* table name */ + (text *)"lineitem1", /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024) /* transfer buffer size */ +}; + +externdef struct sess session = +{ + (text *)"scott", /* user */ + (text *)"tiger", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemdplp.c */ + diff --git a/cdemdplp.dat b/cdemdplp.dat new file mode 100644 index 0000000..4a65736 --- /dev/null +++ b/cdemdplp.dat @@ -0,0 +1,30 @@ + 115519 78511724386.67.04.02NO13-MAR-9612-FEB-9622-MAR-96DELIVER IN PERSONTRUCK iPBw4mMm7w7kQ zNPL i261OPP + 1 6731 73223658958.28.09.06NO12-APR-9628-FEB-9620-APR-96TAKE BACK RETURN MAIL 5wM04SNyl0AnghCP2nx lAi + 1 6370 3713 810210.96 .1.02NO29-JAN-9605-MAR-9631-JAN-96TAKE BACK RETURN REG AIRSQC2C 5PNCy4mM + 1 214 46542831197.88.09.06NO21-APR-9630-MAR-9616-MAY-96NONE AIR Om0L65CSAwSj5k6k + 1 1564 6763246897.92.07.02NO30-JAN-9607-FEB-9603-FEB-96DELIVER IN PERSONMAIL CB0SnyOL PQ32B70wB75k 6Aw10m0wh + 1 2403 160524 31329.6 .1.04NO30-MAR-9614-MAR-9601-APR-96NONE FOB C2gOQj OB6RLk1BS15 igN + 216819 82012441659.44 0.08NO05-MAR-9709-FEB-9711-MAR-97COLLECT COD AIR O52M70MRgRNnmm476mNm + 319451 721230 41113.5.05.01AF05-FEB-9429-DEC-9318-FEB-94TAKE BACK RETURN FOB 6wQnO0Llg6y + 310017 1834440788.44.07.03RF19-JAN-9423-DEC-9315-FEB-94TAKE BACK RETURN SHIP LhiA7wygz0k4g4zRhMLBAM + 3 444 1955 6 8066.64.04.01RF28-JAN-9415-DEC-9314-FEB-94TAKE BACK RETURN REG AIR6nmBmjQkgiCyzCQBkxPPOx5j4hB 0lRywgniP7 + 310617 13813858049.18 0.05AF11-DEC-9327-NOV-9316-DEC-93TAKE BACK RETURN RAIL 3AR yMS77lQ12kR + 3 4581 9043754966.46.09.05AF22-DEC-9328-DEC-9304-JAN-94DELIVER IN PERSONAIR jykM7l5S7xl6nin26jhn75C60kj2iQAgg + 319568 838635 52064.6.01.05RF23-DEC-9310-JAN-9413-JAN-94COLLECT COD RAIL nNMwmwnnji74jRnMPl0z41BgwCLjk7ANPQM + 416642 1751 4 6234.56 0.07NO10-JAN-9623-DEC-9523-JAN-96TAKE BACK RETURN SHIP jLS22n33Qw + 5 430 18114559869.35.06 0RF18-NOV-9420-OCT-9409-DEC-94NONE AIR MQR1NNRmlBx1ylCy3k7lBS0 + 5 1904 658249 88489.1 .1 0AF25-AUG-9405-OCT-9409-SEP-94TAKE BACK RETURN RAIL kAPQM67LOxSNlnimlM + 512845 37032747461.68.06.07RF01-NOV-9407-SEP-9408-NOV-94DELIVER IN PERSONSHIP CxQnkxC3xP zyiRBzj6wB30NnCi hx Q4y1OQ kg6P + 6 2938 1911 2 3681.86.01.06RF12-APR-9216-MAY-9210-MAY-92NONE TRUCK mzl027k3h7ANRiL2C + 718310 11512834392.68.04 0NO11-MAR-9607-APR-9629-MAR-96TAKE BACK RETURN FOB 7CjjL1PLCOnhgh + 7 3052 53338 36291.9.05.06NO05-FEB-9616-MAR-9629-FEB-96TAKE BACK RETURN MAIL kA2hOk7zy5PA0126AB2nwB22Amzh7kx1LSnCzikB67i + 719894 16451221766.68.05.05NO19-MAR-9628-FEB-9623-MAR-96TAKE BACK RETURN MAIL k5MQgQix5mRNgy5nk6Rk2zAQyB21AyLxw5hRBM5AO + 7 7581 582610 14885.8.01.03NO25-FEB-9625-FEB-9612-MAR-96TAKE BACK RETURN MAIL iL w 06ySPx + 717470 7387 7 9712.29.08.02NO27-MAR-9615-FEB-9608-APR-96TAKE BACK RETURN FOB Liz5AjP4g2kOP + 7 8804 579430 51384.03.08NO10-APR-9614-MAR-9618-APR-96DELIVER IN PERSONREG AIR2O0CNMzMNn5LM2A2SwnPn604 ghN641OBwCl6h5hyh6 + 7 6215 98422629151.46 .1.02NO25-JAN-9615-MAR-9631-JAN-96TAKE BACK RETURN RAIL AxnNxAyS50Sk + 32 6286 799115 17884.2.04.08NO04-SEP-9504-OCT-9510-SEP-95TAKE BACK RETURN SHIP 6nRBz7zn2gLgL3S2ligw51CQ4mn2 + 32 8280 53922327330.44.04.04NO01-OCT-9522-AUG-9504-OCT-95TAKE BACK RETURN FOB iOCwx0NQ1n44O2hg3PQ3ALQ ROy6y4N1g n6jLxh5 + 115510 78511724386.67.04.02NO13-MAR-9612-FEB-9622-MAR-96DELIVER IN PERSONTRUCK iPBw4mMm7w7kQ zNPL i261OPP + 1 6031 73223658958.28.09.06NO12-APR-9628-FEB-9620-APR-96TAKE BACK RETURN MAIL 5wM04SNyl0AnghCP2nx lAi + 11 6370 3713 810210.96 .1.02NO29-JAN-9605-MAR-9631-JAN-96TAKE BACK RETURN REG AIRSQC2C 5PNCy4mM diff --git a/cdemdplp.sql b/cdemdplp.sql new file mode 100644 index 0000000..7dbd20d --- /dev/null +++ b/cdemdplp.sql @@ -0,0 +1,83 @@ +rem +rem $Header: cdemdplp.sql 04-apr-2001.11:17:49 eegolf Exp $ +rem +rem cdemdplp.sql +rem +rem Copyright (c) 2001 Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemdplp.sql - C Demo Direct Path api for LineItem Partition table +rem +rem DESCRIPTION +rem - creates a lineitem partition tbl for loading data w/ direct path api +rem via direct path API. +rem - execute this script before running cdemodp driver +rem w/cdemdplp client. +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem eegolf 04/04/01 - Merged eegolf_demo_update +rem eegolf 03/04/01 - updated for 9i +rem cmlim 09/16/98 - Created +rem + +set echo off; +connect scott/tiger; + +rem for direct path +drop table LINEITEM_DP; +create table LINEITEM_DP + (L_ORDERKEY NUMBER, + L_PARTKEY NUMBER, + L_SUPPKEY NUMBER, + L_LINENUMBER NUMBER, + L_QUANTITY NUMBER, + L_EXTENDEDPRICE NUMBER, + L_DISCOUNT NUMBER, + L_TAX NUMBER, + L_RETURNFLAG CHAR(1), + L_LINESTATUS CHAR(1), + L_SHIPDATE DATE, + L_COMMITDATE DATE, + L_RECEIPTDATE DATE, + L_SHIPINSTRUCT VARCHAR2(25), + L_SHIPMODE VARCHAR2(10), + L_COMMENT VARCHAR2(44)) + partition by range (L_ORDERKEY) + (partition LINEITEM1 values less than (12250) , + partition LINEITEM2 values less than (24500) , + partition LINEITEM3 values less than (36750) , + partition LINEITEM4 values less than (49000) , + partition LINEITEM5 values less than (61250) , + partition LINEITEM6 values less than (73500) , + partition LINEITEM7 values less than (maxvalue) ); + +rem for conventional path +drop table LINEITEM_CV; +create table LINEITEM_CV + (L_ORDERKEY NUMBER, + L_PARTKEY NUMBER, + L_SUPPKEY NUMBER, + L_LINENUMBER NUMBER, + L_QUANTITY NUMBER, + L_EXTENDEDPRICE NUMBER, + L_DISCOUNT NUMBER, + L_TAX NUMBER, + L_RETURNFLAG CHAR(1), + L_LINESTATUS CHAR(1), + L_SHIPDATE DATE, + L_COMMITDATE DATE, + L_RECEIPTDATE DATE, + L_SHIPINSTRUCT VARCHAR2(25), + L_SHIPMODE VARCHAR2(10), + L_COMMENT VARCHAR2(44)) + partition by range (L_ORDERKEY) + (partition LINEITEM1 values less than (12250) , + partition LINEITEM2 values less than (24500) , + partition LINEITEM3 values less than (36750) , + partition LINEITEM4 values less than (49000) , + partition LINEITEM5 values less than (61250) , + partition LINEITEM6 values less than (73500) , + partition LINEITEM7 values less than (maxvalue) ); + +exit; diff --git a/cdemdpno.c b/cdemdpno.c new file mode 100644 index 0000000..f4d2a2e --- /dev/null +++ b/cdemdpno.c @@ -0,0 +1,157 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemdpno.c 15-aug-2006.10:06:59 jkaloger Exp $ "; +#endif /* RCSID */ + +/* +** Copyright (c) 2001 Oracle Corporation. All rights reserved. +*/ + +/* +** Directions: +** 1. make -f demo_rdbms.mk build_dp EXE=cdemdpno OBJS=cdemdpno.o +** makes the cdemdpno executable +** 2. sqlplus OE/OE @cdemdp9i.sql +** creates the Oracle 9.0 types tbl +** 3. cdemdpno < cdemdpno.dat +** runs the executable +** 4. to retrieve data, select from "dp_api_demo1" as "OE/OE" +** +*/ + +/* + NAME + cdemdpno.c - An example C program that loads a nested column + object via Direct Path API. + + DESCRIPTION + A client module to be used with the cdemodp.c driver. + + NOTES + This module loads selected types as defined in the Sample Schema. + Refer to Cdemdp9i.sql for more information on the use of the + Sample Schema with the DP API demo modules. + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + cmlim 09/11/01 - fix lint + eegolf 04/04/01 - Merged eegolf_demo_update + eegolf 03/27/01 - Creation + */ + +#include +#include +#include + +externdef struct col objx_02_col [] = +{ + { + (text *)"warehouse_id", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"warehouse_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"location_id", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + } +}; + +externdef struct fld objx_02_fld [] = +{ + { 45, 47, 3, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* warehouse_id */ + { 48, 82, 35, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* warehouse_name */ + { 83, 86, 4, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* location_id */ +}; + +externdef struct obj warehouse_typ = +{ + (text *) "WAREHOUSE_TYP", 3, objx_02_col, objx_02_fld, 0, 0, + (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_OBJ}; + + +externdef struct col objx_01_col [] = +{ + { + (text *)"product_id", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"warehouse", 0, SQLT_NTY, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, &warehouse_typ + }, + { + (text *)"quantity_on_hand", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + } +}; + +externdef struct fld objx_01_fld [] = +{ + { 26, 31, 6, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* product_id */ + { 32, 36, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* warehouse */ + { 37, 44, 8, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* quantiti_on_hand */ +}; + +externdef struct obj inventory_typ = +{ + (text *) "INVENTORY_TYP", 3, objx_01_col, objx_01_fld, 0, 0, + (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_OBJ}; + + +externdef struct col column[] = +{ + { + (text *)"cust_first_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"cust_last_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"current_inventory", 0, SQLT_NTY, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, & inventory_typ + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 10, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_first_name */ + { 11,20, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_last_name */ + { 21,25, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* current_inventory */ +}; + + +externdef struct tbl table = +{ + (text *)"OE", /* table owner */ + (text *)"dp_api_demo1", /* table name */ + (text *)"" , /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024) /* transfer buffer size */ +}; + +externdef struct sess session = +{ + (text *)"oe", /* user */ + (text *)"oe", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemdpno.c */ + diff --git a/cdemdpno.dat b/cdemdpno.dat new file mode 100644 index 0000000..ffc18e8 --- /dev/null +++ b/cdemdpno.dat @@ -0,0 +1,10 @@ +fredrich lawson 1 666666 188888888123Plainfield road parts and pieces 4444 +pamela smith 1 555555 177777777222Plainfield road parts and pieces 4444 +james thyson 1 777777 166666666333Plainfield road parts and pieces 4444 +barbara sweeney 1 888888 155555555444Plainfield road parts and pieces 4444 +richard jacobs 1 999999 144444444555Plainfield road parts and pieces 4444 +mary miller 1 222222 122222222666Plainfield road parts and pieces 4444 +franklin ford 333333 199999999777Plainfield road parts and pieces 4444 +jessica patrick 1 444444 188888888111Plainfield road parts and pieces 4444 +john wang 1 555555 77777777333Plainfield road parts and pieces 4444 +peter barnes 1 666666 122222222333Plainfield road parts and pieces 4444 diff --git a/cdemdpro.c b/cdemdpro.c new file mode 100644 index 0000000..88b2385 --- /dev/null +++ b/cdemdpro.c @@ -0,0 +1,132 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemdpro.c 15-aug-2006.10:07:25 jkaloger Exp $ "; +#endif /* RCSID */ + +/* +** Copyright (c) 2001 Oracle Corporation. All rights reserved. +*/ + +/* +** Directions: +** 1. make -f demo_rdbms.mk build_dp EXE=cdemdpro OBJS=cdemdpro +** makes the cdemdpro executable +** 2. sqlplus OE/OE @cdemdp9i.sql +** creates the Oracle 9.0 types tbl +** 2a. sqlldr OE/OE cdemdpro.ctl +** loads the dp_api_demo2 table. +** 3. cdemdpro < cdemdpro.dat +** runs the executable +** 4. to retrieve data, select from "dp_api_demo1" as "OE/OE" +** +*/ + +/* + NAME + cdemdpro.c - An example C program that loads a reference object + via Direct Path API. Table name is in .dat file. + The refs point to objects in the dp_api_demo2 table. + + DESCRIPTION + A client module to be used with the cdemodp.c driver. + + NOTES + This module loads selected types as defined in the Sample Schema. + Refer to Cdemdp9i.sql for more information on the use of the + Sample Schema with the DP API demo modules. + + IMPORTANT + This module requires running cdemdpro.ctl in sql*loader to load + warehouse_typ table. + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + cmlim 09/11/01 - fix lint + eegolf 04/04/01 - Merged eegolf_demo_update + eegolf 04/03/01 - + eegolf 03/28/01 - Creation + */ + +#include +#include +#include + + +externdef struct col objx_01_col [] = +{ + { + (text *)"ref_tbl", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"sys_oid", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + } +}; + +externdef struct fld objx_01_fld [] = +{ + { 26, 40, 15, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* ref_tbl */ + { 41, 72, 32, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* sys_oid */ +}; + +externdef struct obj warehouse_typ = +{ + (text *)0, 2, objx_01_col, objx_01_fld, 0, 0, + (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_REF}; + + +externdef struct col column[] = +{ + { + (text *)"cust_first_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"cust_last_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"inventory_warehouse", 0, SQLT_REF, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, & warehouse_typ + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 10, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_first_name */ + { 11,20, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_last_name */ + { 21,25, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* inventory_warehouse */ +}; + + +externdef struct tbl table = +{ + (text *)"OE", /* table owner */ + (text *)"dp_api_demo1", /* table name */ + (text *)"" , /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024) /* transfer buffer size */ +}; + +externdef struct sess session = +{ + (text *)"oe", /* user */ + (text *)"oe", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemdpro.c */ + diff --git a/cdemdpro.ctl b/cdemdpro.ctl new file mode 100644 index 0000000..5cb7f64 --- /dev/null +++ b/cdemdpro.ctl @@ -0,0 +1,21 @@ +-- Load the dp_api_demo2 table specifying OIDs. + + +load data +infile * + +into table dp_api_demo2 +replace +oid (name_oid) +( +name_oid FILLER position(1:32), +warehouse_id position(33:35), +warehouse_name position(36:70), +location_id position(71:74) +) + + +BEGINDATA +78686CC3AEE15A4DE034080020A3EC15123plainville warehouse parts_one 1234 +78686CC3AEE25A4DE034080020A3EC15222plainville warehouse parts_two 1212 +78686CC3AEE35A4DE034080020A3EC15333plainville warehouse pieces_one 2323 diff --git a/cdemdpro.dat b/cdemdpro.dat new file mode 100644 index 0000000..30fa74b --- /dev/null +++ b/cdemdpro.dat @@ -0,0 +1,10 @@ +fredrich lawson 1 dp_api_demo2 78686CC3AEE15A4DE034080020A3EC15 +pamela smith 1 dp_api_demo2 78686CC3AEE25A4DE034080020A3EC15 +james thyson 1 dp_api_demo2 78686CC3AEE35A4DE034080020A3EC15 +barbara sweeney 1 dp_api_demo2 78686CC3AEE15A4DE034080020A3EC15 +richard jacobs dp_api_demo2 78686CC3AEE25A4DE034080020A3EC15 +mary miller 1 dp_api_demo2 78686CC3AEE35A4DE034080020A3EC15 +franklin ford 1 dp_api_demo2 78686CC3AEE15A4DE034080020A3EC15 +jessica patrick 1 dp_api_demo2 78686CC3AEE25A4DE034080020A3EC15 +john wang 1 dp_api_demo2 78686CC3AEE35A4DE034080020A3EC15 +peter barnes 1 dp_api_demo2 78686CC3AEE35A4DE034080020A3EC15 diff --git a/cdemdpss.c b/cdemdpss.c new file mode 100644 index 0000000..b8ecad1 --- /dev/null +++ b/cdemdpss.c @@ -0,0 +1,172 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemdpss.c 15-aug-2006.10:07:47 jkaloger Exp $ "; +#endif /* RCSID */ + +/* +** Copyright (c) 2001 Oracle Corporation. All rights reserved. +*/ + +/* +** Directions: +** 1. make -f demo_rdbms.mk build_dp EXE=cdemdpss OBJS=cdemdpss.o +** makes the cdemdpss executable +** 2. sqlplus OE/OE @cdemdp9i.sql +** creates the Oracle 9.0 types tbl +** 3. cdemdpss < cdemdpss.dat +** runs the executable +** 4. to retrieve data, select from "dp_api_demo1" as "OE/OE" +** +*/ + +/* + NAME + cdemdpss.c - An example C program that loads a sql string + via Direct Path API. + + DESCRIPTION + A client module to be used with the cdemodp.c driver. + + NOTES + This module loads selected types as defined in the Sample Schema. + Refer to Cdemdp9i.sql for more information on the use of the + Sample Schema with the DP API demo modules. + + IMPORTANT + Argument names to opaques and sql strings must be unique. + + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + cmlim 09/11/01 - fix lint + eegolf 04/04/01 - Merged eegolf_demo_update + eegolf 03/28/01 - Creation + */ + +#include +#include +#include + + +externdef struct obj inventory_stock_date = +{ + (text *) "sysdate", 0, 0, 0, 0, 0, + (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_OPQ}; + + + +externdef struct col objx_02_col [] = +{ + { + (text *)"name_str2_arg1", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + } +}; + +externdef struct fld objx_02_fld [] = +{ + { 66, 67, 2, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* name_str2, arg1 */ +}; + + + +externdef struct obj name_str2 = +{ + (text *) "lower(add_months(sysdate, :name_str2_arg1))", 1, objx_02_col, + objx_02_fld, 0, 0, (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_OPQ}; + + +externdef struct col objx_01_col [] = +{ + { + (text *)"name_str_arg1", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"name_str_arg2", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"name_str_arg3", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + } +}; + +externdef struct fld objx_01_fld [] = +{ + { 36, 55,20, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* name_str, arg1 */ + { 56, 60, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* name_str, arg2 */ + { 61, 65, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* name_str, arg3 */ +}; + +externdef struct obj name_str = +{ + (text *) "substr(:name_str_arg1, :name_str_arg2, :name_str_arg3)", 3, + objx_01_col, objx_01_fld, 0, 0, + (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_OPQ}; + + +externdef struct col column[] = +{ + { + (text *)"cust_first_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"cust_last_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"inventory_string", 0, SQLT_NTY, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, & name_str + }, + { + (text *)"inventory_string2", 0, SQLT_NTY, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, & name_str2 + }, + { + (text *)"inventory_stock_date", 0, SQLT_NTY, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, & inventory_stock_date + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 10, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_first_name */ + { 11,20, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_last_name */ + { 21,25, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* inventory_string */ + { 26,30, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* inventory_string2 */ + { 31,35, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* inventory_stock_date */ +}; + + +externdef struct tbl table = +{ + (text *)"OE", /* table owner */ + (text *)"dp_api_demo1", /* table name */ + (text *)"" , /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024) /* transfer buffer size */ +}; + +externdef struct sess session = +{ + (text *)"oe", /* user */ + (text *)"oe", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemdpss.c */ + diff --git a/cdemdpss.dat b/cdemdpss.dat new file mode 100644 index 0000000..706be5b --- /dev/null +++ b/cdemdpss.dat @@ -0,0 +1,10 @@ +fredrich lawson 1 1 1 this is a demo 1 4 1 +pamela smith 1 1 1 this is a demo 1 7 2 +james thyson 1 1 this is a demo 1 9 3 +barbara sweeney 1 1 this is a demo 1 14 1 +richard jacobs 1 1 this is a demo 1 14 2 +mary miller 1 1 1 this is a demo 1 9 3 +franklin ford 1 1 1 this is a demo 1 7 1 +jessica patrick 1 1 1 this is a demo 1 4 2 +john wang 1 1 1 this is a demo 1 4 3 +peter barnes 1 1 1 this is a demo 1 7 1 diff --git a/cdemo1.c b/cdemo1.c new file mode 100644 index 0000000..ddd7959 --- /dev/null +++ b/cdemo1.c @@ -0,0 +1,415 @@ +/* Copyright (c) 1991, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + cdemo1.c - C Demo Program + MODIFIED (MM/DD/YY) + azhao 10/11/06 - case-senstive password change + kmohan 03/28/06 - change hda to size_t + emendez 09/13/00 - fix top 5 olint errors + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 01/05/96 - Creation of the Solaris version with hda as + ub4 array of HDA_SIZE/sizeof(ub4) for alignment + reasons. +*/ +/* + * -- cdemo1.c -- + * An example program which adds new employee + * records to the personnel data base. Checking + * is done to insure the integrity of the data base. + * The employee numbers are automatically selected using + * the current maximum employee number as the start. + * + * The program queries the user for data as follows: + * + * Enter employee name: + * Enter employee job: + * Enter employee salary: + * Enter employee dept: + * + * The program terminates if return key (CR) is entered + * when the employee name is requested. + * + * If the record is successfully inserted, the following + * is printed: + * + * "ename" added to department "dname" as employee # "empno" + * + * The size of the HDA is defined by the HDA_SIZE constant, + * which is declared in ocidem.h to be 256 bytes for 32- + * bit architectures and 512 bytes for 64-bit architectures. + */ + +#include +#include +#include +#include + + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + + +text *username = (text *) "SCOTT"; +text *password = (text *) "tiger"; + +/* Define SQL statements to be used in program. */ +text *insert = (text *) "INSERT INTO emp(empno, ename, job, sal, deptno)\ + VALUES (:empno, :ename, :job, :sal, :deptno)"; +text *seldept = (text *) "SELECT dname FROM dept WHERE deptno = :1"; +text *maxemp = (text *) "SELECT NVL(MAX(empno), 0) FROM emp"; +text *selemp = (text *) "SELECT ename, job FROM emp"; + +/* Define an LDA, a HDA, and two cursors. */ +Lda_Def lda; +size_t hda[HDA_SIZE/sizeof(size_t)]; +Cda_Def cda1; +Cda_Def cda2; + + +void err_report(); +void do_exit(); +void myfflush(); + + + +main() +{ + sb4 empno, sal, deptno; + sb4 len, len2, rv, dsize, dsize2; + sb4 enamelen, joblen, deptlen; + sb2 sal_ind, job_ind; + sb2 db_type, db2_type; + sb1 name_buf[20], name2_buf[20]; + text *cp, *ename, *job, *dept; + +/* + * Connect to ORACLE and open two cursors. + * Exit on any error. + */ + if (olog(&lda, (ub1 *)hda, username, -1, password, -1, + (text *) 0, -1, (ub4)OCI_LM_DEF)) + { + err_report(&lda); + exit(EXIT_FAILURE); + } + printf("Connected to ORACLE as %s\n", username); + + if (oopen(&cda1, &lda, (text *) 0, -1, -1, (text *) 0, -1)) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + if (oopen(&cda2, &lda, (text *) 0, -1, -1, (text *) 0, -1)) + { + err_report(&cda2); + do_exit(EXIT_FAILURE); + } + + /* Turn off auto-commit. Default is off, however. */ + if (ocof(&lda)) + { + err_report(&lda); + do_exit(EXIT_FAILURE); + } + + /* Retrieve the current maximum employee number. */ + if (oparse(&cda1, maxemp, (sb4) -1, DEFER_PARSE, + (ub4) VERSION_7)) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + if (odefin(&cda1, 1, (ub1 *) &empno, (sword) sizeof(sword), + (sword) INT_TYPE, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + if (oexfet(&cda1, (ub4) 1, FALSE, FALSE)) + { + if (cda1.rc == NO_DATA_FOUND) + empno = 10; + else + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + } + + /* Describe the columns in the select-list + of "selemp" to determine the max length of + the employee name and job title. + */ + if (oparse(&cda1, selemp, (sb4) -1, FALSE, (ub4)VERSION_7)) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + + len = sizeof(name_buf); len2 = sizeof (name2_buf); + if (odescr(&cda1, 1, &enamelen, + (sb2 *) &db_type, name_buf, (sb4 *) &len, + (sb4 *) &dsize, (sb2 *) 0, (sb2 *) 0, (sb2 *) 0) || + odescr(&cda1, 2, &joblen, + (sb2 *) &db_type, name2_buf, (sb4 *) &len2, + (sb4 *) &dsize2, (sb2 *) 0, (sb2 *) 0, (sb2 *) 0)) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + + /* Parse the INSERT statement. */ + if (oparse(&cda1, insert, (sb4) -1, FALSE, (ub4) VERSION_7)) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + + /* Parse the SELDEPT statement. */ + if (oparse(&cda2, seldept, (sb4) -1, FALSE, (ub4) VERSION_7)) + { + err_report(&cda2); + do_exit(EXIT_FAILURE); + } + + /* Allocate output buffers. Allow for \n and '\0'. */ + ename = (text *) malloc((int) enamelen + 2); + job = (text *) malloc((int) joblen + 2); + + /* Bind the placeholders in the INSERT statement. */ + if (obndrv(&cda1, (text *) ":ENAME", -1, (ub1 *) ename, + enamelen+1, STRING_TYPE, -1, (sb2 *) 0, + (text *) 0, -1, -1) || + obndrv(&cda1, (text *) ":JOB", -1, (ub1 *) job, joblen+1, + STRING_TYPE, -1, &job_ind, (text *) 0, -1, -1) || + obndrv(&cda1, (text *) ":SAL", -1, (ub1 *) &sal, (sword) sizeof (sal), + INT_TYPE, -1, &sal_ind, (text *) 0, -1, -1) || + obndrv(&cda1, (text *) ":DEPTNO",-1, (ub1 *) &deptno, + (sword) sizeof (deptno), INT_TYPE, -1, + (sb2 *) 0, (text *) 0, -1, -1) || + obndrv(&cda1, (text *) ":EMPNO", -1, (ub1 *) &empno, + (sword) sizeof (empno), INT_TYPE, -1, + (sb2 *) 0, (text *) 0, -1, -1)) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + + /* Bind the placeholder in the "seldept" statement. */ + if (obndrn(&cda2, + 1, + (ub1 *) &deptno, + (sword) sizeof(deptno), + INT_TYPE, + -1, + (sb2 *) 0, + (text *) 0, + -1, + -1)) + { + err_report(&cda2); + do_exit(EXIT_FAILURE); + } + + /* Describe the select-list field "dname". */ + len = sizeof (name_buf); + if (odescr(&cda2, 1, (sb4 *) &deptlen, &db_type, + name_buf, (sb4 *) &len, (sb4 *) &dsize, (sb2 *) 0, + (sb2 *) 0, (sb2 *) 0)) + { + err_report(&cda2); + do_exit(EXIT_FAILURE); + } + +/* Allocate the dept buffer now that you have length. */ + dept = (text *) malloc((int) deptlen + 1); + + /* Define the output variable for the select-list. */ + if (odefin(&cda2, + 1, + (ub1 *) dept, + deptlen+1, + STRING_TYPE, + -1, + (sb2 *) 0, + (text *) 0, + -1, + -1, + (ub2 *) 0, + (ub2 *) 0)) + { + err_report(&cda2); + do_exit(EXIT_FAILURE); + } + + for (;;) + { + /* Prompt for employee name. Break on no name. */ + printf("\nEnter employee name (or CR to EXIT): "); + fgets((char *) ename, (int) enamelen+1, stdin); + cp = (text *) strchr((char *) ename, '\n'); + if (cp == ename) + { + printf("Exiting... "); + do_exit(EXIT_SUCCESS); + } + if (cp) + *cp = '\0'; + else + { + printf("Employee name may be truncated.\n"); + myfflush(); + } + /* Prompt for the employee's job and salary. */ + printf("Enter employee job: "); + job_ind = 0; + fgets((char *) job, (int) joblen + 1, stdin); + cp = (text *) strchr((char *) job, '\n'); + if (cp == job) + { + job_ind = -1; /* make it NULL in table */ + printf("Job is NULL.\n");/* using indicator variable */ + } + else if (cp == 0) + { + printf("Job description may be truncated.\n"); + myfflush(); + } + else + *cp = '\0'; + + printf("Enter employee salary: "); + scanf("%d", &sal); + myfflush(); + sal_ind = (sal <= 0) ? -2 : 0; /* set indicator variable */ + + /* + * Prompt for the employee's department number, and verify + * that the entered department number is valid + * by executing and fetching. + */ + do + { + printf("Enter employee dept: "); + scanf("%d", &deptno); + myfflush(); + if (oexec(&cda2) || + (ofetch(&cda2) && (cda2.rc != NO_DATA_FOUND))) + { + err_report(&cda2); + do_exit(EXIT_FAILURE); + } + if (cda2.rc == NO_DATA_FOUND) + printf("The dept you entered doesn't exist.\n"); + } while (cda2.rc == NO_DATA_FOUND); + + /* + * Increment empno by 10, and execute the INSERT + * statement. If the return code is 1 (duplicate + * value in index), then generate the next + * employee number. + */ + empno += 10; + if (oexec(&cda1) && cda1.rc != 1) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + while (cda1.rc == 1) + { + empno += 10; + if (oexec(&cda1) && cda1.rc != 1) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + } /* end for (;;) */ + +/* Commit the change. */ + if (ocom(&lda)) + { + err_report(&lda); + do_exit(EXIT_FAILURE); + } + printf( + "\n\n%s added to the %s department as employee number %d\n", + ename, dept, empno); + } + do_exit(EXIT_SUCCESS); + +} + + +void +err_report(cursor) + Cda_Def *cursor; +{ + sword n; + text msg[512]; + + printf("\n-- ORACLE error--\n"); + printf("\n"); + n = oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + if (cursor->fc > 0) + fprintf(stderr, "Processing OCI function %s", + oci_func_tab[cursor->fc]); +} + + +/* + * Exit program with an exit code. + */ +void do_exit(exit_code) + sword exit_code; +{ + sword error = 0; + + if (oclose(&cda1)) + { + fprintf(stderr, "Error closing cursor 1.\n"); + error++; + } + if (oclose(&cda2)) + { + fprintf(stderr, "Error closing cursor 2.\n"); + error++; + } + if (ologof(&lda)) + { + fprintf(stderr, "Error on disconnect.\n"); + error++; + } + if (error == 0 && exit_code == EXIT_SUCCESS) + printf ("\nG'day\n"); + + exit(exit_code); +} + + +void myfflush() +{ + eb1 buf[50]; + + fgets((char *) buf, 50, stdin); +} + + diff --git a/cdemo2.c b/cdemo2.c new file mode 100644 index 0000000..fdf13b9 --- /dev/null +++ b/cdemo2.c @@ -0,0 +1,509 @@ +/* Copyright (c) 1991, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + cdemo2.c - C demo Program # 2 + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + echen 03/11/97 - fix a test bug + dchatter 01/05/96 - Creation of the Solaris version with hda as + ub4 array of HDA_SIZE/sizeof(ub4) for alignment + reasons. +*/ + +/* This program accepts arbitrary SQL statements from the user, + and processes the statement. Statements may be entered on + multiple lines, and must be terminated by a semi-colon. + If a query, the results are printed. + + Statements are entered at the OCISQL prompt. + + To quit the program, type EXIT at the OCISQL prompt. + + The size of the HDA is defined by the HDA_SIZE constant, + which is declared in ocidem.h to be 256 bytes for 32- + bit architectures and 512 bytes for 64-bit architectures. +*/ + +#include +#include +#include + + +/* Include OCI-specific headers. */ +#include +#include +#ifdef __STDC__ +#include +#else +#include +#endif +#include + + +/* Constants used in this program. */ +#define MAX_BINDS 12 +#define MAX_ITEM_BUFFER_SIZE 33 +#define MAX_SELECT_LIST_SIZE 12 +#define MAX_SQL_IDENTIFIER 31 + +#define PARSE_NO_DEFER 0 +#define PARSE_V7_LNG 2 + + +/* Define one logon data area and one cursor data area + Also define a host data area for olog. + (See ocidfn.h for declarations). */ +Lda_Def lda; +Cda_Def cda; +size_t hda[HDA_SIZE/sizeof(size_t)]; + +/* Declare an array of bind values. */ +text bind_values[MAX_BINDS][MAX_ITEM_BUFFER_SIZE]; + +/* Declare structures for query information. */ +struct describe +{ + sb4 dbsize; + sb2 dbtype; + sb1 buf[MAX_ITEM_BUFFER_SIZE]; + sb4 buflen; + sb4 dsize; + sb2 precision; + sb2 scale; + sb2 nullok; +}; + +struct define +{ + ub1 buf[MAX_ITEM_BUFFER_SIZE]; + float flt_buf; + sword int_buf; + sb2 indp; + ub2 col_retlen, col_retcode; +}; + + +/* Define arrays of describe and define structs. */ +struct describe desc[MAX_SELECT_LIST_SIZE]; +struct define def[MAX_SELECT_LIST_SIZE]; + +/* Declare this programs functions. */ +sword connect_user(); +sword describe_define(); +sword do_binds(); +void do_exit(); +void oci_error(); +sword get_sql_statement(); +void print_header(); +void print_rows(); + +/* Globals */ +static text sql_statement[2048]; +static sword sql_function; +static sword numwidth = 8; + + +main() +{ + sword col, errno, n, ncols; + text *cp; + + /* Connect to ORACLE. */ + if (connect_user()) + exit(-1); + + /* Open a cursor, exit on error (unrecoverable). */ + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) + { + printf("Error opening cursor. Exiting...\n"); + ologof(&lda); + exit(-1); + } + + /* Process user's SQL statements. */ + + for (;;) + { + /* Get the statement, exit on "exit". */ + if (get_sql_statement()) { + printf("\n"); + do_exit(0); + } + + /* Parse the statement; do not defer the parse, + so that errors come back right away. */ + if (oparse(&cda, (text *) sql_statement, (sb4) -1, + (sword) PARSE_NO_DEFER, (ub4) PARSE_V7_LNG)) + { + oci_error(&cda); + continue; + } + + /* Save the SQL function code right after parse. */ + sql_function = cda.ft; + + /* Bind any input variables. */ + if ((ncols = do_binds(&cda, sql_statement)) == -1) + continue; + + /* If the statement is a query, describe and define + all select-list items before doing the oexec. */ + if (sql_function == FT_SELECT) + if ((ncols = describe_define(&cda)) == -1) + continue; + + /* Execute the statement. */ + if (oexec(&cda)) + { + oci_error(&cda); + continue; + } + + /* Fetch and display the rows for the query. */ + if (sql_function == FT_SELECT) + { + print_header(ncols); + print_rows(&cda, ncols); + } + + /* Print the rows-processed count. */ + if (sql_function == FT_SELECT || + sql_function == FT_UPDATE || + sql_function == FT_DELETE || + sql_function == FT_INSERT) + printf("\n%d row%c processed.\n", cda.rpc, + cda.rpc == 1 ? ' ' : 's'); + else + printf("\nStatement processed.\n"); + + } /* end for (;;) */ + + +} /* end main() */ + + +sword +connect_user() +{ + text username[132]; + text password[132]; + sword n; + + /* Three tries to connect. */ + for (n = 3; --n >= 0; ) + { + printf("Username: "); + gets((char *) username); + printf("Password: "); + gets((char *) password); + + if (olog(&lda, (ub1 *)hda, username, -1, password, -1, + (text *) 0, -1, (ub4)OCI_LM_DEF)) + { + printf("Cannot connect as %s.\n", username); + printf("Try again.\n\n"); + } + else + { + return 0; + } + } + printf("Connection failed. Exiting...\n"); + return -1; +} + + +/* Describe select-list items. */ + +sword +describe_define(cda) +Cda_Def *cda; +{ + sword col, deflen, deftyp; + static ub1 *defptr; + + /* Describe the select-list items. */ + for (col = 0; col < MAX_SELECT_LIST_SIZE; col++) + { + desc[col].buflen = MAX_ITEM_BUFFER_SIZE; + if (odescr(cda, col + 1, &desc[col].dbsize, + &desc[col].dbtype, &desc[col].buf[0], + &desc[col].buflen, &desc[col].dsize, + &desc[col].precision, &desc[col].scale, + &desc[col].nullok)) + { + /* Break on end of select list. */ + if (cda->rc == VAR_NOT_IN_LIST) + break; + else + { + oci_error(cda); + return -1; + } + } + /* adjust sizes and types for display */ + switch (desc[col].dbtype) + { + case NUMBER_TYPE: + desc[col].dbsize = numwidth; + /* Handle NUMBER with scale as float. */ + if (desc[col].scale != 0) + { + defptr = (ub1 *) &def[col].flt_buf; + deflen = (sword) sizeof(float); + deftyp = FLOAT_TYPE; + desc[col].dbtype = FLOAT_TYPE; + } + else + { + defptr = (ub1 *) &def[col].int_buf; + deflen = (sword) sizeof(sword); + deftyp = INT_TYPE; + desc[col].dbtype = INT_TYPE; + } + break; + default: + if (desc[col].dbtype == DATE_TYPE) + desc[col].dbsize = 9; + if (desc[col].dbtype == ROWID_TYPE) + desc[col].dbsize = 18; + defptr = def[col].buf; + deflen = desc[col].dbsize > MAX_ITEM_BUFFER_SIZE ? + MAX_ITEM_BUFFER_SIZE : desc[col].dbsize + 1; + deftyp = STRING_TYPE; + break; + } + if (odefin(cda, col + 1, + defptr, deflen, deftyp, + -1, &def[col].indp, (text *) 0, -1, -1, + &def[col].col_retlen, + &def[col].col_retcode)) + { + oci_error(cda); + return -1; + } + } + return col; +} + + +/* Bind input variables. */ + +sword +do_binds(cda, stmt_buf) +Cda_Def *cda; +text *stmt_buf; +{ + sword i, in_literal, n; + text *cp, *ph; + + /* Find and bind input variables for placeholders. */ + for (i = 0, in_literal = FALSE, cp = stmt_buf; + *cp && i < MAX_BINDS; cp++) + { + if (*cp == '\'') + in_literal = ~in_literal; + if (*cp == ':' && !in_literal) + { + for (ph = ++cp, n = 0; + *cp && (isalnum(*cp) || *cp == '_') + && n < MAX_SQL_IDENTIFIER; + cp++, n++ + ) + ; + *cp = '\0'; + printf("Enter value for %s: ", ph); + gets((char *) &bind_values[i][0]); + + /* Do the bind, using obndrv(). + NOTE: the bind variable address must be static. + This would not work if bind_values were an + auto on the do_binds stack. */ + if (obndrv(cda, ph, -1, (ub1 *)&bind_values[i][0], -1, + VARCHAR2_TYPE, + -1, (sb2 *) 0, (text *) 0, -1, -1)) + { + oci_error(cda); + return -1; + } + i++; + } /* end if (*cp == ...) */ + } /* end for () */ + return i; +} + + + +/* Clean up and exit. LDA and CDA are + global. */ +void +do_exit(rv) +sword rv; +{ + if (oclose(&cda)) + fputs("Error closing cursor!\n", stdout); + if (ologof(&lda)) + fputs("Error logging off!\n", stdout); + exit(rv); +} + + +void +oci_error(cda) +Cda_Def *cda; +{ + text msg[512]; + sword n; + + fputs("\n-- ORACLE ERROR --\n", stderr); + n = oerhms(&lda, cda->rc, msg, (sword) sizeof (msg)); + fprintf(stderr, "%.*s", n, msg); + fprintf(stderr, "Processing OCI function %s\n", + oci_func_tab[cda->fc]); + fprintf(stderr, "Do you want to continue? [yn]: "); + fgets((char *) msg, (int) sizeof (msg), stdin); + if (*msg != '\n' && *msg != 'y' && *msg != 'Y') + do_exit(1); + fputc('\n', stdout); +} + + +sword +get_sql_statement() +{ + text cbuf[1024]; + text *cp; + sword stmt_level; + + + for (stmt_level = 1; ;) + { + if (stmt_level == 1) + { + /* Init statement buffer and print prompt. */ + *sql_statement = '\0'; + fputs("\nOCISQL> ", stdout); + } + else + { + printf("%3d ", stmt_level); + } + + /* Get (part of) a SQL statement. */ + gets((char *) cbuf); + if (*cbuf == '\0') + continue; + if (strncmp((char *) cbuf, "exit", 4) == 0) + return -1; + + /* Concatenate to statement buffer. */ + if (stmt_level > 1) + strcat((char *) sql_statement, " "); + strcat((char *) sql_statement, (char *) cbuf); + + /* Check for possible terminator. */ + cp = &sql_statement[strlen((char *) sql_statement) - 1]; + + while (isspace(*cp)) + cp--; + if (*cp == ';') + { + *cp = '\0'; + break; + } + stmt_level++; + } + return 0; +} + + +void +print_header(ncols) +sword ncols; +{ + sword col, n; + + fputc('\n', stdout); + + for (col = 0; col < ncols; col++) + { + n = desc[col].dbsize - desc[col].buflen; + if (desc[col].dbtype == FLOAT_TYPE || + desc[col].dbtype == INT_TYPE) + { + printf("%*c", n, ' '); + printf("%*.*s", desc[col].buflen, + desc[col].buflen, desc[col].buf); + } + else + { + printf("%*.*s", desc[col].buflen, + desc[col].buflen, desc[col].buf); + printf("%*c", n, ' '); + } + fputc(' ', stdout); + } + fputc('\n', stdout); + + for (col = 0; col < ncols; col++) + { + for (n = desc[col].dbsize; --n >= 0; ) + fputc('-', stdout); + fputc(' ', stdout); + } + fputc('\n', stdout); +} + + +void +print_rows(cda, ncols) +Cda_Def *cda; +sword ncols; +{ + sword col, n; + + for (;;) + { + fputc('\n', stdout); + /* Fetch a row. Break on end of fetch, + disregard null fetch "error". */ + if (ofetch(cda)) + { + if (cda->rc == NO_DATA_FOUND) + break; + if (cda->rc != NULL_VALUE_RETURNED) + oci_error(cda); + } + for (col = 0; col < ncols ; col++) + { + /* Check col. return code for null. If + null, print n spaces, else print value. */ + if (def[col].indp < 0) + printf("%*c", desc[col].dbsize, ' '); + else + { + switch (desc[col].dbtype) + { + case FLOAT_TYPE: + printf("%*.*f", numwidth, 2, def[col].flt_buf); + break; + case INT_TYPE: + printf("%*d", numwidth, def[col].int_buf); + break; + default: + printf("%s", def[col].buf); + n = desc[col].dbsize - strlen((char *) def[col].buf); + if (n > 0) + printf("%*c", n, ' '); + break; + } + } + fputc(' ', stdout); + } + } /* end for (;;) */ +} + diff --git a/cdemo3.c b/cdemo3.c new file mode 100644 index 0000000..142c7a5 --- /dev/null +++ b/cdemo3.c @@ -0,0 +1,292 @@ +/* Copyright (c) 1991, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + cdemo3.c - C demo program # 3 + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 01/05/96 - Creation of the Solaris version with hda as + ub4 array of HDA_SIZE/sizeof(ub4) for alignment + reasons. +*/ +/* + * cdemo3.c + * + * Demonstrates using the oflng function to retrieve + * a portion of a LONG column. + * + * This example "plays" a digitized voice message + * by repeatedly extracting 64 Kbyte chunks of the message + * from the table and sending them to a converter buffer + * (for example, a digital-to-analog converter's FIFO buffer). + * + * To better understand this example, the table is created by + * the program, and some dummy data is inserted into it. + * + * The converter subroutine is only simulated in this example + * program. + * + * The size of the HDA is defined by the HDA_SIZE constant, + * which is declared in ocidem.h to be 256 bytes for 32- + * bit architectures and 512 bytes for 64-bit architectures. + * + */ + +#include +#include +#include + +#define MSG_SIZE 200000 + +#include +#include +#ifdef __STDC__ +#include +#else +#include +#endif +#include + +Cda_Def cda; +Lda_Def lda; +size_t hda[HDA_SIZE/sizeof(size_t)]; + + +dvoid do_exit(); +dvoid oci_error(); +dvoid play_msg(); + + +main() +{ + text sql_statement[256]; + register sword i; + sb2 indp; + ub2 retl, rcode; + sword msg_id; + sb4 msg_len, len, offset; + ub1 *ucp; + register ub1 *ucp1; + ub4 ret_len; + + + /* Connect to ORACLE. */ + if (olog(&lda, (ub1 *)hda, (text *) "scott/tiger", -1, + (text *) 0, -1, (text *) 0, -1, (ub4)OCI_LM_DEF)) + { + fputs("Cannot connect with username SCOTT. Exiting...\n", stderr); + exit(EXIT_FAILURE); + } + fputs("Connected to ORACLE as user SCOTT.\n", stdout); + + + /* Open a cursor. */ + if (oopen(&cda, &lda, (text *) 0, -1, + -1, (text *) 0, -1)) + { + fputs("Cannot open cursor. Exiting...\n", stderr); + exit(EXIT_FAILURE); + } + + fputs("Program is about to drop the VOICE_MAIL table.\n", stdout); + fputs("Is this OK (Y or N)? : ", stdout); + fflush(stdout); + + gets((char *) sql_statement); + if (*sql_statement != 'y' && *sql_statement != 'Y') + do_exit(EXIT_SUCCESS); + + /* Parse, set defflg parameter for non-deferred parse + (to execute the DDL statement immediately). */ + if (oparse(&cda, (text *) "DROP TABLE voice_mail", + (sb4)-1, FALSE, (ub4)2)) + { + if (cda.rc == 942) + fputs("Table did not exist.\n", stdout); + else + oci_error(&cda); + } + else + fputs("Dropped table \"voice_mail\".\n", stdout); + + strcpy((char *) sql_statement, "CREATE TABLE voice_mail\ + (msg_id NUMBER(6), msg_len NUMBER(12), msg LONG RAW)"); + if (oparse(&cda, sql_statement, (sb4)-1, FALSE, (ub4)2)) + oci_error(&cda); + fputs("Created table \"voice_mail\".\n", stdout); + + + /* Create a dummy message. */ + strcpy((char *) sql_statement, + "INSERT INTO voice_mail (msg_id, msg_len, msg) \ + VALUES (:1, :2, :3)"); + if (oparse(&cda, sql_statement, (sb4)-1, FALSE, (ub4)2)) + oci_error(&cda); + + if (obndrn(&cda, 1, (ub1 *) &msg_id, 4, 3, -1, + (sb2 *) 0, (text *) 0, 0, -1)) + oci_error(&cda); + + /* Set buffer address before binding. */ + ucp = (ub1 *) malloc(MSG_SIZE); + if (ucp == 0) + { + fputs("malloc error\n", stderr); + do_exit(EXIT_FAILURE); + } + + if (obndrn(&cda, 2, (ub1 *) &msg_len, 4, 3, -1, + (sb2 *) 0, (text *) 0, 0, -1)) + oci_error(&cda); + + if (obndrn(&cda, 3, ucp, MSG_SIZE, 24, -1, + (sb2 *) 0, (text *) 0, 0, -1)) + oci_error(&cda); + + /* Set bind vars before oexn. */ + msg_id = 100; + msg_len = MSG_SIZE; + for (i = 0, ucp1 = ucp; i < MSG_SIZE; i++) + *ucp1++ = (ub1) i % 128; + + if (oexn(&cda, 1, 0)) + oci_error(&cda); + fputs("Data inserted in table \"voice_mail\".\n", stdout); + +/* + * After setting up the test data, do the + * select and fetch the message chunks + */ + strcpy((char *) sql_statement, "select msg_id, msg_len, msg\ + from voice_mail where msg_id = 100"); + if (oparse(&cda, sql_statement, (sb4)-1, 0, (ub4)2)) + oci_error(&cda); + if (odefin(&cda, + 1, /* index */ + (ub1 *) &msg_id, /* output variable */ + 4, /* length */ + 3, /* datatype */ + -1, /* scale */ + (sb2 *) 0, /* indp */ + (text *) 0, /* fmt */ + 0, /* fmtl */ + -1, /* fmtt */ + (ub2 *) 0, /* retl */ + (ub2 *) 0)) /* rcode */ + oci_error(&cda); + if (odefin(&cda, + 2, /* index */ + (ub1 *) &msg_len,/* output variable */ + 4, /* length */ + 3, /* datatype */ + -1, /* scale */ + (sb2 *) 0, /* indp */ + (text *) 0, /* fmt */ + 0, /* fmtl */ + -1, /* fmtt */ + (ub2 *) 0, /* retl */ + (ub2 *) 0)) /* rcode */ + oci_error(&cda); + if (odefin(&cda, + 3, /* index */ + ucp, /* output variable */ + 100, /* length */ + 24, /* LONG RAW datatype code */ + -1, /* scale */ + &indp, /* indp */ + (text *) 0, /* fmt */ + 0, /* fmtl */ + -1, /* fmtt */ + &retl, /* retl */ + &rcode)) /* rcode */ + oci_error(&cda); + + + /* Do the query, getting the msg_id and the first + 100 bytes of the message. */ + if (oexfet(&cda, + (ub4) 1, /* nrows */ + 0, /* cancel (FALSE) */ + 0)) /* exact (FALSE) */ + { + oci_error(&cda); + } + fprintf(stdout, + "Message %d is available, length is %d.\n", msg_id, msg_len); + fprintf(stdout, + "indp = %d, rcode = %d, retl = %d\n", indp, rcode, retl); + + /* Play the message, looping until there are + no more data points to output. */ + + for (offset = (ub4) 0; ; offset += (ub4) 0x10000) + { + len = msg_len < 0x10000 ? msg_len : 0x10000; + + if (oflng(&cda, + 3, /* position */ + ucp, /* buf */ + len, /* bufl */ + 24, /* datatype */ + &ret_len, /* retl */ + offset)) /* offset */ + oci_error(&cda); + + /* Output the message chunk. */ + play_msg(ucp, len); + msg_len -= len; + if (msg_len <= 0) + break; + } + do_exit(EXIT_SUCCESS); +} + + +dvoid +play_msg(buf, len) +ub1 *buf; +sword len; +{ + fprintf(stdout, "\"playing\" %d bytes.\n", len); +} + + +dvoid +oci_error(cda) +Cda_Def *cda; +{ + text msg[200]; + sword n; + + fputs("\n-- ORACLE ERROR --\n", stderr); + n = oerhms(&lda, (sb2) cda->rc, msg, 200); + fprintf(stderr, "%.*s", n, msg); + fprintf(stderr, "Processing OCI function %s\n", + oci_func_tab[(int) cda->fc]); + do_exit(EXIT_FAILURE); +} + + +dvoid +do_exit(rv) +sword rv; +{ + fputs("Exiting...\n", stdout); + if (oclose(&cda)) + { + fputs("Error closing cursor.\n", stderr); + rv = EXIT_FAILURE; + } + if (ologof(&lda)) + { + fputs("Error logging off.\n", stderr); + rv = EXIT_FAILURE; + } + exit(rv); +} + + + diff --git a/cdemo4.c b/cdemo4.c new file mode 100644 index 0000000..d43c22b --- /dev/null +++ b/cdemo4.c @@ -0,0 +1,413 @@ +/* Copyright (c) 1991, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + cdemo4.c - + DESCRIPTION + + PUBLIC FUNCTION(S) + + PRIVATE FUNCTION(S) + + RETURNS + + NOTES + + MODIFIED (MM/DD/YY) + azhao 10/11/06 - case-senstive password change + kmohan 03/28/06 - change hda to size_t + jchai 07/27/04 - add order by in select stmt + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + plocke 11/18/95 - to update for v7.3 + slari 04/25/95 - merge changes from branch 1.6.720.1 + slari 04/19/95 - replace orlon with olog + emendez 04/07/94 - merge changes from branch 1.4.710.3 + gdoherty 04/06/94 - merge changes from branch 1.4.710.1 + emendez 02/07/94 - fix for bug 196094 + emendez 02/02/94 - Fix for bug 157576 + gdoherty 02/02/94 - make oci header inclusion for ansi or k+r adaptive + lfeng 01/13/93 - fix non-portable fflush + rkooi2 11/27/92 - Changing e... datatypes to s... + kaghevli 11/06/92 - test + rkooi2 10/29/92 - Creation +*/ +/* cdemo4.c + * + * Demonstrates doing a FETCH from a cursor + * into PL/SQL tables. The tables are bound to C + * arrays using the obndra routine. + * The fully-commented script to create the stored procedure + * is in the demo program file calldemo.sql. + * + * Execute this script using SQL*DBA or SQL*Plus + * to store the package before executing this program. + * + * The script is: + * create or replace package calldemo as + * + * type char_array is table of varchar2(20) index by binary_integer; + * type num_array is table of float index by binary_integer; + * + * procedure get_employees( + * dept_number in integer, -- which department to query + * batch_size in integer, -- how many rows at a time + * found in out integer, -- n of rows actually returned + * done_fetch out integer, -- all done flag + * emp_name out char_array,-- arrays of employee names, + * job out char_array,-- jobs, + * sal out num_array);-- salaries + * + * end; + * / + * + * create or replace package body calldemo as + * + * cursor get_emp( + * dept_number in integer) is + * select ename, job, sal from emp + * where deptno = dept_number order by ename; + * + * -- Procedure get_employees fetches a batch of employee + * -- rows (batch size is determined by the client/caller + * -- of this procedure). Procedure may be called from + * -- other stored procedures or client application + * -- programs. The procedure opens the cursor if it is + * -- not already open, fetches a batch of rows, and + * -- returns the number of rows actually retrieved. At + * -- end of fetch, the procedure closes the cursor. + * + * procedure get_employees( + * dept_number in integer, + * batch_size in integer, + * found in out integer, + * done_fetch out integer, + * emp_name out char_array, + * job out char_array, + * sal out num_array) is + * + * begin + * if NOT get_emp%ISOPEN then -- open the cursor if it is + * open get_emp(dept_number); -- not already open + * end if; + * + * -- Fetch up to "batch_size" rows into PL/SQL table, + * -- tallying rows found as they are retrieved. When end + * -- of fetch is encountered, close the cursor and exit + * -- the loop, returning only the last set of rows found. + * + * done_fetch := FALSE; + * found := 0; + * + * for i in 1..batch_size loop + * fetch get_emp -- get one emp table row + * into emp_name(i), job(i), sal(i); + * + * if get_emp%notfound then -- if no row was found, then + * close get_emp; -- close the cursor + * done_fetch := TRUE; -- indicate all done + * exit; -- exit the loop + * else + * found := found + 1; -- else count the row and continue + * end if; + * end loop; + * end; + * end; + * / + */ + +#include +#include + +#include +#include +#ifdef __STDC__ +#include +#else +#include +#endif +#include + +#define MAX_ARRAY_SIZE 5 +#define NO_PARSE_DEFER 0 +#define V7_LNGFLG 2 +#define VC_LENGTH 20 + +/* Declare the data areas. */ +Cda_Def cda; +Lda_Def lda; +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ + +/* Declare routines in this program */ +dvoid do_fetch(/*_ void _*/); +dvoid oci_error(/*_ void _*/); + +main(argc, argv) +sword argc; +text **argv; +{ + text username[128]; + + if (argc > 1) + strncpy((char *) username, (char *) argv[1], + sizeof (username) - 1); + else + strcpy((char *) username, "SCOTT/tiger"); + + if (olog(&lda, (ub1 *)hda, username, -1, (text *) 0, -1, + (text *) 0, -1, (ub4)OCI_LM_DEF)) + { + printf("Cannot connect as %s. Exiting...\n", username); + exit(-1); + } + else + printf("Connected.\n"); + + /* Open the OCI cursor. */ + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) + { + printf("Cannot open cursor data area, exiting...\n"); + exit(-1); + } + + /* Fetch and print the data. */ + do_fetch(); + + /* Close the OCI cursor. */ + if (oclose(&cda)) + { + printf("Error closing cursor!\n"); + exit(-1); + } + + /* Disconnect from ORACLE. */ + if (ologof(&lda)) + { + printf("Error logging off!\n"); + exit(-1); + } + exit(0); +} + + +/* Set up an anonymous PL/SQL call to the stored + procedure that fetches the data. */ +dvoid +do_fetch(/*_ void _*/) +{ + text *call_fetch = (text *) "\ + begin\ + calldemo.get_employees(:deptno, :t_size, :num_ret, :all_done,\ + :e_name, :job, :sal);\ + end;"; + sword table_size = MAX_ARRAY_SIZE; + sword i, n_ret, done_flag; + sword dept_num; + sb2 n_ret_indp; + ub2 n_ret_len, n_ret_rcode; + ub4 n_ret_cursiz = 0; + + text emp_name[MAX_ARRAY_SIZE][VC_LENGTH]; + sb2 emp_indp_name[MAX_ARRAY_SIZE]; + ub2 emp_len_name[MAX_ARRAY_SIZE]; + ub2 emp_rcode_name[MAX_ARRAY_SIZE]; + ub4 emp_cursiz_name = (ub4) MAX_ARRAY_SIZE; + + text job[MAX_ARRAY_SIZE][VC_LENGTH]; + sb2 job_indp[MAX_ARRAY_SIZE]; + ub2 job_len[MAX_ARRAY_SIZE]; + ub2 job_rcode[MAX_ARRAY_SIZE]; + ub4 job_cursiz = (ub4) MAX_ARRAY_SIZE; + + float salary[MAX_ARRAY_SIZE]; + sb2 salary_indp[MAX_ARRAY_SIZE]; + ub2 salary_len[MAX_ARRAY_SIZE]; + ub2 salary_rcode[MAX_ARRAY_SIZE]; + ub4 salary_cursiz = (ub4) MAX_ARRAY_SIZE; + + /* parse the anonymous SQL block */ + if (oparse(&cda, call_fetch, (sb4)-1, + NO_PARSE_DEFER, (ub4)V7_LNGFLG)) + { + oci_error(); + return; + } + + /* initialize the bind arrays */ + for (i = 0; i < MAX_ARRAY_SIZE; i++) + { + emp_len_name[i] = VC_LENGTH; + job_len[i] = VC_LENGTH; + salary_len[i] = sizeof (float); + } + + n_ret_len = sizeof (sword); + + /* bind the department number IN parameter */ + if (obndrv(&cda, (text *) ":deptno", -1, (ub1 *) &dept_num, + (sword) sizeof (sword), INT_TYPE, -1, + (sb2 *) 0, (text *) 0, -1, -1)) + { + oci_error(); + return; + } + /* bind the table size IN parameter */ + if (obndrv(&cda, (text *) ":t_size", -1, (ub1 *) &table_size, + (sword) sizeof (sword), + INT_TYPE, -1, (sb2 *) 0, (text *) 0, -1, -1)) + { + oci_error(); + return; + } + /* bind the fetch done OUT parameter */ + if (obndrv(&cda, (text *) ":all_done", -1, (ub1 *) &done_flag, + (sword) sizeof (sword), + INT_TYPE, -1, (sb2 *) 0, (text *) 0, -1, -1)) + { + oci_error(); + return; + } + + /* Bind the OUT n_ret using obndra. obndrv could + have been used just as well, since no arrays + are involved, but it is possible to use obndra + for scalars as well. */ + if (obndra(&cda, + (text *) ":num_ret", + -1, + (ub1 *) &n_ret, + (sword) sizeof (sword), + INT_TYPE, + -1, + &n_ret_indp, + &n_ret_len, + &n_ret_rcode, + (ub4) 0, /* pass as 0, not 1, when binding a scalar */ + (ub4 *) 0, /* pass as the null pointer when scalar */ + (text *) 0, + -1, + -1)) + { + oci_error(); + return; + } + + /* bind the employee name array */ + if (obndra(&cda, + (text *) ":e_name", + -1, + (ub1 *) emp_name, + VC_LENGTH, + VARCHAR2_TYPE, + -1, + emp_indp_name, + emp_len_name, + emp_rcode_name, + (ub4) MAX_ARRAY_SIZE, + &emp_cursiz_name, + (text *) 0, + -1, + -1)) + { + oci_error(); + return; + } + + /* bind the job array */ + if (obndra(&cda, + (text *) ":job", + -1, + (ub1 *) job, + VC_LENGTH, + VARCHAR2_TYPE, + -1, + job_indp, + job_len, + job_rcode, + (ub4) MAX_ARRAY_SIZE, + &job_cursiz, + (text *) 0, + -1, + -1)) + { + oci_error(); + return; + } + + /* bind the salary array */ + if (obndra(&cda, + (text *) ":sal", + -1, + (ub1 *) salary, + (sword) sizeof (float), + FLOAT_TYPE, + -1, + salary_indp, + salary_len, + salary_rcode, + (ub4) MAX_ARRAY_SIZE, + &salary_cursiz, + (text *) 0, + -1, + -1)) + { + oci_error(); + return; + } + + printf("\nenter deptno: "); + scanf("%d", &dept_num); + + for (;;) + { + /* execute the fetch */ + if (oexec(&cda)) + { + oci_error(); + return; + } + + printf("\n%d row%c returned\n", + n_ret, n_ret == 1 ? '\0' : 's'); + + if (n_ret > 0) + { + printf("\n%-*.*s%-*.*s%s\n", + VC_LENGTH, VC_LENGTH, "Employee Name", + VC_LENGTH, VC_LENGTH, "Job", " Salary"); + for (i = 0; i < n_ret; i++) + { + printf("%.*s", emp_len_name[i], emp_name[i]); + printf("%*c", VC_LENGTH - emp_len_name[i], ' '); + printf("%.*s", job_len[i], job[i]); + printf("%*c", VC_LENGTH - job_len[i], ' '); + printf("%8.2f\n", salary[i]); + } + } + if (done_flag != 0) + { + printf("\n"); + break; + } + } + return; +} + + +dvoid +oci_error(/*_ void _*/) +{ + text msg[900]; + sword rv; + + rv = oerhms(&lda, cda.rc, msg, (sword) sizeof (msg)); + + printf("\n\n%.*s", rv, msg); + printf("Processing OCI function %s\n", + oci_func_tab[(int) cda.fc]); + return; +} + + diff --git a/cdemo5.c b/cdemo5.c new file mode 100644 index 0000000..6a7aab1 --- /dev/null +++ b/cdemo5.c @@ -0,0 +1,313 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemo5.c 11-oct-2006.17:36:36 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + cdemo5.c - a small example of use of variable cursors + MODIFIED (MM/DD/YY) + azhao 10/11/06 - case-senstive password change + lzhao 04/04/05 - bug4184176 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + azhao 05/16/97 - change ub1 to ub4 for hstb + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + plocke 11/18/95 - to update for v7.3 + slari 04/25/95 - merge changes from branch 1.1.720.1 + slari 04/20/95 - Branch_for_patch + slari 04/19/95 - replace orlon with olog + pvasterd 10/20/94 - Changes to bring into line with other cdemos + dchatter 10/17/94 - Creation + */ +/* + * -- cdemo5.c -- + * + * An example program which demonstrates the use of + * Variable Cursors in an OCI program. + * + */ + +#include +#include +#include +#include +#include +#include +#include + + /* oparse flags */ +#define DEFER_PARSE 1 +#define VERSION_7 2 + +#define NPOS 16 +#define DSCLEN 240 + +text *username = (text *) "SCOTT"; +text *password = (text *) "tiger"; + +static sword retval; +static ub4 hstb[512]; +static text errorb[4095]; +static text cbuf[NPOS][DSCLEN]; +static sb4 cbufl[NPOS]; +static sb4 dbsize[NPOS]; +static sb4 dsize[NPOS]; +static sb2 dbtype[NPOS]; +static sb2 prec[NPOS]; +static sb2 scale[NPOS]; +static sb2 nullok[NPOS]; + +static Lda_Def lda1; + +static text plsql_block[] = + "begin \ + OPEN :cursor1 FOR select empno, ename, job, mgr, hiredate,sal,deptno\ + from emp where job=:job order by empno;\ + end;"; + +/* CLIENT CURSORS */ +static Cda_Def cursor, cursor_emp; + +/* Prototype */ +void oracle_error(); + +int main () +{ + Lda_Def *ldap = &lda1; + + ub4 empno; + text ename[11]; + text job[10]; + ub4 mgr; + text hidate[10]; + ub4 sal; + ub4 deptno; + int i; + text job_kind[50]; + ub4 pos; + + strcpy((char *) job_kind, (char *)"ANALYST"); + fprintf(stdout,"\n\nFETCHING for job=%s\n\n",job_kind); + + /* + * Connect to Oracle as SCOTT/TIGER. + * Exit on any error. + */ + + if (olog(ldap, (ub1 *)hstb, username, -1, password, -1, + (text *) 0, -1, (ub4)OCI_LM_DEF)) + { + printf("Unable to connect as %s\n", username); + exit(EXIT_FAILURE); + } + printf("Connected to Oracle as %s\n\n", username); + + /* + * Open a cursor for executing the PL/SQL block. + */ + + if (oopen(&cursor, ldap, (text *) 0, -1, 0, (text *) 0, -1)) + { + oracle_error(&cursor); + exit(EXIT_FAILURE); + } + + /* + * Parse the PL/SQL block. + */ + + if (oparse(&cursor, plsql_block, (sb4) -1, (sword) TRUE, (ub4) 2)) + { + oracle_error(&cursor); + exit(EXIT_FAILURE); + } + + /* + * Bind a variable of cursor datatype, the cursor will be opened + * inside the PL/SQL block. + */ + + if (obndra(&cursor, (text *) ":cursor1", -1, (ub1 *) &cursor_emp, + -1, SQLT_CUR, -1, (sb2 *) 0, (ub2 *) 0, (ub2 *) 0, + (ub4) 0, (ub4 *) 0, (text *) 0, 0, 0)) + { + oracle_error(&cursor); + exit(EXIT_FAILURE); + } + + /* + * Bind a variable of string datatype. + */ + + if (obndra(&cursor, (text *) ":job", -1, (ub1 *) job_kind, + -1, SQLT_STR, -1, (sb2 *) 0, (ub2 *) 0, (ub2 *) 0, + (ub4) 0, (ub4 *) 0, (text *) 0, 0, 0)) + { + oracle_error(&cursor); + exit(EXIT_FAILURE); + } + + /* + * Execute the PL/SQL block. + */ + + if (oexec(&cursor)) + { + oracle_error(&cursor); + exit(EXIT_FAILURE); + } + + /* + * Close the cursor on which the PL/SQL block executed. + */ + + if (oclose(&cursor)) + { + oracle_error(&cursor); + exit(EXIT_FAILURE); + } + + /* + * Do describe on cursor initialized and returned from the PL/SQL block. + */ + + for (pos = 0; pos < NPOS; pos++) + { + cbufl[pos] = DSCLEN; + if (odescr(&cursor_emp, (sword) (pos+1), &dbsize[pos], &dbtype[pos], + (sb1 *) cbuf[pos], &cbufl[pos], &dsize[pos], + &prec[pos], &scale[pos], &nullok[pos])) + { + if (cursor_emp.rc == 1007) + break; + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + } + + printf("Describe select-list returns:\n\n"); + printf("----------------------------------------\n"); + printf("Item\t\tMaxSize\t\tType\n"); + printf("----------------------------------------\n"); + for (i = 0; i < pos; i++) + { + cbuf[i][cbufl[i]] = '\0'; + printf("%s\t\t%d\t\t%d\n", cbuf[i], dbsize[i], dbtype[i]); + } + + /* + * Do client defines. + */ + + if (odefin(&cursor_emp, 1, (ub1 *) &empno, (sword) sizeof(ub4), SQLT_INT, + -1, (sb2 *) -1, (text *) 0, (sword) 0, (sword) 0, (ub2 *) 0, + (ub2 *) 0)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + + if (odefin(&cursor_emp, 2, (ub1 *) ename, (sword) sizeof(ename), + SQLT_STR, -1, (sb2 *) -1, (text *)0, (sword) 0, (sword) 0, + (ub2 *) 0, (ub2 *) 0)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + + if (odefin(&cursor_emp, 3, (ub1 *) job, (sword) sizeof(job), + SQLT_STR, -1, (sb2 *) -1, (text *) 0, (sword) 0, (sword) 0, + (ub2 *) 0, (ub2 *) 0)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + + if (odefin(&cursor_emp, 4, (ub1 *)&mgr, (sword) sizeof(ub4), SQLT_INT, + -1, (sb2 *) -1, (text *)0, (sword) 0, (sword) 0, (ub2 *) 0, + (ub2 *) 0)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + + if (odefin(&cursor_emp, 5, (ub1 *)hidate, (sword) sizeof(hidate), + SQLT_STR, -1, (sb2 *) -1, (text *) 0, (sword) 0, (sword) 0, + (ub2 *) 0, (ub2 *) 0)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + + if (odefin(&cursor_emp, 6, (ub1 *) &sal, (sword) sizeof(ub4), SQLT_INT, + -1, (sb2 *) -1, (text *) 0, (sword) 0, (sword) 0, (ub2 *) 0, + (ub2 *) 0)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + + if (odefin(&cursor_emp, 7, (ub1 *) &deptno, (sword) sizeof(deptno), + SQLT_INT, -1, (sb2 *) -1, (text *) 0, (sword) 0, (sword) 0, + (ub2 *) 0, (ub2 *) 0)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + + printf("\nFETCH from variable cursor:\n\n"); + printf("------------------------------------------------------------\n"); + printf("empno\tename\tjob\tmgr\thiredate\tsalary\tdept\n"); + printf("------------------------------------------------------------\n"); + + /* + * Now fetch the result set and display. + */ + + while (1) + { + sb4 err = 0; + + if (err = ofetch(&cursor_emp)) + { + if (cursor_emp.rc == 1403) + break; + else + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + } + else + { + /* A row was returned; have to do the fetch. */ + fprintf(stdout, "%d\t%s\t%s\t%d\t%s\t%d\t%d\n\n", + empno, ename, job, mgr, hidate, sal, deptno); + } + } + + /* + * Log off. + */ + + if (ologof(ldap)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } +} /* end of main */ + +void oracle_error(lda) +Lda_Def * lda; +{ + char msgbuf[512]; + int n=oerhms(lda, lda->rc, (text *)msgbuf, (int) sizeof(msgbuf) ); + + printf("\n\n%.*s\n",n,msgbuf); +} + + diff --git a/cdemo6.cc b/cdemo6.cc new file mode 100644 index 0000000..11a828c --- /dev/null +++ b/cdemo6.cc @@ -0,0 +1,315 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemo6.cc 18-feb-2005.06:13:14 sudsrini Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1991, 2005, Oracle. All rights reserved. +*/ + +/* + NAME + cdemo1.cc - C++ Demo Program + MODIFIED (MM/DD/YY) + sudsrini 02/18/05 - include stdlib + slari 08/08/01 - b1737025: move extern declaration + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + akatti 05/19/98 - [493012]:bug fix to prevent core dump + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + slari 04/19/95 - replace orlon with olog + skrishna 10/20/94 - Creation +*/ +/* + * -- cdemo6.cc -- + * An example program which illustrates how a C++ program + * can use the OCI interface to access ORACLE database. + * + * This program retrieves department name, given the + * department number. + * + * The program queries the user for data as follows: + * + * Enter department number: + * + * The program terminates if -1 is entered + * when the department number is requested. + */ +#include +#include +#include + +extern "C" +{ +#include +/* demo constants and structs */ +} + +#include +#include + +const text *username = (text *) "SCOTT"; +const text *password = (text *) "TIGER"; + +/* define SQL statements to be used in the program */ +const text *seldept = (text *) "SELECT dname FROM dept WHERE deptno = :1"; + +void err_report(FILE *file, text *errmsg, sword func_code); +void myfflush(); + +/* connection destructor */ +connection::~connection() +{ + // disconnect if connection exists + if (state == connected) + { + if (disconnect()) + { + display_error(stderr); + } + } +} + +/* connect to ORACLE */ +sword connection::connect(const text *username, const text *password) +{ + sword status; + + if (state == connected) + { + // this object is already connected + return (CONERR_ALRCON); + } + + if ((status = olog(&lda, hda, (text *) username, -1, + (text *)password, -1, (text *) 0, -1, + OCI_LM_DEF)) == 0) + { + // successful login + state = connected; + printf("Connected to ORACLE as %s\n", username); + } + + return (status); +} + +/* disconnect from ORACLE */ +sword connection::disconnect() +{ + sword status; + + if (state == not_connected) + { + // this object has not been connected + return (CONERR_NOTCON); + } + + if ((status = ologof(&lda)) == 0) + { + // successful logout + state = not_connected; + } + + return (status); +} + +/* write error message to the given file */ +void connection::display_error(FILE *file) const +{ + if (lda.rc != 0) + { + sword n; + text msg[512]; + + n = oerhms((cda_def *)&lda, lda.rc, msg, (sword) sizeof(msg)); + err_report(file, msg, lda.fc); + } +} + +/* cursor destructor */ +cursor::~cursor() +{ + if (state == opened) + { + if (close()) + display_error(stderr); + } +} + +/* open the cursor */ +sword cursor::open(connection *conn_param) +{ + sword status; + + if (state == opened) + { + // this cursor has already been opened + return (CURERR_ALROPN); + } + + if ((status = oopen(&cda, &conn_param->lda, (text *)0, -1, -1, + (text *)0, -1)) == 0) + { + // successfull open + state = opened; + conn = conn_param; + } + + return (status); +} + +/* close the cursor */ +sword cursor::close() +{ + sword status; + + if (state == not_opened) + { + // this cursor has not been opened + return (CURERR_NOTOPN); + } + + if ((status = oclose(&cda)) == 0) + { + // successful cursor close + state = not_opened; + conn = (connection *)0; + } + + return (status); +} + +/* write error message to the given file */ +void cursor::display_error(FILE *file) const +{ + if (cda.rc != 0) + { + sword n; + text msg[512]; + + n = oerhms(&conn->lda, cda.rc, msg, (sword) sizeof(msg)); + err_report(file, msg, cda.fc); + } +} + +int main() +{ + sword deptno; + sword len, dsize; + sb4 deptlen; + sb2 db_type; + sb1 name_buf[20]; + text *dept; + +/* + * Connect to ORACLE and open a cursor. + * Exit on any error. + */ + connection conn; + if (conn.connect(username, password)) + { + conn.display_error(stderr); + return(EXIT_FAILURE); + } + + cursor crsr; + if (crsr.open(&conn)) + { + crsr.display_error(stderr); + return(EXIT_FAILURE); + } + + /* parse the SELDEPT statement */ + if (crsr.parse(seldept)) + { + crsr.display_error(stderr); + return(EXIT_FAILURE); + } + + /* bind the placeholder in the SELDEPT statement */ + if (crsr.bind_by_position(1, (ub1 *) &deptno, (sword) sizeof(deptno), + INT_TYPE, -1, (sb2 *) 0)) + { + crsr.display_error(stderr); + return(EXIT_FAILURE); + } + + /* describe the select-list field "dname" */ + len = sizeof (name_buf); + if (crsr.describe(1, (sb4 *) &deptlen, &db_type, + name_buf, (sb4 *) &len, (sb4 *) &dsize, (sb2 *) 0, + (sb2 *) 0, (sb2 *) 0)) + { + crsr.display_error(stderr); + return(EXIT_FAILURE); + } + + /* allocate space for dept name now that you have length */ + dept = new text[(int) deptlen + 1]; + + /* define the output variable for the select-list */ + if (crsr.define_by_position(1, (ub1 *) dept, (sword)deptlen+1, + STRING_TYPE, -1, (sb2 *) 0, (ub2 *) 0, + (ub2 *) 0)) + { + crsr.display_error(stderr); + delete dept; + return(EXIT_FAILURE); + } + + for (;;) + { + /* prompt for department number, break if given number == -1 */ + printf("\nEnter department number (or -1 to EXIT): "); + while (scanf("%d", &deptno) != 1) + { + myfflush(); + printf("Invalid input, please enter a number (-1 to EXIT): "); + } + if (deptno == -1) + { + printf("Exiting... "); + break; + } + + /* display the name of the corresponding department */ + if (crsr.execute() || crsr.fetch()) + { + if (crsr.get_error_code() != NO_DATA_FOUND) + { + crsr.display_error(stderr); + delete dept; + return(EXIT_FAILURE); + } + else + printf( + "\n The department number that you entered doesn't exist.\n"); + } + else + { + printf("\n Department name = %s Department number = %d\n", + dept, deptno); + } + } + + delete dept; + printf ("\nG'day\n"); + + return 0; +} + + +void err_report(FILE *file, text *errmsg, sword func_code) +{ + fprintf(file, "\n-- ORACLE error--\n\n%s\n", errmsg); + if (func_code > 0) + fprintf(file, "Processing OCI function %s\n", + oci_func_tab[func_code]); +} + +void myfflush() +{ + eb1 buf[50]; + + fgets((char *) buf, 50, stdin); +} + + diff --git a/cdemo6.h b/cdemo6.h new file mode 100644 index 0000000..dd9392d --- /dev/null +++ b/cdemo6.h @@ -0,0 +1,117 @@ +/* + * $Header: cdemo6.h 08-aug-2001.16:30:28 slari Exp $ + */ + +/* Copyright (c) 1995, 2001, Oracle Corporation. All rights reserved. +*/ + +/* + NAME + cdemo6.h - header file for C++ Demo Program + MODIFIED (MM/DD/YY) + slari 08/08/01 - b1737025: move extern declaration + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + slari 04/25/95 - merge changes from branch 1.1.720.1 + slari 04/24/95 - Branch_for_patch + slari 04/21/95 - Creation +*/ + + +#include +#include +#include +#include + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* Class forward declarations */ +class connection; +class cursor; + +/* + * This class represents a connection to ORACLE database. + * + * NOTE: This connection class is just given as an example and all possible + * operations on a connection have not been defined. + */ +class connection +{ + friend class cursor; + public: + connection() + { state = not_connected; memset(hda,'\0', HDA_SIZE); } + ~connection(); + sword connect(const text *username, const text *password); + sword disconnect(); + void display_error(FILE* file) const; + private: + Lda_Def lda; + ub1 hda[HDA_SIZE]; + enum conn_state + { + not_connected, + connected + }; + conn_state state; +}; + +/* + * This class represents an ORACLE cursor. + * + * NOTE: This cursor class is just given as an example and all possible + * operations on a cursor have not been defined. + */ +class cursor +{ + public: + cursor() + {state = not_opened; conn = (connection *)0; } + ~cursor(); + sword open(connection *conn_param); + sword close(); + sword parse(const text *stmt) + { return (oparse(&cda, (text *)stmt, (sb4)-1, + DEFER_PARSE, (ub4) VERSION_7)); } + /* bind an input variable */ + sword bind_by_position(sword sqlvnum, ub1 *progvar, sword progvarlen, + sword datatype, sword scale, sb2 *indicator) + { return (obndrn(&cda, sqlvnum, progvar, progvarlen, datatype, scale, + indicator, (text *)0, -1, -1)); } + /* define an output variable */ + sword define_by_position(sword position, ub1 *buf, sword bufl, + sword datatype, sword scale, sb2 *indicator, + ub2 *rlen, ub2 *rcode) + { return (odefin(&cda, position, buf, bufl, datatype, scale, indicator, + (text *)0, -1, -1, rlen, rcode)); } + sword describe(sword position, sb4 *dbsize, sb2 *dbtype, sb1 *cbuf, + sb4 *cbufl, sb4 *dsize, sb2 *prec, sb2 *scale, sb2 *nullok) + { return (odescr(&cda, position, dbsize, dbtype, cbuf, cbufl, dsize, + prec, scale, nullok)); } + sword execute() + { return (oexec(&cda)); } + sword fetch() + { return (ofetch(&cda)); } + sword get_error_code() const + { return (cda.rc); } + void display_error( FILE* file) const; + private: + Cda_Def cda; + connection *conn; + enum cursor_state + { + not_opened, + opened + }; + cursor_state state; +}; + +/* + * Error number macros + */ +#define CONERR_ALRCON -1 /* already connected */ +#define CONERR_NOTCON -2 /* not connected */ +#define CURERR_ALROPN -3 /* cursor is already open */ +#define CURERR_NOTOPN -4 /* cursor is not opened */ diff --git a/cdemo81.c b/cdemo81.c new file mode 100644 index 0000000..f9db754 --- /dev/null +++ b/cdemo81.c @@ -0,0 +1,445 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemo81.c 14-apr-2006.10:55:52 lburgess Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1996, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemo81.c - Basic OCI V8 functionality + + DESCRIPTION + + * An example program which adds new employee + * records to the personnel data base. Checking + * is done to insure the integrity of the data base. + * The employee numbers are automatically selected using + * the current maximum employee number as the start. + * + * The program queries the user for data as follows: + * + * Enter employee name: + * Enter employee job: + * Enter employee salary: + * Enter employee dept: + * + * The program terminates if return key (CR) is entered + * when the employee name is requested. + * + * If the record is successfully inserted, the following + * is printed: + * + * "ename" added to department "dname" as employee # "empno" + + Demonstrates creating a connection, a session and executing some SQL. + Also shows the usage of allocating memory for application use which has the + life time of the handle. + + MODIFIED (MM/DD/YY) + lburgess 04/14/06 - lowercase passwords + aliu 04/21/06 - use OCIEnvCreate and exit if it fails + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + dchatter 10/14/98 - add the usage of xtrmemsz and usrmempp + azhao 06/23/97 - Use OCIBindByPos, OCIBindByName; clean up + echen 12/17/96 - OCI beautification + dchatter 07/18/96 - delete spurious header files + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + mgianata 06/17/96 - change ociisc() to OCISessionBegin() + aroy 04/26/96 - change OCITransCommitt -> OCITransCommit + slari 04/24/96 - use OCITransCommitt + aroy 02/21/96 - fix bug in get descriptor handle call + lchidamb 02/20/96 - cdemo81.c converted for v8 OCI + lchidamb 02/20/96 - Creation + +*/ + + +#include +#include +#include +#include + +static text *username = (text *) "SCOTT"; +static text *password = (text *) "tiger"; + +/* Define SQL statements to be used in program. */ +static text *insert = (text *)"INSERT INTO emp(empno, ename, job, sal, deptno)\ + VALUES (:empno, :ename, :job, :sal, :deptno)"; +static text *seldept = (text *)"SELECT dname FROM dept WHERE deptno = :1"; +static text *maxemp = (text *)"SELECT NVL(MAX(empno), 0) FROM emp"; +static text *selemp = (text *)"SELECT ename, job FROM emp"; + +static OCIEnv *envhp; +static OCIError *errhp; + +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void cleanup(/*_ void _*/); +static void myfflush(/*_ void _*/); +int main(/*_ int argc, char *argv[] _*/); + +static sword status; + +int main(argc, argv) +int argc; +char *argv[]; +{ + + sword empno, sal, deptno; + sword len, len2, rv, dsize, dsize2; + sb4 enamelen = 10; + sb4 joblen = 9; + sb4 deptlen = 14; + sb2 sal_ind, job_ind; + sb2 db_type, db2_type; + sb1 name_buf[20], name2_buf[20]; + text *cp, *ename, *job, *dept; + + sb2 ind[2]; /* indicator */ + ub2 alen[2]; /* actual length */ + ub2 rlen[2]; /* return length */ + + OCIDescribe *dschndl1 = (OCIDescribe *) 0, + *dschndl2 = (OCIDescribe *) 0, + *dschndl3 = (OCIDescribe *) 0; + + OCISession *authp = (OCISession *) 0; + OCIServer *srvhp; + OCISvcCtx *svchp; + OCIStmt *inserthp, + *stmthp, + *stmthp1; + OCIDefine *defnp = (OCIDefine *) 0; + + OCIBind *bnd1p = (OCIBind *) 0; /* the first bind handle */ + OCIBind *bnd2p = (OCIBind *) 0; /* the second bind handle */ + OCIBind *bnd3p = (OCIBind *) 0; /* the third bind handle */ + OCIBind *bnd4p = (OCIBind *) 0; /* the fourth bind handle */ + OCIBind *bnd5p = (OCIBind *) 0; /* the fifth bind handle */ + OCIBind *bnd6p = (OCIBind *) 0; /* the sixth bind handle */ + + sword errcode = 0; + + errcode = OCIEnvCreate((OCIEnv **) &envhp, (ub4) OCI_DEFAULT, + (dvoid *) 0, (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t)) 0, + (void (*)(dvoid *, dvoid *)) 0, (size_t) 0, (dvoid **) 0); + + if (errcode != 0) { + (void) printf("OCIEnvCreate failed with errcode = %d.\n", errcode); + exit(1); + } + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + /* server contexts */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, OCI_HTYPE_SERVER, + (size_t) 0, (dvoid **) 0); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0); + + (void) OCIServerAttach( srvhp, errhp, (text *)"", strlen(""), 0); + + /* set attribute server context in the service context */ + (void) OCIAttrSet( (dvoid *) svchp, OCI_HTYPE_SVCCTX, (dvoid *)srvhp, + (ub4) 0, OCI_ATTR_SERVER, (OCIError *) errhp); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **)&authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0); + + (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) username, (ub4) strlen((char *)username), + (ub4) OCI_ATTR_USERNAME, errhp); + + (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *)password), + (ub4) OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin ( svchp, errhp, authp, OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)); + + (void) OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, + (ub4) OCI_ATTR_SESSION, errhp); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp1, + OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)); + + /* Retrieve the current maximum employee number. */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, maxemp, + (ub4) strlen((char *) maxemp), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + /* bind the input variable */ + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, 1, (dvoid *) &empno, + (sword) sizeof(sword), SQLT_INT, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, OCI_DEFAULT)); + + /* execute and fetch */ + if (status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT)) + { + if (status == OCI_NO_DATA) + empno = 10; + else + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + } + + + /* + * When we bind the insert statement we also need to allocate the storage + * of the employee name and the job description. + * Since the lifetime of these buffers are the same as the statement, we + * will allocate it at the time when the statement handle is allocated; this + * will get freed when the statement disappears and there is less + * fragmentation. + * + * sizes required are enamelen+2 and joblen+2 to allow for \n and \0 + * + */ + + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &inserthp, + OCI_HTYPE_STMT, (size_t) enamelen + 2 + joblen + 2, + (dvoid **) &ename)); + job = (text *) (ename+enamelen+2); + + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, insert, + (ub4) strlen((char *) insert), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp1, errhp, seldept, + (ub4) strlen((char *) seldept), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + + /* Bind the placeholders in the INSERT statement. */ + if ((status = OCIBindByName(stmthp, &bnd1p, errhp, (text *) ":ENAME", + -1, (dvoid *) ename, + enamelen+1, SQLT_STR, (dvoid *) 0, + (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT)) || + (status = OCIBindByName(stmthp, &bnd2p, errhp, (text *) ":JOB", + -1, (dvoid *) job, + joblen+1, SQLT_STR, (dvoid *) &job_ind, + (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT)) || + (status = OCIBindByName(stmthp, &bnd3p, errhp, (text *) ":SAL", + -1, (dvoid *) &sal, + (sword) sizeof(sal), SQLT_INT, (dvoid *) &sal_ind, + (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT)) || + (status = OCIBindByName(stmthp, &bnd4p, errhp, (text *) ":DEPTNO", + -1, (dvoid *) &deptno, + (sword) sizeof(deptno), SQLT_INT, (dvoid *) 0, + (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT)) || + (status = OCIBindByName(stmthp, &bnd5p, errhp, (text *) ":EMPNO", + -1, (dvoid *) &empno, + (sword) sizeof(empno), SQLT_INT, (dvoid *) 0, + (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT))) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + /* Bind the placeholder in the "seldept" statement. */ + if (status = OCIBindByPos(stmthp1, &bnd6p, errhp, 1, + (dvoid *) &deptno, (sword) sizeof(deptno),SQLT_INT, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + /* Allocate the dept buffer now that you have length. */ + /* the deptlen should eventually get from dschndl3. */ + deptlen = 14; + dept = (text *) malloc((size_t) deptlen + 1); + + /* Define the output variable for the select-list. */ + if (status = OCIDefineByPos(stmthp1, &defnp, errhp, 1, + (dvoid *) dept, deptlen+1, SQLT_STR, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + for (;;) + { + /* Prompt for employee name. Break on no name. */ + printf("\nEnter employee name (or CR to EXIT): "); + fgets((char *) ename, (int) enamelen+1, stdin); + cp = (text *) strchr((char *) ename, '\n'); + if (cp == ename) + { + printf("Exiting... "); + cleanup(); + return OCI_SUCCESS; + } + if (cp) + *cp = '\0'; + else + { + printf("Employee name may be truncated.\n"); + myfflush(); + } + /* Prompt for the employee's job and salary. */ + printf("Enter employee job: "); + job_ind = 0; + fgets((char *) job, (int) joblen + 1, stdin); + cp = (text *) strchr((char *) job, '\n'); + if (cp == job) + { + job_ind = -1; /* make it NULL in table */ + printf("Job is NULL.\n");/* using indicator variable */ + } + else if (cp == 0) + { + printf("Job description may be truncated.\n"); + myfflush(); + } + else + *cp = '\0'; + + printf("Enter employee salary: "); + scanf("%d", &sal); + myfflush(); + sal_ind = (sal <= 0) ? -2 : 0; /* set indicator variable */ + + /* + * Prompt for the employee's department number, and verify + * that the entered department number is valid + * by executing and fetching. + */ + do + { + printf("Enter employee dept: "); + scanf("%d", &deptno); + myfflush(); + if ((status = OCIStmtExecute(svchp, stmthp1, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT)) + && (status != OCI_NO_DATA)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + if (status == OCI_NO_DATA) + printf("The dept you entered doesn't exist.\n"); + } while (status == OCI_NO_DATA); + + /* + * Increment empno by 10, and execute the INSERT + * statement. If the return code is 1 (duplicate + * value in index), then generate the next + * employee number. + */ + empno += 10; + if ((status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT)) + && status != 1) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + while (status == 1) + { + empno += 10; + if ((status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT)) + && status != 1) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + } /* end for (;;) */ + + /* Commit the change. */ + if (status = OCITransCommit(svchp, errhp, 0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + printf("\n\n%s added to the %s department as employee number %d\n", + ename, dept, empno); + } +} + + +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +/* + * Exit program with an exit code. + */ +void cleanup() +{ + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, OCI_HTYPE_ENV); + return; +} + + +void myfflush() +{ + eb1 buf[50]; + + fgets((char *) buf, 50, stdin); +} + + +/* end of file cdemo81.c */ + diff --git a/cdemo82.c b/cdemo82.c new file mode 100644 index 0000000..75ae307 --- /dev/null +++ b/cdemo82.c @@ -0,0 +1,514 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemo82.c 04-apr-2005.17:08:37 lzhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1996, 2005, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemo82.c - oci adt sample program ; run cdemo82.sql + + MODIFIED (MM/DD/YY) + lzhao 04/04/05 - bug4184289 + akatti 11/05/99 - [987191]:consider ret value of OCIDescribeAny + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + svedala 02/17/98 - OCI obsoletion changes + echen 06/03/97 - fix name resolution problem + cchau 05/19/97 - change OCITypeByName to OCIDescribeAny + azhao 01/30/97 - fix lint error + azhao 01/11/97 - also check OCI_SUCCESS_WITH_INFO in fetch + echen 01/03/97 - remove obsoleve type + azhao 07/18/96 - use OCI_PIN_ANY,OCI_PIN_LATEST for ogiopin + dchatter 07/18/96 - change ifdef for including cdemo82.h + slari 07/15/96 - Creation + +*/ + +#ifndef CDEMO82_ORACLE +#include +#endif + +#include + +#define SCHEMA "CDEMO82" + + +/*****************************************************************************/ +static void pin_display_addr(envhp, errhp, addrref) +OCIEnv *envhp; +OCIError *errhp; +OCIRef *addrref; +{ + sword status; + address *addr = (address *)0; + + checkerr(errhp, OCIObjectPin(envhp, errhp, addrref, (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&addr)); + + if (addr) + { + printf("address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), OCIStringPtr(envhp, addr->zip)); + } + else + { + printf("Pinned address pointer is null\n"); + } + + checkerr(errhp, OCIObjectUnpin(envhp, errhp, (dvoid *) addr)); +} + +/*****************************************************************************/ +static void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + ub4 buflen; + ub4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, (sb4 *)&errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + printf("Error - %s\n", errbuf); + break; + case OCI_INVALID_HANDLE: + printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + +/*****************************************************************************/ +/* +** Execute "selvalstmt" statement which selects records +** from a table with an ADT. +*/ +static void selectval(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIType *addr_tdo = (OCIType *) 0; + OCIDefine *defn1p = (OCIDefine *) 0, *defn2p = (OCIDefine *) 0; + address *addr = (address *)NULL; + sword custno =0; + int i = 0; + OCIRef *addrref = (OCIRef *) 0; + OCIRef *type_ref = (OCIRef *) 0; + sb4 status; + OCIDescribe *dschp = (OCIDescribe *) 0; + OCIParam *parmp; + sword retval; + + /* allocate describe handle for OCIDescribeAny */ + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + /* define the application request */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selvalstmt, + (ub4) strlen((char *)selvalstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + /* bind the input variable */ + checkerr(errhp, OCIDefineByPos(stmthp, &defn1p, errhp, + (ub4) 1, (dvoid *) &custno, + (sb4) sizeof(sword), SQLT_INT, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defn2p, errhp, (ub4) 2, (dvoid *) 0, + (sb4) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, (ub4) OCI_DEFAULT)); + + /* checkerr(errhp, OCITypeByName(envhp, errhp, svchp, (const text *) 0, + (ub4) 0, (const text *) "ADDRESS_VALUE", + (ub4) strlen((const char *) "ADDRESS_VALUE"), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, + &addr_tdo)); */ + + /* Bug 987191 - if describe call fails, no OCIAttrGet on desc handle */ + if ((retval = OCIDescribeAny(svchp, errhp, (text *)"ADDRESS_VALUE", + (ub4) strlen((char *)"ADDRESS_VALUE"), OCI_OTYPE_NAME, + (ub1)1, (ub1) OCI_PTYPE_TYPE, dschp)) != OCI_SUCCESS) + { + if (retval == OCI_NO_DATA) + { + printf("NO DATA: OCIDescribeAny on ADDRESS_VALUE\n"); + } + else + { + printf( "ERROR: OCIDescribeAny on ADDRESS_VALUE\n"); + checkerr(errhp, retval); + return; + } + } + else + { + checkerr(errhp, OCIAttrGet((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, errhp)); + + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &type_ref, (ub4 *) 0, + (ub4) OCI_ATTR_REF_TDO, (OCIError *) errhp)); + } + + checkerr(errhp, OCIObjectPin(envhp, errhp, type_ref, (OCIComplexObject *) 0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&addr_tdo)); + + if(!addr_tdo) + { + printf("NULL tdo returned\n"); + goto done_selectval; + } + + + checkerr(errhp, OCIDefineObject(defn2p, errhp, addr_tdo, (dvoid **) &addr, + (ub4 *) 0, (dvoid **) 0, (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + /* execute and fetch */ + do + { + if (addr) + printf("custno = %d address.state = %.2s address.zip = %.10s\n", custno, + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + else + printf("custno = %d fetched address is NULL\n", custno); + + addr = (address *)NULL; + } + while ((status = OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)) == OCI_SUCCESS || + status == OCI_SUCCESS_WITH_INFO); + + + if ( status!= OCI_NO_DATA ) + checkerr(errhp, status); + + printf("\n\n"); + + done_selectval: + + i = 0; /* dummy statement, need something after label */ +/* + checkerr(errhp, OCIHandleFree((dvoid *) defn1p, (ub4) OCI_HTYPE_DEFINE)); + checkerr(errhp, OCIHandleFree((dvoid *) defn2p, (ub4) OCI_HTYPE_DEFINE)); +*/ + +} + +/*****************************************************************************/ +/* +** Execute "selobjstmt" statement which selects records +** from a table with a ref. +*/ +static void selectobj(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIType *addr_tdo = (OCIType *) 0; + OCIDefine *defn1p = (OCIDefine *) 0, *defn2p = (OCIDefine *) 0; + sword status; + OCIRef *addrref = (OCIRef *) 0, *addrref1 = (OCIRef *) 0; + sword custno =0; + int i = 0; + address *addr; + ub4 ref_len; + + + /* define the application request */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selobjstmt, + (ub4) strlen((char *)selobjstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defn1p, errhp, (ub4) 1, + (dvoid *) &custno, + (sb4) sizeof(sword), SQLT_INT, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, (ub4) OCI_DEFAULT)); + + addrref = (OCIRef *)NULL; + checkerr(errhp, OCIDefineByPos(stmthp, &defn2p, errhp, (ub4) 2, + (dvoid *) NULL, + (sb4) 0, SQLT_REF, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineObject(defn2p, errhp, (OCIType *)NULL, + (dvoid **)&addrref, + &ref_len, (dvoid **)0, (ub4 *)0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + do + { + printf("custno = %d fetched address\n", custno); + + if ( addrref ) + { + pin_display_addr(envhp, errhp, addrref); + } + else + printf("Address ref is NULL\n"); + + } + while ((status = OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)) == OCI_SUCCESS || + status == OCI_SUCCESS_WITH_INFO); + + + if ( status != OCI_NO_DATA ) + checkerr(errhp, status); + + printf("\n\n"); +/* + checkerr(errhp, OCIHandleFree((dvoid *) defn1p, (ub4) OCI_HTYPE_DEFINE)); + checkerr(errhp, OCIHandleFree((dvoid *) defn2p, (ub4) OCI_HTYPE_DEFINE)); +*/ + +} + + +/*****************************************************************************/ +/* + ** execute "insstmt" + ** + */ +static void insert(envhp, svchp, stmthp, errhp, insstmt, nrows) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +text *insstmt; +ub2 nrows; +{ + OCIType *addr_tdo = (OCIType *) 0; + address addrs; + null_address naddrs; + address *addr = &addrs; + null_address *naddr = &naddrs; + sword custno =300; + OCIBind *bnd1p = (OCIBind *) 0, *bnd2p = (OCIBind *) 0; + char buf[20]; + ub2 i; + OCIRef *type_ref = (OCIRef *) 0; + OCIDescribe *dschp = (OCIDescribe *) 0; + OCIParam *parmp; + sword retval; + + /* allocate describe handle for OCIDescribeAny */ + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + /* define the application request */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) insstmt, + (ub4) strlen((char *)insstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + /* bind the input variable */ + checkerr(errhp, OCIBindByName(stmthp, &bnd1p, errhp, (text *) ":custno", + (sb4) -1, (dvoid *) &custno, + (sb4) sizeof(sword), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, (ub4) 0, (ub4 *) 0, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIBindByName(stmthp, &bnd2p, errhp, (text *) ":addr", + (sb4) -1, (dvoid *) 0, + (sb4) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + /* checkerr(errhp, OCITypeByName(envhp, errhp, svchp, (const text *) 0, + (ub4) 0, (const text *) "ADDRESS_VALUE", + (ub4) strlen((const char *) "ADDRESS_VALUE"), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, + &addr_tdo)); */ + + /* Bug 987191-if describe call fails, don't call OCIAttrGet on dsc handle */ + if ((retval = OCIDescribeAny(svchp, errhp, (text *)"ADDRESS_VALUE", + (ub4) strlen((char *)"ADDRESS_VALUE"), OCI_OTYPE_NAME, + (ub1)1, (ub1) OCI_PTYPE_TYPE, dschp)) != OCI_SUCCESS) + { + if (retval == OCI_NO_DATA) + { + printf("NO DATA: OCIDescribeAny on ADDRESS_VALUE\n"); + } + else + { + printf( "ERROR: OCIDescribeAny on ADDRESS_VALUE\n"); + checkerr(errhp, retval); + return; + } + } + else + { + checkerr(errhp, OCIAttrGet((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, errhp)); + + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &type_ref, (ub4 *) 0, + (ub4) OCI_ATTR_REF_TDO, (OCIError *) errhp)); + } + + checkerr(errhp, OCIObjectPin(envhp, errhp, type_ref, (OCIComplexObject *) 0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&addr_tdo)); + + if(!addr_tdo) + { + printf("Null tdo returned\n"); + goto done_insert; + } + + checkerr(errhp, OCIBindObject(bnd2p, errhp, addr_tdo, (dvoid **) &addr, + (ub4 *) 0, (dvoid **) &naddr, (ub4 *) 0)); + + for(i = 0; i <= nrows; i++) + { + addr->state = (OCIString *) 0; + sprintf(buf, "%cA", 65+i%27); + checkerr(errhp, OCIStringAssignText(envhp, errhp, + (CONST text*) buf, 2, &addr->state)); + addr->zip = (OCIString *) 0; + sprintf(buf, "94%d ", i+455); + checkerr(errhp, OCIStringAssignText(envhp, errhp, (CONST text*) buf, 10, + &addr->zip)); + + naddr->null_adt = 0; + naddr->null_state = 0; + naddr->null_zip = 0; + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + } + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + done_insert: + + i = 0; /* dummy statement, need something after label */ + +/* + checkerr(errhp, OCIHandleFree((dvoid *) bnd1p, (ub4) OCI_HTYPE_BIND)); + checkerr(errhp, OCIHandleFree((dvoid *) bnd2p, (ub4) OCI_HTYPE_BIND)); +*/ + +} + +/*****************************************************************************/ +int main() +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCIStmt *stmthp; + OCISession *usrhp; + + OCIInitialize((ub4) OCI_THREADED | OCI_OBJECT, (dvoid *)0, + (dvoid * (*)()) 0, (dvoid * (*)()) 0, (void (*)()) 0 ); + + OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &envhp, (ub4) OCI_HTYPE_ENV, + 52, (dvoid **) &tmp); + + OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp); + + OCIServerAttach( srvhp, errhp, (text *) 0, (sb4) 0, (ub4) OCI_DEFAULT); + + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp); + + /* set attribute server context in the service context */ + OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp); + + /* allocate a user context handle */ + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"cdemo82", (ub4)strlen((char *)"cdemo82"), + OCI_ATTR_USERNAME, errhp); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"cdemo82", (ub4)strlen((char *)"cdemo82"), + OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, + OCI_CRED_RDBMS, OCI_DEFAULT)); + + OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, + OCI_ATTR_SESSION, errhp); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, 50, (dvoid **) &tmp)); + + /* execute "insstmt" */ + printf("--- Test insertion into extent table.\n"); + insert(envhp, svchp, stmthp, errhp, insstmt, 26); + + /* execute "selstmt" */ + printf("--- Test selection of a table with one ADT column.\n"); + selectval(envhp, svchp, stmthp, errhp); + + + /* execute "selobjstmt" */ + printf("--- Test selection of a table with one ADT REF.\n"); + selectobj(envhp, svchp, stmthp, errhp); + + + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT)); + + OCISessionEnd(svchp, errhp, usrhp, (ub4)OCI_DEFAULT); + OCIServerDetach( srvhp, errhp, (ub4) OCI_DEFAULT ); + checkerr(errhp, OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER)); + checkerr(errhp, OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX)); + checkerr(errhp, OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR)); + +} + +/* end of file cdemo82.c */ + diff --git a/cdemo82.h b/cdemo82.h new file mode 100644 index 0000000..6b34eac --- /dev/null +++ b/cdemo82.h @@ -0,0 +1,155 @@ +/* + * $Header: cdemo82.h 07-jun-2005.11:41:35 aliu Exp $ + */ + +/* Copyright (c) 1996, 2005, Oracle. All rights reserved. +*/ + +/* + NAME + cdemo82.h - header file for oci adt sample program + + MODIFIED (MM/DD/YY) + aliu 06/06/05 - fix lrg 1844051 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + echen 06/03/97 - fix name resolution problem + azhao 01/30/97 - fix lint error + echen 01/03/97 - remove obsoleve type + azhao 07/18/96 - not to include s.h + dchatter 07/18/96 - delete spurious .h files + slari 07/15/96 - Creation + +*/ + + +#ifndef CDEMO82_ORACLE +# define CDEMO82_ORACLE + +#ifndef OCI_ORACLE +#include +#endif + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +#define SERVER "ORACLE" +#define ADDRESS_TYPE_NAME "ADDRESS_OBJECT" +#define EMB_ADDRESS_TYPE_NAME "EMBEDDED_ADDRESS" +#define ADDREXT "ADDREXT" +#define EMBADDREXT "EMBADDREXT" +#define RETURN_ON_ERROR(error) if (error) return (error) +#define BIG_RECORD_SIZE 1000 + + + +struct address +{ + OCIString *state; + OCIString *zip; +}; +typedef struct address address; + +struct null_address +{ + sb4 null_adt; + sb4 null_state; + sb4 null_zip; +}; +typedef struct null_address null_address; + +struct embaddress +{ + OCIString *state; + OCIString *zip; + OCIRef *preaddrref; +}; +typedef struct embaddress embaddress; + + +struct null_embaddress +{ + sb4 null_state; + sb4 null_zip; + sb4 null_preaddrref; +}; +typedef struct null_embaddress null_embaddress; + +struct person +{ + OCIString *name; + OCINumber age; + address addr; +}; +typedef struct person person; + +struct null_person +{ + sb4 null_name; + sb4 null_age; + null_address null_addr; +}; + +typedef struct null_person null_person; + +static const text *const names[] = +{(text *) "CUSTOMERVAL", (text *) "ADDRESS", (text *) "STATE"}; + +static const text *const selvalstmt = (text *) + "SELECT custno, addr FROM customerval order by custno, addr.zip"; + +static const text *const selobjstmt = (text *) + "SELECT custno, addr FROM customerobj order by custno, addr.zip"; + +static const text *const selref = (text *) + "SELECT REF(e) from extaddr e"; + +static const text *const deleteref = (text *) + "DELETE extaddr"; + +static const text *const insertref = (text *) +"insert into extaddr values(address_object('CA', '98765'))"; + +static const text *const modifyref = (text *) +"update extaddr set object_column = address_object('TX', '61111')"; + +static const text *const selembref = (text *) + "SELECT REF(emb) from embextaddr emb"; + +static const text *const bndref = (text *) +"update extaddr set object_column.state = 'GA' where object_column = :addrref"; + +static const text *const insstmt = +(text *)"INSERT INTO customerval (custno, addr) values (:custno, :addr)"; + +dvoid *tmp; + + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ +OCIRef *cbfunc(/*_ dvoid *context _*/); + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void selectval(/*_ OCIEnv *envhp, OCISvcCtx *svchp, + OCIStmt *stmthp, OCIError *errhp _*/); +static void selectobj(/*_ OCIEnv *envhp, OCISvcCtx *svchp, + OCIStmt *stmthp, OCIError *errhp _*/); +static void insert(/*_ OCIEnv *envhp, OCISvcCtx *svchp, + OCIStmt *stmthp, OCIError *errhp, + text *insstmt, ub2 nrows _*/); + +static void pin_display_addr(/*_ OCIEnv *envhp, OCIError *errhp, + OCIRef *addrref _*/); + +int main(/*_ void _*/); + + + +#endif /* cdemo82 */ diff --git a/cdemo82.sql b/cdemo82.sql new file mode 100644 index 0000000..1d1e582 --- /dev/null +++ b/cdemo82.sql @@ -0,0 +1,132 @@ +rem +rem $Header: cdemo82.sql 18-jun-2004.14:31:26 stsun Exp $ +rem +rem cdemo82.sql +rem +rem Copyright (c) 1996, 2004, Oracle. All rights reserved. +rem +rem NAME +rem cdemo82.sql - sql to be executed before cdemo82 +rem +rem DESCRIPTION +rem +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem stsun 06/18/04 - system/manager instead of sysdba +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem svedala 09/11/98 - a "/" required after create type - bug 717842 +rem cchau 08/18/97 - enable dictionary protection +rem echen 06/03/97 - fix name resolution problem +rem azhao 04/02/97 - add as object for create type +rem dchatter 07/19/96 - scott/tiger to cdemo82/cdemo82 +rem slari 07/15/96 - Created +rem + +REMARK >>>> Set System Variables For Current SQLPlus Session <<<< +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET PAGESIZE 100 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET DEFINE '^' + +set echo on; + +connect system/manager; + +drop user cdemo82 cascade; + +create user cdemo82 identified by cdemo82; + +grant connect, resource to cdemo82; + +connect cdemo82/cdemo82; + +drop table customerval; + +drop table customerobj; + +drop table extaddr; + +drop table embextaddr; + +drop type embedded_address; + +drop type address_object; + +drop type person; + +drop table emp; + +create type address_object as object (state char(2), zip char(10)); +/ + +create type embedded_address as object (state char(2), zip char(10), + preaddr REF address_object); +/ + +drop type address_value; + +create type address_value as object (state char(2), zip char(10)); +/ + +create table customerval (custno number, addr address_value); + +insert into customerval values(100, address_value('CA', '94065')); + +create table extaddr of address_object; + +create table customerobj (custno number, addr REF address_object); + +insert into extaddr values (address_object('CA', '94065')); + +insert into customerobj values(1000, null); + +update customerobj + set addr = (select ref(e) from extaddr e where e.zip='94065'); + +insert into extaddr values (address_object('CA', '98765')); + +insert into extaddr values (address_object('CA', '95117')); + +select REFTOHEX(ref(e)) from extaddr e; + +create table embextaddr of embedded_address; + +insert into embextaddr values (embedded_address('CA', '95117', NULL)); + +drop table extper; + +drop table empref; + +drop table emp; + +drop type person; + +create type person as object ( name char(20), age number, + address address_object ); +/ + +create table emp (emp_id number, emp_info person); + +create table empref (emp_id number, emp_info REF person); + +create table extper of person; + +create or replace procedure upd_addr(addr IN OUT address_object) is +begin + addr.state := 'CA'; + addr.zip := '95117'; +end; +/ + +commit; + +set echo off; + + + diff --git a/cdemoanydata1.c b/cdemoanydata1.c new file mode 100644 index 0000000..689e6e5 --- /dev/null +++ b/cdemoanydata1.c @@ -0,0 +1,775 @@ +/* Copyright (c) 2001, 2002, Oracle Corporation. All rights reserved. */ + +/* + + NAME + cdemoAnyData1.c - OCI demo program for ANYDATA. + + DESCRIPTION + An example program which inserts and selects rows of data to + and from anydatatab. + Rows are inserted into anydatatab by converting to ANYDATA + from the following types: NUMBER, VARCHAR2, DATE, + ADDRESS_OBJECT, CHAR, RAW, and COLLECTION in the above oder. + Then rows are fetched and COL2 accessed from ANYDATA + in the same order. + SQL> describe anydatatab; + Name Null? Type + ------------------------- -------- --------------- + COL1 NUMBER + COL2 SYS.ANYDATA + SQL> describe address_object; + Name Null? Type + ------------------------- -------- --------------- + STATE VARCHAR2(3) + ZIP VARCHAR2(13) + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + Dependent Files: + cdemoAnyData1.sql - SQL script to be run before execution. + + MODIFIED (MM/DD/YY) + jchai 06/13/02 - fix bug 2360431 + ani 09/17/01 - OCIAnyDataAccess changes for Number,Date + ani 04/30/01 - Merged ani_ocidemo + ani 04/24/01 - Creation + +*/ + +#include +#include +#include + +#ifndef OCI_ORACLE +#include +#endif + +#define BUFLEN 20 +#define ADDR_SETNOTNULL(nind) (memset(nind, (char)0, 3*sizeof(OCIInd))); + +typedef struct cdemoanctx +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCISvcCtx *svchp; + OCIError *errhp; + OCISession *authp; + OCIStmt *stmthp; +} cdemoanctx; + +struct address +{ + OCIString *state; /* text state[3]; */ + OCIString *zip; /* text zip[11]; */ +}; +typedef struct address address; + +struct null_address +{ + sb2 null_address; + sb2 null_state; + sb2 null_zip; +}; +typedef struct null_address null_address; + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +static text *username = (text *) "scott"; +static text *password = (text *) "tiger"; + +/* Define SQL statements to be used in program. */ +static text *inst1 = (text *)"INSERT INTO anydatatab VALUES (:first_col, :oan_buffer)"; +static text *sel1 = (text *)"SELECT * FROM anydatatab WHERE col1 = "; + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ +static void initialize(cdemoanctx *ctxptr); +static void create_table(cdemoanctx *ctxptx); +static void drop_table(cdemoanctx *ctxptx); +static void sql_exec_insert(/*_ cdemoanctx *ctxptr, ub2 typecode, ub4 index _*/); +static void sql_exec_select(/*_ cdemoanctx *ctxptr, OCITypeCode typecode, ub4 recnum _*/); +static void cleanup(cdemoanctx *ctxptr); +static void checkerr(OCIError *errhp, sword status); +int main(); + + +int main() +{ + cdemoanctx ctx; + + printf("\n ######## start executing test ############ \n"); + + initialize(&ctx); + + /* execute sql statement */ + sql_exec_insert(&ctx, OCI_TYPECODE_NUMBER, 1); + sql_exec_insert(&ctx, OCI_TYPECODE_VARCHAR2, 2); + sql_exec_insert(&ctx, OCI_TYPECODE_DATE, 3); + sql_exec_insert(&ctx, OCI_TYPECODE_OBJECT, 4); + sql_exec_insert(&ctx, OCI_TYPECODE_CHAR, 5); + sql_exec_insert(&ctx, OCI_TYPECODE_RAW, 6); + sql_exec_insert(&ctx, OCI_TYPECODE_NAMEDCOLLECTION, 7); + + sql_exec_select(&ctx, OCI_TYPECODE_NUMBER, 1); + sql_exec_select(&ctx, OCI_TYPECODE_VARCHAR2, 2); + sql_exec_select(&ctx, OCI_TYPECODE_DATE, 3); + sql_exec_select(&ctx, OCI_TYPECODE_OBJECT, 4); + sql_exec_select(&ctx, OCI_TYPECODE_CHAR, 5); + sql_exec_select(&ctx, OCI_TYPECODE_RAW, 6); + sql_exec_select(&ctx, OCI_TYPECODE_NAMEDCOLLECTION, 7); + + /* clean things up before exhit */ + cleanup(&ctx); + return 1; + +} /*end main*/ + + +/********************************************************************* + * execute insert statement * + * This function converts data of given type specified by parameter * + * "typecode" to OCIANYDATA, then insert OCIANYDATA into datatabase * + * table named anydatatab. * + *********************************************************************/ +void sql_exec_insert(ctxptr, typecode, index) +cdemoanctx *ctxptr; +ub2 typecode; +ub4 index; +{ + OCIBind *bndp1 = (OCIBind *) NULL; + OCIBind *bndp2 = (OCIBind *) NULL; + + OCIType *any_tdo = (OCIType *)0; + OCIInd indp = OCI_IND_NOTNULL; + OCIInd *any_indp = (OCIInd *)0; + OCIAnyData *oan_buffer = (OCIAnyData *)0; + OCIType *addr_tdo = (OCIType *)0; + dvoid *addr = (dvoid *)0; + address *addr_obj = (address *)0; + + ub4 first_col = index; + ub4 any_number, i; + OCINumber num; + OCIString *str = (OCIString *) 0; + OCIDate date; + + OCIDuration dur; + OCIParam *type_info = (OCIParam *)0; + OCIRaw *raw_col = (OCIRaw *)0; + ub1* raw_ptr; + ub1 lbuf1[BUFLEN]; + dvoid *nind = (dvoid *)0; + /*text zip[6] = "00000";*/ + char zip[6] = "00000"; + + OCITable *addr_tab = (OCITable *) 0; + OCIType *addr_tab_tdo = (OCIType *)0; + sb4 collsiz; + /*address *addr = (address *)0, *addr2 = (address *)0;*/ + boolean exist; + /*sb4 index;*/ + dvoid *elem = (dvoid *)0; + dvoid *elemind = (dvoid *)0; + OCIInd *addr_tab_null=(OCIInd *)0; + address *addr_coll[3]; + + + printf("Testing INSERT ... \n"); + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, + ctxptr->errhp, inst1, (ub4) strlen((char *)inst1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCITypeByName(ctxptr->envhp, + ctxptr->errhp, ctxptr->svchp, + (CONST text *)"SYS", (ub4) strlen("SYS"), + (CONST text *) "ANYDATA", (ub4) strlen("ANYDATA"), + (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_ALL, &any_tdo)); + checkerr(ctxptr->errhp, OCITypeByName(ctxptr->envhp, + ctxptr->errhp, ctxptr->svchp, + (CONST text *)"", (ub4) strlen(""), + (CONST text *) "ADDRESS_OBJECT", + (ub4) strlen("ADDRESS_OBJECT"), + (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_ALL, &addr_tdo)); + + /* prepare data for insertion */ + switch (typecode) + { + case OCI_TYPECODE_NUMBER: + any_number = 10; + checkerr(ctxptr->errhp, OCINumberFromInt(ctxptr->errhp, + &any_number, sizeof(any_number), + OCI_NUMBER_UNSIGNED, &num)); + + checkerr(ctxptr->errhp, OCIAnyDataConvert(ctxptr->svchp, + ctxptr->errhp, (OCITypeCode)OCI_TYPECODE_NUMBER, + (OCIType *)0, OCI_DURATION_SESSION, (dvoid *)&indp, + (dvoid *)&num, 0, &oan_buffer)); + break; + + case OCI_TYPECODE_VARCHAR2: + OCIStringAssignText(ctxptr->envhp, ctxptr->errhp, + (text *)"TestString", 10, &str); + checkerr(ctxptr->errhp, OCIAnyDataConvert(ctxptr->svchp, + ctxptr->errhp,(OCITypeCode)OCI_TYPECODE_VARCHAR2, + (OCIType *)0, OCI_DURATION_SESSION, (dvoid *)&indp, + (dvoid *) str, 0, &oan_buffer)); + break; + + case OCI_TYPECODE_DATE: + OCIDateSetDate((OCIDate *) &date, (sb2)2000, (ub1) 7, (ub1)31); + checkerr(ctxptr->errhp, OCIAnyDataConvert(ctxptr->svchp, + ctxptr->errhp, (OCITypeCode)OCI_TYPECODE_DATE, + (OCIType *)0, OCI_DURATION_SESSION, (dvoid *)&indp, + (dvoid *)&date, 0, &oan_buffer)); + break; + + case OCI_TYPECODE_CHAR: + OCIStringAssignText(ctxptr->envhp, ctxptr->errhp, + (text *)"CHARString", 10, &str); + checkerr(ctxptr->errhp, OCIAnyDataConvert(ctxptr->svchp, + ctxptr->errhp,(OCITypeCode)OCI_TYPECODE_CHAR, + (OCIType *)0, OCI_DURATION_SESSION, (dvoid *)&indp, + (dvoid *) str, 0, &oan_buffer)); + break; + + case OCI_TYPECODE_OBJECT: + if ( OCIObjectNew(ctxptr->envhp, ctxptr->errhp, + ctxptr->svchp, OCI_TYPECODE_OBJECT, + addr_tdo, (dvoid *) 0, + OCI_DURATION_DEFAULT, TRUE, + (dvoid **) &addr_obj) != OCI_SUCCESS) + { + printf("object new error \n"); + exit(0); /*no point of proceeding */ + } + + OCIStringAssignText(ctxptr->envhp, ctxptr->errhp, + (text *)"NV", 2, &addr_obj->state); + OCIStringAssignText(ctxptr->envhp, ctxptr->errhp, + (text *)"11111", 5, &addr_obj->zip); + + OCIObjectGetInd(ctxptr->envhp, ctxptr->errhp, (dvoid *)addr_obj, &nind); + ADDR_SETNOTNULL(nind); + + checkerr(ctxptr->errhp, OCIAnyDataConvert(ctxptr->svchp, + ctxptr->errhp, OCI_TYPECODE_OBJECT, + addr_tdo, OCI_DURATION_SESSION, (dvoid *)nind, + addr_obj, 0, &oan_buffer)); + break; + + case OCI_TYPECODE_RAW: + for (i = 0; i < BUFLEN; i++) + lbuf1[i] = (ub1) 'R'; + checkerr(ctxptr->errhp, OCIRawAssignBytes(ctxptr->envhp, + ctxptr->errhp, lbuf1, BUFLEN, &raw_col)); + checkerr(ctxptr->errhp, OCIAnyDataConvert(ctxptr->svchp, + ctxptr->errhp, (OCITypeCode)OCI_TYPECODE_RAW, + (OCIType *)0, OCI_DURATION_SESSION, (dvoid *)&indp, + (dvoid *) raw_col, 0, &oan_buffer)); + break; + + case OCI_TYPECODE_NAMEDCOLLECTION: + checkerr(ctxptr->errhp, OCITypeByName(ctxptr->envhp, + ctxptr->errhp, ctxptr->svchp, + (CONST text *)"", (ub4) strlen(""), + (const text *) "ADDR_TAB", + (ub4) strlen((const char *) "ADDR_TAB"), + (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_ALL, &addr_tab_tdo)); + + checkerr(ctxptr->errhp, OCIObjectNew(ctxptr->envhp, ctxptr->errhp, + ctxptr->svchp, OCI_TYPECODE_NAMEDCOLLECTION, + addr_tab_tdo, (dvoid *) 0, + OCI_DURATION_DEFAULT, TRUE, + (dvoid **) &addr_tab)); + + for(i=0;i<3;i++) { + addr_coll[i] = (address *) 0; + checkerr(ctxptr->errhp, OCIObjectNew(ctxptr->envhp, ctxptr->errhp, + ctxptr->svchp, OCI_TYPECODE_OBJECT, addr_tdo, (dvoid *) 0, + OCI_DURATION_DEFAULT, TRUE, (dvoid **) &addr_coll[i])); + OCIStringAssignText(ctxptr->envhp, ctxptr->errhp, + (text *)"CA", 2, &addr_coll[i]->state); + (void) sprintf((char *) zip, "%s%d", "9406", i); + OCIStringAssignText(ctxptr->envhp, ctxptr->errhp, + (text *) zip, 5, &addr_coll[i]->zip); + checkerr(ctxptr->errhp, OCICollAppend(ctxptr->envhp, ctxptr->errhp, + addr_coll[i], addr_tab_null, (OCIColl *)addr_tab)); + } + + OCIObjectGetInd(ctxptr->envhp, ctxptr->errhp, (dvoid *)addr_tab, &nind); + ADDR_SETNOTNULL(nind); + + checkerr(ctxptr->errhp, OCIAnyDataConvert(ctxptr->svchp, + ctxptr->errhp, OCI_TYPECODE_NAMEDCOLLECTION, + addr_tab_tdo, OCI_DURATION_SESSION, (dvoid *)nind, + addr_tab, 0, &oan_buffer)); + + break; + } + + /* + * associate items in insert statement with output buffer variables + */ + checkerr(ctxptr->errhp,OCIBindByName(ctxptr->stmthp,&bndp1, + ctxptr->errhp, (text *) ":first_col", (sb4) -1, + (dvoid*) &first_col, (sb4) sizeof(sword), (ub2)SQLT_INT, + (dvoid*) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, + (ub4) OCI_DEFAULT)); + checkerr(ctxptr->errhp, OCIBindByName(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (text *) ":oan_buffer", (sb4)-1, + (dvoid *)0, (sb4) 0, (ub2)SQLT_NTY, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4) 0, (ub4 *) 0, (ub4)OCI_DEFAULT)); + checkerr(ctxptr->errhp, OCIBindObject(bndp2, ctxptr->errhp, + any_tdo, (dvoid **) &oan_buffer, (ub4 *) 0, + (dvoid **)&any_indp, (ub4 *) 0)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, ctxptr->errhp, + (ub4)1, (ub4)0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4)OCI_DEFAULT)); + + OCIAnyDataDestroy(ctxptr->svchp, ctxptr->errhp, oan_buffer); + +} /* end sql_exe_insert() */ + + +/********************************************************************* + * execute select statement * + * This function selects OCIANYDATA from table anydatatab, retrieves * + * the type information from resulting OCIANYDATA and accesses data * + * according to the type using OCIANYDATACCESS(). + *********************************************************************/ +void sql_exec_select(ctxptr, typecode, recnum) +cdemoanctx *ctxptr; +OCITypeCode typecode; +ub4 recnum; +{ + sword col1; + OCIDefine *defnp1 = (OCIDefine *) NULL; + OCIDefine *defnp2 = (OCIDefine *) NULL; + + OCIType *any_tdo = (OCIType *)0; + OCIType *addr_tdo = (OCIType *)0; + address *addr_obj = (address *)0; + OCIType *type = (OCIType *)0; + OCITypeCode tc; + OCIInd indp; + OCIInd *any_indp = (OCIInd *) 0; + + OCIAnyData *oan_buffer = (OCIAnyData *)0; + ub4 len, col2, i; + OCINumber num; + OCINumber *num_ptr = # + OCIString *str = (OCIString *) 0; + OCIDate date; + OCIDate *date_ptr = &date; + text sel_stmt[200]; + sb2 year1; + ub1 month1, day1; + OCIRaw *raw_col = (OCIRaw *)0; + ub1 *raw_ptr = (ub1 *)0; + + OCITable *addr_tab = (OCITable *) 0; + OCIType *addr_tab_tdo = (OCIType *)0; + sb4 collsiz; + address *addr = (address *)0, *addr2 = (address *)0; + boolean exist; + sb4 index; + dvoid *elem = (dvoid *)0; + dvoid *elemind = (dvoid *)0; + + OCIInd ind2=OCI_IND_NOTNULL; + OCIInd *ind2p = &ind2; + + + checkerr(ctxptr->errhp, OCITypeByName(ctxptr->envhp, + ctxptr->errhp, ctxptr->svchp, + (const text *) "", (ub4) strlen((const char *) ""), + (const text *) "ADDRESS_OBJECT", + (ub4) strlen((const char *) "ADDRESS_OBJECT"), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &addr_tdo)); + + (void) sprintf((char *) sel_stmt, "%s%d", sel1, recnum); + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, + ctxptr->errhp, sel_stmt, (ub4) strlen((char *)sel_stmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("Testing SELECT ... \n"); + + checkerr(ctxptr->errhp, OCITypeByName(ctxptr->envhp, + ctxptr->errhp, ctxptr->svchp, + (CONST text *)"SYS", (ub4) strlen("SYS"), + (CONST text *) "ANYDATA", (ub4) strlen("ANYDATA"), + (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_ALL, &any_tdo)); + /* + * associate items in select statement with output buffer variables + */ + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp,(ub4) 1,(dvoid*) &col1, + (sb4) sizeof(col1), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4)2, (dvoid *)0, + (sb4) 0, (ub2)SQLT_NTY, (dvoid *)0, + (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT)); + checkerr(ctxptr->errhp, OCIDefineObject(defnp2, + ctxptr->errhp, any_tdo, + (dvoid **) &oan_buffer, (ub4 *) 0, + (dvoid **)&any_indp, (ub4 *) 0)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, ctxptr->stmthp, + ctxptr->errhp, (ub4)1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4)OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIAnyDataGetType(ctxptr->svchp, + ctxptr->errhp, (OCIAnyData *)oan_buffer, + (OCITypeCode *)&tc, (OCIType **)&type)); + + if(tc != typecode) + printf("ERROR: OCIAnyDataGetType retrieved wrong type information\n"); + + /* print out results */ + printf("Printing out select stmt results ... \n"); + printf("c1 is: %d\n",col1); + + switch (typecode) + { + case OCI_TYPECODE_NUMBER: + /*checkerr(ctxptr->errhp, + OCIAnyDataAccess(ctxptr->svchp, ctxptr->errhp, + oan_buffer, (OCITypeCode)OCI_TYPECODE_NUMBER, + (OCIType *)0, (dvoid *)&indp, (dvoid *)&num, &len)); + OCINumberToInt(ctxptr->errhp, &num, sizeof(col2), 0, &col2); */ + + checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, ctxptr->errhp, + oan_buffer, (OCITypeCode)OCI_TYPECODE_NUMBER, + (OCIType *)0, (dvoid *)&indp, (dvoid **)&num_ptr, &len)); + OCINumberToInt(ctxptr->errhp, num_ptr, sizeof(col2), 0, &col2); + + printf("c2 is: %d\n",col2); + break; + + case OCI_TYPECODE_VARCHAR2: + checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, ctxptr->errhp, + oan_buffer, (OCITypeCode)OCI_TYPECODE_VARCHAR2, + (OCIType *)0, (dvoid *)&indp, (dvoid *)&str, &len)); + + printf("c2 is %s \n", OCIStringPtr(ctxptr->envhp, str)); + break; + + case OCI_TYPECODE_DATE: + /*checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, + ctxptr->errhp, oan_buffer, + (OCITypeCode)OCI_TYPECODE_DATE, + (OCIType *)0, (dvoid *)&indp, (dvoid *)&date, &len)); + OCIDateGetDate( (CONST OCIDate *) &date, &year1, &month1, &day1 ); */ + + checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, + ctxptr->errhp, oan_buffer, + (OCITypeCode)OCI_TYPECODE_DATE, + (OCIType *)0, (dvoid *)&indp, + (dvoid **)&date_ptr, &len)); + OCIDateGetDate( (CONST OCIDate *) date_ptr, &year1, &month1, &day1 ); + + printf("c2 is %d/%d/%d\n", day1, month1, year1); + + break; + + case OCI_TYPECODE_OBJECT: + checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, ctxptr->errhp, + oan_buffer, (OCITypeCode) OCI_TYPECODE_OBJECT, + (OCIType *)addr_tdo, (dvoid *) &ind2p, + (dvoid **)&addr_obj, &len)); + printf("state is %s \n", + OCIStringPtr(ctxptr->envhp, addr_obj->state)); + printf("zip is %s \n", + OCIStringPtr(ctxptr->envhp, addr_obj->zip)); + break; + + case OCI_TYPECODE_CHAR: + checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, + ctxptr->errhp, oan_buffer, + (OCITypeCode)OCI_TYPECODE_CHAR, + (OCIType *)0, (dvoid *)&indp, (dvoid *)&str, &len)); + + printf("c2 is %s \n", OCIStringPtr(ctxptr->envhp, str)); + break; + + case OCI_TYPECODE_RAW: + checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, ctxptr->errhp, + oan_buffer, (OCITypeCode)OCI_TYPECODE_RAW, + (OCIType *)0, (dvoid *)&indp, (dvoid *)&raw_col, &len)); + + raw_ptr = OCIRawPtr(ctxptr->envhp, raw_col); + printf("RAW data is: "); + for(i=0;ierrhp, OCITypeByName(ctxptr->envhp, + ctxptr->errhp, ctxptr->svchp, + (CONST text *)"", (ub4) strlen(""), + (const text *) "ADDR_TAB", + (ub4) strlen((const char *) "ADDR_TAB"), + (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_ALL, &addr_tab_tdo)); + + checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, + ctxptr->errhp, oan_buffer, + (OCITypeCode)OCI_TYPECODE_NAMEDCOLLECTION, + (OCIType *) addr_tab_tdo, (dvoid *) &ind2p, + (dvoid *)&addr_tab, &len)); + + /* check how many elements in the typed table */ + checkerr(ctxptr->errhp, OCICollSize(ctxptr->envhp, ctxptr->errhp, + (CONST OCIColl *) addr_tab, &collsiz)); + printf("c2 is a typed table with %d elements:\n", collsiz); + if (collsiz == 0) + break; + + /*Dump the table from the top to the bottom. */ + /* go to the first element and print out the index */ + checkerr(ctxptr->errhp, OCITableFirst(ctxptr->envhp, + ctxptr->errhp, addr_tab, &index)); + checkerr(ctxptr->errhp, OCICollGetElem(ctxptr->envhp, + ctxptr->errhp, + (CONST OCIColl *) addr_tab, index, + &exist, &elem, &elemind)); + addr = (address *)elem; + + printf("\tAddress 1 is: %s", + OCIStringPtr(ctxptr->envhp,addr->state)); + printf("\t%s\n", OCIStringPtr(ctxptr->envhp, addr->zip)); + + for(;!OCITableNext(ctxptr->envhp, ctxptr->errhp, index, + addr_tab, &index, &exist) && exist;) + { + checkerr(ctxptr->errhp, OCICollGetElem(ctxptr->envhp, + ctxptr->errhp, + (CONST OCIColl *) addr_tab,index, + &exist, &elem, &elemind)); + addr = (address *)elem; + printf("\tAddress %d is: %s", index+1, + OCIStringPtr(ctxptr->envhp,addr->state)); + printf("\t%s\n", OCIStringPtr(ctxptr->envhp, addr->zip)); + } + break; + + DEFAULT: + printf("TYPED DATA CAN'T BE DISPLAYED IN THIS PROGRAM\n"); + break; + } +} /* end sql_exe_select() */ + + +/******************************************************* + * initialize envionment and handlers * + * * + *******************************************************/ + +void initialize(ctxptr) +cdemoanctx *ctxptr; +{ + + if (OCIEnvCreate((OCIEnv **) &ctxptr->envhp, + (ub4)OCI_THREADED|OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0, + (size_t) 0, (dvoid **) 0 )) + printf("FAILED: OCIEnvCreate()\n"); + + + printf("\n ######## Connect to server ############# \n"); + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, (dvoid **) &ctxptr->errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->errhp\n"); + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, (dvoid **) &ctxptr->srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->srvhp\n"); + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, (dvoid **) &ctxptr->svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->svchp\n"); + + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, (dvoid **) &ctxptr->authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->authp\n"); + + if (OCIServerAttach(ctxptr->srvhp, ctxptr->errhp, (text *) "", + (sb4) strlen((char *) ""), (ub4) OCI_DEFAULT)) + printf("FAILED: OCIServerAttach()\n"); + + if (OCIAttrSet((dvoid *) ctxptr->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) ctxptr->srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, + ctxptr->errhp)) + printf("FAILED: OCIAttrSet() server attribute\n"); + + + /*begin log_on part */ + + if (OCIAttrSet((dvoid *) ctxptr->authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) username, (ub4) strlen((char *) username), + (ub4) OCI_ATTR_USERNAME, ctxptr->errhp)) + printf("FAILED: OCIAttrSet() userid\n"); + + if (OCIAttrSet((dvoid *) ctxptr->authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *) password), + (ub4) OCI_ATTR_PASSWORD, ctxptr->errhp)) + printf("FAILED: OCIAttrSet() passwd\n"); + + printf("Logging on as %s ....\n", username); + + checkerr(ctxptr->errhp, OCISessionBegin((dvoid *)ctxptr->svchp, + ctxptr->errhp,ctxptr->authp, + (ub4) OCI_CRED_RDBMS,(ub4) OCI_DEFAULT )); + + printf("%s logged on.\n", username); + + if (OCIAttrSet((dvoid *) ctxptr->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) ctxptr->authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, + ctxptr->errhp)) + printf("FAILED: OCIAttrSet() session\n"); + + /* end log_on part */ + + /* alocate stmt handle for sql queries */ + if (OCIHandleAlloc((dvoid *)ctxptr->envhp, (dvoid **) &ctxptr->stmthp, + (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0)) + printf("FAILED: alloc statement handle\n"); + + +} /* end initialize() */ + + +/******************************************************* + * clean up envionment and handlers * + * * + *******************************************************/ +void cleanup(ctxptr) +cdemoanctx *ctxptr; +{ + printf("\n ########## clean up ############ \n"); + + if (OCISessionEnd(ctxptr->svchp, ctxptr->errhp, + ctxptr->authp, (ub4) 0)) + printf("FAILED: OCISessionEnd()\n"); + + printf("%s Logged off.\n", username); + + if (OCIServerDetach(ctxptr->srvhp, ctxptr->errhp, (ub4) OCI_DEFAULT)) + printf("FAILED: OCIServerDetach()\n"); + + printf("Detached from server.\n"); + + printf("Freeing handles ...\n"); + if (ctxptr->stmthp) + OCIHandleFree((dvoid *) ctxptr->stmthp, (ub4) OCI_HTYPE_STMT); + if (ctxptr->errhp) + OCIHandleFree((dvoid *) ctxptr->errhp, (ub4) OCI_HTYPE_ERROR); + if (ctxptr->srvhp) + OCIHandleFree((dvoid *) ctxptr->srvhp, (ub4) OCI_HTYPE_SERVER); + if (ctxptr->svchp) + OCIHandleFree((dvoid *) ctxptr->svchp, (ub4) OCI_HTYPE_SVCCTX); + if (ctxptr->authp) + OCIHandleFree((dvoid *) ctxptr->authp, (ub4) OCI_HTYPE_SESSION); + if (ctxptr->envhp) + OCIHandleFree((dvoid *) ctxptr->envhp, (ub4) OCI_HTYPE_ENV); + +} /* end cleanup() */ + + +/******************************************************* + * check status and print error information * + * * + *******************************************************/ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + if(errcode == 22303){ + printf("Please run cdemoanydata1.sql before executing the demo! \n"); + exit(1); + } + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} /* end checkerr() */ + + +/* end of file cdemoAnyData1.c */ + + + + + + + + + + + + + + + + + + + + + diff --git a/cdemoanydata1.sql b/cdemoanydata1.sql new file mode 100644 index 0000000..246a383 --- /dev/null +++ b/cdemoanydata1.sql @@ -0,0 +1,59 @@ +Rem +Rem $Header: cdemoanydata1.sql 04-may-2001.16:09:54 jchai Exp $ +Rem +Rem cdemoAnyData1.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem cdemoAnyData1.sql - Demo program for ANYDATA +Rem +Rem DESCRIPTION +Rem SQL script to prepare table anydatatab and address_object type +Rem +Rem NOTES +Rem Neet to run before cdemoAnyData. +Rem +Rem MODIFIED (MM/DD/YY) +Rem jchai 05/04/01 - Merged jchai_add_oci_demos_to_shiphome +Rem ani 04/30/01 - Merged ani_ocidemo +Rem ani 04/24/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect scott/tiger +/ +drop table anydatatab +/ +drop table addr_objtab +/ +drop type addr_tab +/ +drop type address_object +/ + +CREATE OR REPLACE TYPE address_object AS OBJECT +( + state varchar2(3), + zip varchar2(13) +) +/ + +create or replace type addr_tab is table of address_object +/ + +create table addr_objtab of address_object +/ +insert into addr_objtab values(address_object('CA','94065')) +/ + +CREATE TABLE anydatatab(col1 number, col2 Sys.AnyData) +/ + diff --git a/cdemoanydata2.c b/cdemoanydata2.c new file mode 100644 index 0000000..e74e753 --- /dev/null +++ b/cdemoanydata2.c @@ -0,0 +1,776 @@ +/* Copyright (c) 2001, 2002, Oracle Corporation. All rights reserved. */ + +/* + + NAME + cdemoAnyData2.c - OCI demo program for ANYDATA. + + DESCRIPTION + An example program which creates an TYPE piecewise using OCITypeBeginCreate() + and then describe the new type created. Three types are created and described. + An OCIANYDATA is constructed piecewise using OCIAnyDataBeginCreate() and + accessed piecewise. + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + Dependent Files: + cdemoAnyData2.sql - SQL script to be run before execution. + + MODIFIED (MM/DD/YY) + jchai 06/13/02 - fix bug 2360431 + ani 09/17/01 - Change access interface for DATE,NUMBER + jchai 05/04/01 - Merged jchai_add_oci_demos_to_shiphome + ani 04/30/01 - Merged ani_ocidemo + ani 04/24/01 - Creation + +*/ + +#include +#include +#include + +#ifndef OCI_ORACLE +# include +#endif + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +#define MAXNAME 30 + +typedef struct cdemoctx +{ + OCIEnv *envhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCIServer *svrhp; + OCISession *usrhp; +} cdemoctx; + +/* boolean IS_CHARTYPE(OCITypeCode tc) */ +#define IS_CHARTYPE(tc) ((tc == OCI_TYPECODE_CHAR) || \ +(tc == OCI_TYPECODE_VARCHAR) || (tc == OCI_TYPECODE_VARCHAR2) || \ +(tc == OCI_TYPECODE_CLOB) || (tc == OCI_TYPECODE_CFILE)) + + +static text *username = (text *) "scott"; +static text *password = (text *) "tiger"; + + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ +static void chk_typecoll (/*_ cdemoctx *ctx, OCIParam *parmp, boolean is_array _*/); +static void describe_type(/*_ cdemoctx *ctx, OCIType *tdo _*/); +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void initialize(cdemoctx *ctx); +static void setup_param(/*_ OCIError *errhp, OCIParam *parm, OCITypeCode tc, + ub1 prec, sb1 scale, ub4 len, ub2 csid, ub1 csfrm, + OCIType *attr_tdo, OraText *schm, OraText *typn _*/); +static OCIType *create_builtin(/*_ OCISvcCtx *svchp, OCIEnv *envhp, OCIError *errhp, + OCIParam *parm, OCIDuration dur _*/); +static OCIType *create_usertype(/*_ OCISvcCtx *svchp, OCIEnv *envhp, OCIError *errhp, + OCITypeCode tc, ub4 cnt, OCIParam *parm1, OCIParam *parm2, + OCIParam *parm3, OCIParam *parm4, OCIParam *parm5, OCIDuration dur _*/); +static void build_data(/*_ OCIEnv *envhp, OCIError *errhp, OCISvcCtx *svchp _*/); +void main(/*_ int argc, char *argv[] _*/); + + +/* check status and print error information */ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = OCI_SUCCESS; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("Error - %s\n", errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } + if (errcode == 1034) + exit(1); + else + return; +} + + +/* initialize envionment and handlers */ +void initialize(ctx) +cdemoctx *ctx; +{ + OCIInitialize((ub4) OCI_THREADED | OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t)) 0, + (void (*)(dvoid *, dvoid *)) 0 ); + + OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &ctx->envhp, + (ub4) OCI_HTYPE_ENV, + 0, (dvoid **)0); + + OCIEnvInit( &ctx->envhp, (ub4) OCI_DEFAULT, 0, (dvoid **) 0 + ); + + OCIHandleAlloc( (dvoid *) ctx->envhp, + (dvoid **) &ctx->errhp, (ub4) OCI_HTYPE_ERROR, 0, (dvoid **)0); + + /* Allocate server handle and attach to server */ + OCIHandleAlloc( (dvoid *) ctx->envhp, + (dvoid **) &ctx->svrhp, + (ub4) OCI_HTYPE_SERVER, 0, (dvoid **) 0); + checkerr(ctx->errhp, OCIServerAttach( ctx->svrhp, + ctx->errhp, (text *) 0, + (sb4) 0, (ub4) OCI_DEFAULT)); + + /* Allocate and setup service context */ + OCIHandleAlloc( (dvoid *) ctx->envhp, + (dvoid **) &ctx->svchp, + (ub4) OCI_HTYPE_SVCCTX, 0, (dvoid **)0); + checkerr(ctx->errhp, OCIAttrSet( (dvoid *) ctx->svchp, + (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) ctx->svrhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) ctx->errhp)); + + /* allocate a user context handle */ + OCIHandleAlloc((dvoid *)ctx->envhp, + (dvoid **)&ctx->usrhp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0); + checkerr(ctx->errhp, OCIAttrSet((dvoid *)ctx->usrhp, + (ub4)OCI_HTYPE_SESSION, + (dvoid *) username, (ub4)strlen((char *) username), + (ub4)OCI_ATTR_USERNAME, ctx->errhp)); + checkerr(ctx->errhp, OCIAttrSet((dvoid *)ctx->usrhp, + (ub4)OCI_HTYPE_SESSION, + (dvoid *) password, (ub4)strlen((char *) password), + (ub4)OCI_ATTR_PASSWORD, ctx->errhp)); + checkerr(ctx->errhp, + OCISessionBegin (ctx->svchp, ctx->errhp, + ctx->usrhp, (ub4)OCI_CRED_RDBMS, + (ub4)OCI_DEFAULT)); + + /* Set up user context inside service context */ + checkerr(ctx->errhp, OCIAttrSet((dvoid *)ctx->svchp, + (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)ctx->usrhp, (ub4)0, + (ub4)OCI_ATTR_SESSION, ctx->errhp)); +} + + +/* Setup param handle with type info */ +void setup_param(errhp, parm, tc, prec, scale, len, csid, csfrm, + attr_tdo, schm, typn) +OCIError *errhp; +OCIParam *parm; +OCITypeCode tc; +ub1 prec; +sb1 scale; +ub4 len; +ub2 csid; +ub1 csfrm; +OCIType *attr_tdo; /* attribute TDO or schema, typename specified */ +OraText *schm; +OraText *typn; +{ + + /* Setup type code */ + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&tc, + (ub4) sizeof(ub2), (ub4)OCI_ATTR_TYPECODE, errhp); + + switch (tc) + { + case OCI_TYPECODE_NUMBER: /* Setup precision and scale */ + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&prec, + (ub4) sizeof(ub1), (ub4)OCI_ATTR_PRECISION, errhp); + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&scale, + (ub4) sizeof(sb1), (ub4)OCI_ATTR_SCALE, errhp); + break; + case OCI_TYPECODE_RAW: /* Setup length of raw */ + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&len, + (ub4) sizeof(ub4), (ub4)OCI_ATTR_DATA_SIZE, errhp); + break; + case OCI_TYPECODE_VARCHAR2: /* Set Len, csid, csfrm for varchar2's */ + case OCI_TYPECODE_VARCHAR: + case OCI_TYPECODE_CHAR: + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&len, + (ub4) sizeof(ub4), (ub4)OCI_ATTR_DATA_SIZE, errhp); + /* FALLTHROUGH */ + case OCI_TYPECODE_CLOB: + case OCI_TYPECODE_CFILE: + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&csid, + (ub4) sizeof(ub2), (ub4)OCI_ATTR_CHARSET_ID, errhp); + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&csfrm, + (ub4) sizeof(ub1), (ub4)OCI_ATTR_CHARSET_FORM, errhp); + break; + case OCI_TYPECODE_REF: + case OCI_TYPECODE_OBJECT: /* handle later */ + case OCI_TYPECODE_VARRAY: + case OCI_TYPECODE_TABLE: + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)attr_tdo, + (ub4) sizeof(OCIType *), (ub4)OCI_ATTR_TDO, errhp); + break; + default: + break; + } +} + + +/* create OCIType of built in types */ +OCIType *create_builtin(svchp, envhp, errhp, parm, dur) +OCISvcCtx *svchp; +OCIEnv *envhp; +OCIError *errhp; +OCIParam *parm; +OCIDuration dur; +{ + ub2 tc; + OCIType *builtin; + ub4 siz; + + /* Get Typecode */ + OCIAttrGet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&tc, + &siz, (ub4)OCI_ATTR_TYPECODE, errhp); + + /* Create transient builtin based on the typecode */ + checkerr(errhp, OCITypeBeginCreate(svchp, errhp, tc, dur, &builtin)); + + checkerr(errhp, OCITypeSetBuiltin(svchp, errhp, builtin, parm)); + + checkerr(errhp, OCITypeEndCreate(svchp, errhp, builtin)); + + return(builtin); +} + + +/* Create a user defined type of given typecode - OBJECT, VARRAY etc. */ +OCIType *create_usertype(svchp, envhp, errhp, tc, cnt, parm1, parm2, + parm3, parm4, parm5, dur) +OCISvcCtx *svchp; +OCIEnv *envhp; +OCIError *errhp; +OCITypeCode tc; +ub4 cnt; +OCIParam *parm1; /* MUST - param for collection info / 1st object attribute */ +OCIParam *parm2; /* OPTIONAL - for 2nd attribute */ +OCIParam *parm3; /* OPTIONAL - for 3rd attribute */ +OCIParam *parm4; /* OPTIONAL - for 4th attribute */ +OCIParam *parm5; /* OPTIONAL - for 5th attribute */ +OCIDuration dur; +{ + OCIType *usertype; + ub4 siz; + sword status; + /* Create transient usertype based on the typecode */ + status = OCITypeBeginCreate(svchp, errhp, tc, dur, &usertype); + checkerr(errhp, status); + if(status!=0){ + printf("exiting.... \n"); + exit(1); + } + + switch (tc) + { + case OCI_TYPECODE_OBJECT: + checkerr(errhp, OCITypeAddAttr(svchp, errhp, usertype, (text *)"attr1", + (ub4)strlen("attr1"), parm1)); + if (parm2) + checkerr(errhp, OCITypeAddAttr(svchp, errhp, usertype, (text *)"attr2", + (ub4)strlen("attr2"), parm2)); + if (parm3) + checkerr(errhp, OCITypeAddAttr(svchp, errhp, usertype, (text *)"attr3", + (ub4)strlen("attr3"), parm3)); + if (parm4) + checkerr(errhp, OCITypeAddAttr(svchp, errhp, usertype, (text *)"attr4", + (ub4)strlen("attr4"), parm4)); + if (parm5) + checkerr(errhp, OCITypeAddAttr(svchp, errhp, usertype, (text *)"attr5", + (ub4)strlen("attr5"), parm5)); + break; + case OCI_TYPECODE_VARRAY: + checkerr(errhp,OCITypeSetCollection(svchp, errhp, usertype, parm1, cnt)); + break; + default: + printf ("Incorrect parameters to create_usertype\n"); + return((OCIType *)0); + } + + checkerr(errhp, OCITypeEndCreate(svchp, errhp, usertype)); + + return(usertype); +} + + +/* Using OCIDescribeAny to describe type */ +static void chk_type (ctx, parmp) +cdemoctx *ctx; +OCIParam *parmp; +{ + OCITypeCode typecode, + collection_typecode; + ub4 size; + OCIType *tdo; + ub2 num_attr; + ub1 is_incomplete, + is_predefined, + is_transient, + has_table; + OCIParam *collection_parmp; + ub1 prec; + sb1 scale; + ub2 len; + ub2 csid; + ub1 csfrm; + ub2 sqltype; + + checkerr(ctx->errhp, OCIAttrGet((dvoid*) parmp, + (ub4) OCI_DTYPE_PARAM, + (dvoid*) &tdo, (ub4 *) 0, + (ub4) OCI_ATTR_TDO, (OCIError *) ctx->errhp)); + + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, + (ub4) OCI_ATTR_TYPECODE, (OCIError *) ctx->errhp)); + + if (typecode == OCI_TYPECODE_NAMEDCOLLECTION) + { + checkerr(ctx->errhp, + OCIAttrGet((dvoid *)parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&collection_typecode, (ub4 *)0, + (ub4)OCI_ATTR_COLLECTION_TYPECODE, + (OCIError *)ctx->errhp)); + checkerr(ctx->errhp, + OCIAttrGet((dvoid *)parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&collection_parmp, (ub4 *)0, + (ub4)OCI_ATTR_COLLECTION_ELEMENT, (OCIError *)ctx->errhp)); + } + + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_incomplete, (ub4 *) 0, + (ub4) OCI_ATTR_IS_INCOMPLETE_TYPE, (OCIError *) ctx->errhp)); + + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_predefined, (ub4 *) 0, + (ub4) OCI_ATTR_IS_PREDEFINED_TYPE, (OCIError *) ctx->errhp)); + + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_transient, (ub4 *) 0, + (ub4) OCI_ATTR_IS_TRANSIENT_TYPE, (OCIError *) ctx->errhp)); + + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &has_table, (ub4 *) 0, + (ub4) OCI_ATTR_HAS_NESTED_TABLE, + (OCIError *) ctx->errhp)); + + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &num_attr, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_TYPE_ATTRS, (OCIError *) ctx->errhp)); + + /* Get constraint info for predefined transient types */ + if (is_predefined && is_transient) + { + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &prec, (ub4 *) 0, + (ub4) OCI_ATTR_PRECISION, + (OCIError *) ctx->errhp)); + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &scale, (ub4 *) 0, + (ub4) OCI_ATTR_SCALE, + (OCIError *) ctx->errhp)); + if (IS_CHARTYPE(typecode)) + { + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &csid, (ub4 *) 0, + (ub4) OCI_ATTR_CHARSET_ID, + (OCIError *) ctx->errhp)); + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &csfrm, (ub4 *) 0, + (ub4) OCI_ATTR_CHARSET_FORM, + (OCIError *) ctx->errhp)); + } + + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &len, (ub4 *) 0, + (ub4) OCI_ATTR_DATA_SIZE, + (OCIError *) ctx->errhp)); + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &sqltype, (ub4 *) 0, + (ub4) OCI_ATTR_DATA_TYPE, + (OCIError *) ctx->errhp)); + } + + printf ( "TYPE\n"); + printf ( "Typecode: %d\n", typecode); + if (typecode == OCI_TYPECODE_NAMEDCOLLECTION) + printf ( "Collection typecode: %d\n", collection_typecode); + printf ( "Number of attrs: %d\n", num_attr); + printf ( "Is incomplete: %d\n", is_incomplete); + printf ( "Is predefined: %d\n", is_predefined); + printf ( "Is transient: %d\n", is_transient); + printf ( "Has nested table: %d\n", has_table); + + if (is_predefined && is_transient) + { + printf( "Predefined transient type information :\n"); + printf( "Precision : %d\n", prec ); + printf( "Scale : %d\n", scale); + printf( "Length : %d\n", len); + printf( "SQLT code : %d\n", sqltype); + if (IS_CHARTYPE(typecode)) + { + printf( "Charset id : %d\n", csid ); + printf( "Charset form : %d\n", csfrm); + } + } + + if (typecode == OCI_TYPECODE_NAMEDCOLLECTION) + chk_typecoll(ctx, collection_parmp, + collection_typecode == OCI_TYPECODE_VARRAY); +} + + +/*describe collection type */ +static void chk_typecoll (ctx, parmp, is_array) +cdemoctx *ctx; +OCIParam *parmp; +boolean is_array; +{ + text schema[MAXNAME], + type[MAXNAME], + *namep; + ub4 size; + ub2 len = 0; + ub4 num_elems; + OCITypeCode typecode; + ub2 datatype; + + checkerr(ctx->errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &len, (ub4 *) 0, + (ub4) OCI_ATTR_DATA_SIZE, (OCIError *) ctx->errhp)); + + checkerr(ctx->errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_TYPE_NAME, (OCIError *) ctx->errhp)); + + strncpy((char *)type, (char *)namep, (size_t) size); + type[size] = '\0'; + + checkerr(ctx->errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_SCHEMA_NAME, (OCIError *) ctx->errhp)); + + strncpy((char *)schema, (char *)namep, (size_t) size); + schema[size] = '\0'; + + checkerr(ctx->errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, (ub4) OCI_ATTR_TYPECODE, + (OCIError *) ctx->errhp)); + + checkerr(ctx->errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &datatype, (ub4 *) 0, (ub4) OCI_ATTR_DATA_TYPE, + (OCIError *) ctx->errhp)); + + num_elems = 0; + if (is_array) + checkerr(ctx->errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &num_elems, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_ELEMS, (OCIError *) ctx->errhp)); + + + printf ( "Schema Type Length Type Datatype Elements\n"); + printf ( "_________________________________________________________\n"); + + printf("%10s%16s%9d%5d%9d%8d\n", schema, type, + len, typecode, datatype, num_elems); + +} + + +/* Describe a type given the OCIType */ +static void describe_type(ctx, tdo) +cdemoctx *ctx; +OCIType *tdo; +{ + OCIDescribe *dschp; + OCIParam *parmp; + + OCIHandleAlloc((dvoid *)ctx->envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, (size_t) 0, (dvoid **) 0); + + checkerr(ctx->errhp, + OCIDescribeAny(ctx->svchp, ctx->errhp, (dvoid *)tdo, + (ub4)0, OCI_OTYPE_PTR, (ub1)1, OCI_PTYPE_TYPE, dschp)); + + checkerr(ctx->errhp, OCIAttrGet((dvoid *)dschp, (ub4)OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, + ctx->errhp)); + + chk_type(ctx, parmp); +} + + +/* constructs an ANYDATA piecewise using OCIAnyDataBeginCreate() + and access the data piecewise */ +static void build_data(envhp, errhp, svchp) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +{ + OCIAnyData *addressimgh = (OCIAnyData *) 0; + OCIAnyData *addressimgh2 = (OCIAnyData *) 0; + text *addressimg_buf; + OCITypeCode typecode; + OCIInd indp; + ub4 zip_size, state_size; + ub2 len; + OCIRef *Ref, *Ref2; + OCIType *tdo = (OCIType *) 0; + sword error; + + OCIString *str = (OCIString *) 0; + OCIRaw *Raw = (OCIRaw *)0; + OCIRaw *Raw2 = (OCIRaw *)0; + ub1 raw_data[5] = {1, 1, 1, 1, 1}; + OCIDate date1, *date2 = (OCIDate *)0; + OCINumber num1, *num2 = (OCINumber *)0; + OCIInd ind1 = OCI_IND_NOTNULL; + + printf("\nBeginning piecewise construction and access ANYDATA\n"); + + checkerr(errhp, OCITypeByName(envhp, errhp, svchp, (const text *) "", + (ub4) strlen((const char *) ""), + (const text *) "BASIC_OBJECT", + (ub4) strlen((const char *) "BASIC_OBJECT"), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &tdo)); + + printf("Constructing image\n"); + + /* begin to construct the data piecewise */ + OCIAnyDataBeginCreate(svchp, errhp, OCI_TYPECODE_OBJECT, tdo, + OCI_DURATION_SESSION, &addressimgh); + + printf("Adding scalar values for the attributes in the image handle\n"); + + OCIStringAssignText(envhp, errhp, (text *)"CA", 2, &str); + printf("state is %s \n", OCIStringPtr(envhp, str)); + OCIAnyDataAttrSet(svchp, errhp, addressimgh, OCI_TYPECODE_CHAR, + (OCIType *)0, (dvoid *)&ind1, str, 2, FALSE); + OCIStringAssignText(envhp, errhp, (text *)"94065", 5, &str); + printf("zip is %s \n", OCIStringPtr(envhp, str)); + OCIAnyDataAttrSet(svchp, errhp, addressimgh, OCI_TYPECODE_CHAR, + (OCIType *)0, (dvoid *)&ind1, str, 5, FALSE); + + OCIRawAssignBytes(envhp, errhp, raw_data, 5, &Raw); + OCIAnyDataAttrSet(svchp, errhp, addressimgh, OCI_TYPECODE_RAW, + (OCIType *)0, (dvoid *)&ind1, Raw, (ub4) 5, FALSE); + + error = OCIDateSysDate(errhp, &date1); + OCIAnyDataAttrSet(svchp, errhp, addressimgh, OCI_TYPECODE_DATE, + (OCIType *)0, (dvoid *)&ind1, &date1, (ub4)0, FALSE); + + zip_size = 10; + error = OCINumberFromInt(errhp, &zip_size, sizeof(zip_size), + OCI_NUMBER_UNSIGNED, &num1); + OCIAnyDataAttrSet(svchp, errhp, addressimgh, OCI_TYPECODE_NUMBER, + (OCIType *)0, (dvoid *)&ind1, &num1, (ub4)0, FALSE); + + printf("Generating Image\n\n"); + OCIAnyDataEndCreate(svchp, errhp, addressimgh); + + /* Access the image */ + printf("Accessing image\n"); + + zip_size = 11; + state_size = 3; + + OCIAnyDataAttrGet(svchp, errhp, addressimgh, + OCI_TYPECODE_CHAR, (OCIType *)0, (dvoid *)&indp, + (dvoid **)&str, &state_size, FALSE); + printf("state is %s \n", OCIStringPtr(envhp, str)); + OCIAnyDataAttrGet(svchp, errhp, addressimgh, + OCI_TYPECODE_CHAR, (OCIType *)0, (dvoid *)&indp, + (dvoid **)&str, &zip_size, FALSE); + printf("zip is %s \n", OCIStringPtr(envhp, str)); + + checkerr(errhp, OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_RAW, + (OCIType *) 0, (dvoid *) 0, OCI_DURATION_TRANS, FALSE, + (dvoid **) &Raw2)); + OCIAnyDataAttrGet(svchp, errhp, addressimgh, + OCI_TYPECODE_RAW, (OCIType *)0, (dvoid *)&indp, + (dvoid **)&Raw2, &state_size, FALSE); + if (!memcmp((dvoid *)OCIRawPtr(envhp, Raw), (dvoid *)OCIRawPtr(envhp, Raw2), + OCIRawSize(envhp, Raw))) + printf("RAWs are same \n"); + else + printf("Error! RAWs are diff \n"); + + error = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_DATE, + (OCIType *) 0, (dvoid *) 0, OCI_DURATION_DEFAULT, FALSE, + (dvoid **) &date2); + /*OCIAnyDataAttrGet(svchp, errhp, addressimgh, + OCI_TYPECODE_DATE, (OCIType *)0, (dvoid *)&indp, + (dvoid **)date2, &state_size, FALSE); */ + OCIAnyDataAttrGet(svchp, errhp, addressimgh, + OCI_TYPECODE_DATE, (OCIType *)0, (dvoid *)&indp, + (dvoid **)&date2, &state_size, FALSE); + (void) OCIDateCompare(errhp, &date1, date2, &error); + + + if (!error) + printf("Dates are same \n"); + else + printf("Error! dates are diff \n"); + + checkerr(errhp, OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_NUMBER, + (OCIType *) 0, (dvoid *) 0, OCI_DURATION_TRANS, FALSE, + (dvoid **) &num2)); + /*OCIAnyDataAttrGet(svchp, errhp, addressimgh, + OCI_TYPECODE_NUMBER, (OCIType *)0, (dvoid *)&indp, + (dvoid **)num2, &state_size, FALSE);*/ + OCIAnyDataAttrGet(svchp, errhp, addressimgh, + OCI_TYPECODE_NUMBER, (OCIType *)0, (dvoid *)&indp, + (dvoid **)&num2, &state_size, FALSE); + OCINumberCmp(errhp, &num1, num2, &error); + if (!error) + printf("Numbers are same \n"); + else + printf("Error! Numbers are diff \n"); + OCINumberToInt(errhp, num2, sizeof(zip_size), 0, + &zip_size); + printf("Number (num2) is %d \n", zip_size); + + /* + ** Free the handles + */ + + printf("Freeing FDO, TDS and Image structures\n\n\n"); + OCIAnyDataDestroy(svchp, errhp, addressimgh); +} + + +void main(int argc, char *argv[]) +{ + cdemoctx ctx; + OCIType *tdo; /* AnyType */ + OCIParam *parm = (OCIParam *)0; /* parameter handle */ + OCIParam *parm2 = (OCIParam *)0; + OCIParam *parm3 = (OCIParam *)0; + OCIDuration dur; + OCIType *attr_tdo; + OCIType *obj_tdo; + OCIType *coll_tdo; + ub1 t_precision; + sb1 t_scale; + ub2 t_charset_id; + ub1 t_charset_form; + ub4 t_data_size; + ub2 t_typecode; + OCIType *t_tdo; + + initialize(&ctx); + + /* Allocate parameter handle for transient type creation */ + OCIDescriptorAlloc((dvoid *)ctx.envhp, (dvoid **)&parm, + (ub4)OCI_DTYPE_PARAM, 0, (dvoid **)0); + OCIDescriptorAlloc((dvoid *)ctx.envhp, (dvoid **)&parm2, + (ub4)OCI_DTYPE_PARAM, 0, (dvoid **)0); + OCIDescriptorAlloc((dvoid *)ctx.envhp, (dvoid **)&parm3, + (ub4)OCI_DTYPE_PARAM, 0, (dvoid **)0); + + OCIDurationBegin(ctx.envhp, ctx.errhp, ctx.svchp, + OCI_DURATION_CALL, &dur); + + + /* Create transient built-in types and descrie types*/ + + /* NUMBER(5,2) */ + setup_param(ctx.errhp, parm, OCI_TYPECODE_NUMBER, (ub1)5, (sb1)2, + (ub4)0, (ub2)0, + (ub1)0, (OCIType *)0, (OraText *)0, (OraText *)0); + + tdo = create_builtin(ctx.svchp, ctx.envhp, ctx.errhp, + parm, dur); + + describe_type(&ctx, tdo); + + /* CHAR(20), csid = OCI_UCS2ID, csfrm = SQLCS_NCHAR */ + setup_param(ctx.errhp, parm, OCI_TYPECODE_CHAR, (ub1)0, (sb1)0, + (ub4)20, (ub2)OCI_UCS2ID, + (ub1)SQLCS_NCHAR, (OCIType *)0, (OraText *)0, (OraText *)0); + tdo = create_builtin(ctx.svchp, ctx.envhp, + ctx.errhp, parm, dur); + describe_type(&ctx, tdo); + + OCIDurationEnd(ctx.envhp, ctx.errhp, ctx.svchp, + dur); + + + OCITypeByName(ctx.envhp, ctx.errhp, + ctx.svchp, (text *)0, (ub4)0, + (text *)"FOO", (ub4)3, (text *)0, (ub4)0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &attr_tdo); + + /* create a transient collection - VARRAY(100) of SCOTT.FOO */ + setup_param(ctx.errhp, parm, OCI_TYPECODE_OBJECT, (ub1)0, (sb1)0, + (ub4)0, (ub2)0, + (ub1)SQLCS_IMPLICIT, attr_tdo, (OraText *)0, (OraText *)0); + coll_tdo = create_usertype(ctx.svchp, ctx.envhp, + ctx.errhp, OCI_TYPECODE_VARRAY, (ub4)100, + parm, (OCIParam *)0, (OCIParam *)0, (OCIParam *)0, + (OCIParam *)0, dur); + describe_type(&ctx, coll_tdo); + + /* piecewise construct an ANYDATA and access it piecewise */ + build_data(ctx.envhp, ctx.errhp, ctx.svchp); + + /* Cleanup */ + OCIHandleFree((dvoid *)ctx.envhp, (ub4) OCI_HTYPE_ENV); + OCITerminate((ub4)OCI_OBJECT); +} + +/* end of file cdemoAnyData2.c */ diff --git a/cdemoanydata2.sql b/cdemoanydata2.sql new file mode 100644 index 0000000..1adbd87 --- /dev/null +++ b/cdemoanydata2.sql @@ -0,0 +1,49 @@ +Rem +Rem $Header: cdemoanydata2.sql 04-may-2001.16:09:55 jchai Exp $ +Rem +Rem cdemoAnyData1.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem cdemoAnyData2.sql - Demo program for ANYDATA +Rem +Rem DESCRIPTION +Rem SQL script to prepare table anydatatab and address_object type +Rem +Rem NOTES +Rem Neet to run before cdemoAnyData2. +Rem +Rem MODIFIED (MM/DD/YY) +Rem jchai 05/04/01 - Merged jchai_add_oci_demos_to_shiphome +Rem ani 04/30/01 - Merged ani_ocidemo +Rem ani 04/24/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect scott/tiger + +drop type foo +/ +drop type basic_object +/ + +CREATE OR REPLACE TYPE foo as OBJECT +( + a DATE, + b VARCHAR2(50), + c CLOB +) +/ + +create or replace type basic_object as object (state char(2), zip char(10), + a3 raw(10), a4 date, a5 number) +/ + diff --git a/cdemobj.c b/cdemobj.c new file mode 100644 index 0000000..07ef8c1 --- /dev/null +++ b/cdemobj.c @@ -0,0 +1,895 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemobj.c 18-feb-2005.15:01:08 aliu Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1995, 2005, Oracle. All rights reserved. +*/ + +/* + NAME + cdemobj.c + DESCRIPTION + Demo of selection of a REF and display the pinned object through + navigational interface. + + NOTES + see routines. + + MODIFIED (MM/DD/YY) + aliu 02/17/05 - lint issues + aliu 02/16/05 - fix bug 4184313 + aliu 07/17/03 - Free dschp after printing in dump_adt + nireland 04/11/00 - Fix porting exception. #1264324 + mpjoshi 02/15/00 - bug 531229 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + svedala 02/18/98 - OCI obsoletion changes + svedala 04/13/98 - + echen 06/04/97 - remove TypeTypeCode call + echen 06/02/97 - fix a bug + echen 06/02/97 - remove obsolete ORT code + skmishra 05/14/97 - stdcc compatibility changes + azhao 03/28/97 - add AS OBJECT to create type + echen 03/24/97 - fix a sequent bug + azhao 03/05/97 - fix compile errors + echen 03/05/97 - remove unnecessary code + cchau 03/03/97 - change functions to long names + cxcheng 02/10/97 - remove short ORO names + echen 01/09/97 - modify the sql syntax + echen 01/03/97 - fix test bugs + echen 11/15/96 - change obsolete type code + skrishna 11/07/96 - continue OCICollGetElem interface change + jboonl10/30/96 - new ori interface + echen 11/06/96 - fix OCICollGetElem + echen 07/19/96 - remove obsolete pin option + echen 07/19/96 - remove obsolete pin option + dchatt07/18/96 - delete Oracle spec code like static + echen 07/16/96 - Creation +*/ + +#ifndef CDEMOBJ_ORACLE +#include "cdemobj.h" +#endif + +/* statement to select a ref from an extent table customer_tab */ +static const text *const selref = (text *) + "SELECT REF(c) from customer_tab c"; + +/* statement to create the type address */ +static const text *const create_type_address = (text *) +"CREATE TYPE address AS OBJECT (\ + no NUMBER,\ + street VARCHAR(60),\ + state CHAR(2),\ + zip CHAR(10)\ +)"; + +/* statement to create the typed table address_tab */ +static const text *const create_type_addr_tab = (text *) +"create type addr_tab is table of address"; + +/* statement to create the type person */ +static const text *const create_type_person = (text *) +"CREATE TYPE person AS OBJECT (\ + firstname CHAR(20),\ + lastname varchar(20),\ + age int,\ + salary float,\ + bonus double precision,\ + retirement_fund int,\ + number_of_kids smallint,\ + years_of_school numeric(10, 2),\ + preaddr addr_tab,\ + birthday date,\ + number_of_pets real,\ + comment1 raw(200),\ + comment2 clob,\ + comment3 varchar2(200),\ + addr ADDRESS\ +)"; + +/* statement to create the type customer */ +static const text *const create_type_customer = (text *) +"CREATE TYPE customer AS OBJECT (\ + account char(20),\ + aperson REF person\ +)"; + +/* statement to create the typed table person */ +static const text *const create_table_person = (text *) +"create table person_tab of person nested table preaddr \ + store as person_preaddr_table"; + +/* statement to create the typed table customer_tab */ +static const text *const create_table_customer = (text *) +"create table customer_tab of customer"; + +/* statement to insert data into table customer_tab */ +static const text *const insert_customer = (text *) +"insert into customer_tab values('00001', null)"; + +/* statement to insert data into table person_tab */ +static const text *const insert_person = (text *) +"insert into person_tab values('Sandy', 'Wood', 25, 32000, 10000, 20000, 3,\ + 15, addr_tab(),\ + to_date('1961 08 23', 'YYYY MM DD'), 2,\ + '1234567890', 'This is a test', 'This is a test',\ + ADDRESS(8888, 'Fenley Road', 'CA', '91406'))"; + +/* statement to insert data into the nested table in person_tab */ +static const text *const insert_address1 = (text *) +"insert into the (select preaddr from person_tab where\ + firstname='Sandy') values\ + (715, 'South Henry', 'ca', '95117')"; +static const text *const insert_address2 = (text *) +"insert into the (select preaddr from person_tab where\ + firstname='Sandy') values\ + (6830, 'Woodley Ave', 'ca', '90416')"; + +/* statement to update the ref in the table customer_tab */ +static const text *const update_customer = (text *) +"update customer_tab set aperson = (select ref(p)\ + from person_tab p where\ + p.firstname = 'Sandy')"; + +/*************************************************************************** +* Check the error and display the error message * +****************************************************************************/ +static void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + break; + case OCI_NEED_DATA: + break; + case OCI_NO_DATA: + break; + case OCI_ERROR: /* get the error back and display on the screen */ + (void) OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("Error - %s\n", errbuf); + break; + case OCI_INVALID_HANDLE: + break; + case OCI_STILL_EXECUTING: + break; + case OCI_CONTINUE: + break; + default: + break; + } +} +/**************************************************************************** +* Display attribute value of an ADT * +****************************************************************************/ +static void display_attr_val(envhp, errhp, names, typecode, attr_value) +OCIEnv *envhp; /* environment handle */ +OCIError *errhp; /* error handle */ +text *names; /* the name of the attribute */ +OCITypeCode typecode; /* the type code */ +dvoid *attr_value; /* the value pointer */ +{ + text str_buf[200]; + double dnum; + ub4 text_len, str_len; + OCIRaw *raw = (OCIRaw *) 0; + OCIString *vs = (OCIString *) 0; + ub1 *temp = (ub1 *)0; + ub4 rawsize = 0; + ub4 i = 0; + + /* display the data based on the type code */ + switch (typecode) + { + case OCI_TYPECODE_DATE : /* fixed length string */ + str_len = 200; + (void) OCIDateToText(errhp, (CONST OCIDate *) attr_value, + (CONST text*) "Month dd, SYYYY, HH:MI A.M.", + (ub1) 27, (CONST text*) "American", (ub4) 8, + (ub4 *)&str_len, str_buf); + str_buf[str_len+1] = '\0'; + (void) printf("attr %s = %s\n", names, (text *) str_buf); + break; + case OCI_TYPECODE_RAW : /* RAW */ + raw = *(OCIRaw **) attr_value; + temp = OCIRawPtr(envhp, raw); + rawsize = OCIRawSize (envhp, raw); + (void) printf("attr %s = ", names); + for (i=0; i < rawsize; i++) + { + (void) printf("0x%x ", temp[i]); + } + (void) printf("\n"); + break; + case OCI_TYPECODE_CHAR : /* fixed length string */ + case OCI_TYPECODE_VARCHAR : /* varchar */ + case OCI_TYPECODE_VARCHAR2 : /* varchar2 */ + vs = *(OCIString **) attr_value; + (void) printf("attr %s = %s\n", + names, (text *) OCIStringPtr(envhp, vs)); + break; + case OCI_TYPECODE_SIGNED8 : /* BYTE - sb1 */ + (void) printf("attr %s = %d\n", names, *(sb1 *) attr_value); + break; + case OCI_TYPECODE_UNSIGNED8 : /* UNSIGNED BYTE - ub1 */ + (void) printf("attr %s = %d\n", names, *(ub1 *) attr_value); + break; + case OCI_TYPECODE_OCTET : /* OCT */ + (void) printf("attr %s = %d\n", names, *(ub1 *) attr_value); + break; + case OCI_TYPECODE_UNSIGNED16 : /* UNSIGNED SHORT */ + case OCI_TYPECODE_UNSIGNED32 : /* UNSIGNED LONG */ + case OCI_TYPECODE_REAL : /* REAL */ + case OCI_TYPECODE_DOUBLE : /* DOUBLE */ + case OCI_TYPECODE_INTEGER : /* INT */ + case OCI_TYPECODE_SIGNED16 : /* SHORT */ + case OCI_TYPECODE_SIGNED32 : /* LONG */ + case OCI_TYPECODE_DECIMAL : /* DECIMAL */ + case OCI_TYPECODE_FLOAT : /* FLOAT */ + case OCI_TYPECODE_NUMBER : /* NUMBER */ + case OCI_TYPECODE_SMALLINT : /* SMALLINT */ + (void) OCINumberToReal(errhp, (CONST OCINumber *) attr_value, + (uword) sizeof(dnum), (dvoid *) &dnum); + (void) printf("attr %s = %f\n", names, dnum); + break; + default: + (void) printf("attr %s - typecode %d\n", names, typecode); + break; + } +} + + +/**************************************************************************** +* Dump the info of any ADT * +****************************************************************************/ +static void dump_adt(envhp, errhp, svchp, tdo, obj, null_obj) +OCIEnv *envhp; /* environment handle */ +OCIError *errhp; /* error handle */ +OCISvcCtx *svchp; /* service handle */ +OCIType *tdo; /* type descriptor */ +dvoid *obj; /* object pointer */ +dvoid *null_obj; /* parallel null struct pointer */ +{ + text *names[50]; + text *lengths[50]; + text *indexes[50]; + ub2 count, pos; + OCITypeElem *ado; + ub4 text_len, str_len; + ub4 i; + OCITypeCode typecode; + OCIInd attr_null_status; + dvoid *attr_null_struct; + dvoid *attr_value; + OCIType *attr_tdo, *element_type; + dvoid *object; + dvoid *null_object; + OCIType *object_tdo; + ub1 status; + OCIRef *type_ref; + text str_buf[200]; + double dnum; + dvoid *element = (dvoid *) 0, *null_element = (dvoid *) 0; + boolean exist, eoc, boc; + sb4 index; + OCIDescribe *dschp = (OCIDescribe *) 0, *dschp1 = (OCIDescribe *) 0; + text *namep, *typenamep; + dvoid *list_attr; + OCIIter *itr = (OCIIter *) 0; + dvoid *parmp = (dvoid *) 0, + *parmdp = (dvoid *) 0, + *parmp1 = (dvoid *) 0, + *parmp2 = (dvoid *) 0; + OCIRef *elem_ref = (OCIRef *) 0; + + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + checkerr(errhp, OCIDescribeAny(svchp, errhp, (dvoid *) tdo, + (ub4) 0, OCI_OTYPE_PTR, (ub1)1, + (ub1) OCI_PTYPE_TYPE, dschp)); + + checkerr(errhp, OCIAttrGet((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, errhp)); + + checkerr(errhp, OCIAttrGet((dvoid*) parmp,(ub4) OCI_DTYPE_PARAM, + (dvoid*) &typenamep, (ub4 *) &str_len, + (ub4) OCI_ATTR_NAME, (OCIError *) errhp)); + typenamep[str_len] = '\0'; + + printf("starting displaying instance of type '%s'\n", typenamep); + + /* loop through all attributes in the type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &count, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_TYPE_ATTRS, (OCIError *) errhp)); + + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&list_attr, (ub4 *)0, + (ub4)OCI_ATTR_LIST_TYPE_ATTRS, (OCIError *)errhp)); + + /* loop through all attributes in the type */ + for (pos = 1; pos <= count; pos++) + { + + checkerr(errhp, OCIParamGet((dvoid *) list_attr, + (ub4) OCI_DTYPE_PARAM, errhp, + (dvoid *)&parmdp, (ub4) pos)); + + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &str_len, + (ub4) OCI_ATTR_NAME, (OCIError *) errhp)); + namep[str_len] = '\0'; + + /* get the attribute */ + if (OCIObjectGetAttr(envhp, errhp, obj, null_obj, tdo, + (CONST oratext **)&namep, &str_len, 1, + (ub4 *)0, 0, &attr_null_status, &attr_null_struct, + &attr_value, &attr_tdo) != OCI_SUCCESS) + (void) printf("BUG -- OCIObjectGetAttr, expect OCI_SUCCESS.\n"); + + /* get the type code of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, + (ub4) OCI_ATTR_TYPECODE, + (OCIError *) errhp)); + + /* support only fixed length string, ref and embedded ADT */ + switch (typecode) + { + case OCI_TYPECODE_OBJECT : /* embedded ADT */ + printf("attribute %s is an embedded ADT. Display instance ....\n", + namep); + /* recursive call to dump nested ADT data */ + dump_adt(envhp, errhp, svchp, attr_tdo, attr_value, + attr_null_struct); + break; + case OCI_TYPECODE_REF : /* embedded ADT */ + printf("attribute %s is a ref. Pin and display instance ...\n", + namep); + /* pin the object */ + if (OCIObjectPin(envhp, errhp, *(OCIRef **)attr_value, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&object) != OCI_SUCCESS) + (void) printf("BUG -- OCIObjectPin, expect OCI_SUCCESS.\n"); + /* allocate the ref */ + if (( status = OCIObjectNew(envhp, errhp, svchp, + OCI_TYPECODE_REF, (OCIType *)0, + (dvoid *)0, OCI_DURATION_DEFAULT, TRUE, + (dvoid **) &type_ref)) != OCI_SUCCESS) + (void) printf("BUG -- OCIObjectNew, expect OCI_SUCCESS.\n"); + /* get the ref of the type from the object */ + if (( status = OCIObjectGetTypeRef(envhp, errhp, object, type_ref)) + != OCI_SUCCESS) + (void) printf("BUG -- ORIOGTR, expect OCI_SUCCESS.\n"); + /* pin the type ref to get the type object */ + if (OCIObjectPin(envhp, errhp, type_ref, (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **) &object_tdo) != OCI_SUCCESS) + (void) printf("BUG -- OCIObjectPin, expect OCI_SUCCESS.\n"); + /* get null struct of the object */ + if (( status = OCIObjectGetInd(envhp, errhp, object, + &null_object)) != OCI_SUCCESS) + (void) printf("BUG -- ORIOGNS, expect OCI_SUCCESS.\n"); + /* call the function recursively to dump the pinned object */ + dump_adt(envhp, errhp, svchp, object_tdo, object, + null_object); + case OCI_TYPECODE_NAMEDCOLLECTION : + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp1, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + checkerr(errhp, OCIDescribeAny(svchp, errhp, (dvoid *) attr_tdo, + (ub4) 0, OCI_OTYPE_PTR, (ub1)1, + (ub1) OCI_PTYPE_TYPE, dschp1)); + + checkerr(errhp, OCIAttrGet((dvoid *) dschp1, + (ub4) OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp1, (ub4 *)0, (ub4)OCI_ATTR_PARAM, errhp)); + + /* get the collection type code of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp1, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, + (ub4) OCI_ATTR_COLLECTION_TYPECODE, + (OCIError *) errhp)); + switch (typecode) + { + case OCI_TYPECODE_VARRAY : /* variable array */ + (void) printf + ("\n---> Dump the table from the top to the bottom.\n"); + checkerr(errhp, OCIAttrGet((dvoid*) parmp1, + (ub4) OCI_DTYPE_PARAM, + (dvoid*) &parmp2, (ub4 *) 0, + (ub4) OCI_ATTR_COLLECTION_ELEMENT, + (OCIError *) errhp)); + checkerr(errhp, OCIAttrGet((dvoid*) parmp2, + (ub4) OCI_DTYPE_PARAM, + (dvoid*) &elem_ref, (ub4 *) 0, + (ub4) OCI_ATTR_REF_TDO, + (OCIError *) errhp)); + checkerr(errhp, OCITypeByRef(envhp, errhp, elem_ref, + OCI_PIN_DEFAULT, (OCITypeGetOpt)0, &element_type)); + /* initialize the iterator */ + checkerr(errhp, OCIIterCreate(envhp, errhp, + (CONST OCIColl*) attr_value, &itr)); + /* loop through the iterator */ + for(eoc = FALSE;!OCIIterNext(envhp, errhp, itr, + (dvoid **) &element, + (dvoid **)&null_element, &eoc) && !eoc;) + { + /* if type is named type, call the same function recursively + */ + if (typecode == OCI_TYPECODE_OBJECT) + dump_adt(envhp, errhp, svchp, element_type, element, + null_element); + else /* else, display the scaler type attribute */ + display_attr_val(envhp, errhp, namep, typecode, element); + } + break; + + case OCI_TYPECODE_TABLE : /* nested table */ + (void) printf + ("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp1, + (ub4) OCI_DTYPE_PARAM, + (dvoid*) &parmp2, (ub4 *) 0, + (ub4) OCI_ATTR_COLLECTION_ELEMENT, + (OCIError *) errhp)); + checkerr(errhp, OCIAttrGet((dvoid*) parmp2, + (ub4) OCI_DTYPE_PARAM, + (dvoid*) &elem_ref, (ub4 *) 0, + (ub4) OCI_ATTR_REF_TDO, + (OCIError *) errhp)); + checkerr(errhp, OCITypeByRef(envhp, errhp, elem_ref, + OCI_DURATION_SESSION, + OCI_TYPEGET_HEADER, &element_type)); + attr_value = *(dvoid **)attr_value; + /* move to the first element in the nested table */ + checkerr(errhp, OCITableFirst(envhp, errhp, + (CONST OCITable*) attr_value, &index)); + (void) printf + (" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, + (CONST OCIColl *) attr_value, index, + &exist, (dvoid **) &element, + (dvoid **) &null_element)); + /* if it is named type, recursively call the same function */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp2, + (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, + (ub4) OCI_ATTR_TYPECODE, + (OCIError *) errhp)); + if (typecode == OCI_TYPECODE_OBJECT) + dump_adt(envhp, errhp, svchp, element_type, + (dvoid *)element, (dvoid *)null_element); + else + display_attr_val(envhp, errhp, namep, typecode, element); + + for(;!OCITableNext(envhp, errhp, index, + (CONST OCITable *) attr_value, + &index, &exist) && exist;) + { + checkerr(errhp, OCICollGetElem(envhp, errhp, + (CONST OCIColl *) attr_value, index, + &exist, (dvoid **) &element, + (dvoid **) &null_element)); + if (typecode == OCI_TYPECODE_OBJECT) + dump_adt(envhp, errhp, svchp, element_type, + (dvoid *)element, (dvoid *)null_element); + else + display_attr_val(envhp, errhp, namep, typecode, element); + } + break; + default: + break; + } + checkerr(errhp, OCIHandleFree((dvoid *) dschp1, + (ub4) OCI_HTYPE_DESCRIBE)); + break; + default: /* scaler type, display the attribute value */ + if (attr_null_status == OCI_IND_NOTNULL) + { + display_attr_val(envhp, errhp, namep, typecode, attr_value); + } + else + printf("attr %s is null\n", namep); + break; + } + } + + printf("finishing displaying instance of type '%s'\n", typenamep); + checkerr(errhp, OCIHandleFree((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE)); +} + + +/**************************************************************************** +* Setup the schema and insert the data * +*****************************************************************************/ +void setup(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + /* create the schema and populate the data */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) create_type_address, + (ub4) strlen((char *) create_type_address), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) create_type_addr_tab, + (ub4) strlen((char *) create_type_addr_tab), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) create_type_person, + (ub4) strlen((char *) create_type_person), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) create_type_customer, + (ub4) strlen((char *) create_type_customer), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) create_table_person, + (ub4) strlen((char *) create_table_person), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) create_table_customer, + (ub4) strlen((char *) create_table_customer), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) insert_customer, + (ub4) strlen((char *) insert_customer), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) insert_person, + (ub4) strlen((char *) insert_person), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) insert_address1, + (ub4) strlen((char *) insert_address1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) insert_address2, + (ub4) strlen((char *) insert_address2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) update_customer, + (ub4) strlen((char *) update_customer), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +} + + +/*****************************************************************************/ +void select_pin_display(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + sword status = OCI_SUCCESS; + OCIDefine *defnp; + OCIRef *custref = (OCIRef *) 0, *per_type_ref = (OCIRef *) 0; + OCIRef *cust_type_ref = (OCIRef *) 0; + ub4 custsize; + customer *cust = (customer *) 0, *custnew = (customer *) 0; + null_customer *null_cust = (null_customer *) 0, + *null_custnew = (null_customer *) 0; + person *per = (person *) 0; + null_person *null_per = (null_person *) 0; + null_address *nt_null = (null_address *) 0; + OCIType *pertdo = (OCIType *) 0, *custtdo = (OCIType *) 0; + address *addr = (address *) 0; + sb4 index; + boolean exist; + dvoid *tabobj = (dvoid *) 0; + + (void) printf("\n=============================================\n"); + + /* allocate ref */ + if (( status = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_REF, + (OCIType *)0, (dvoid *)0, OCI_DURATION_DEFAULT, + TRUE, (dvoid **) &per_type_ref)) + != OCI_SUCCESS) + (void) printf("BUG -- OCIObjectNew, expect OCI_SUCCESS.\n"); + + /* allocate ref */ + if (( status = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_REF, + (OCIType *)0, (dvoid *)0, OCI_DURATION_DEFAULT, + TRUE, (dvoid **) &cust_type_ref)) + != OCI_SUCCESS) + (void) printf("BUG -- OCIObjectNew, expect OCI_SUCCESS.\n"); + + /* define the application request */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selref, + (ub4) strlen((char *) selref), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + +/* + checkerr(errhp, OCIHandleAlloc( (dvoid *) stmthp, (dvoid **) &defnp, + (ub4) OCI_HTYPE_DEFINE, + 0, (dvoid **) 0)); +*/ + + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, (dvoid *) 0, + (sb4) 0, SQLT_REF, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineObject(defnp, errhp, (OCIType *) 0, + (dvoid **) &custref, + &custsize, (dvoid **) 0, (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, + (ub4) 0, (OCISnapshot *) + NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + while ((status = OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)) == 0) + { + + (void) printf("\n-----------------------------------------\n"); + + /* pin the ref and get the typed table to get to person */ + checkerr(errhp, OCIObjectPin(envhp, errhp, custref, + (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **) &cust)); + (void) printf("The customer account number is %s\n", + OCIStringPtr(envhp, cust->account)); + if (( status = OCIObjectGetInd(envhp, errhp, (dvoid *) cust, + (dvoid **) &null_cust)) != OCI_SUCCESS) + { + (void) printf("BUG -- ORIOGNS, expect OCI_SUCCESS.\n"); + } + else + { + (void) printf("null_cus = %d, null_account = %d, null_aperson = %d\n", + null_cust->null_cus, null_cust->null_account, + null_cust->null_aperson); + } + + checkerr(errhp, OCIObjectPin(envhp, errhp, cust->aperson, + (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **) &per)); + + if (( status = OCIObjectGetInd(envhp, errhp, (dvoid *) per, + (dvoid **) &null_per)) != OCI_SUCCESS) + { + (void) printf("BUG -- ORIOGNS, expect OCI_SUCCESS.\n"); + } + else + { + checkerr(errhp, OCIObjectGetTypeRef(envhp, errhp, (dvoid *)per, + per_type_ref)); + checkerr(errhp, OCIObjectPin(envhp, errhp, per_type_ref, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **) &pertdo)); + dump_adt(envhp, errhp, svchp, pertdo, (dvoid *) per, + (dvoid *) null_per); + } + } + + if ( status != OCI_NO_DATA ) + checkerr(errhp, status); + + (void) printf("\n\n"); +} + + +/**************************************************************************** +* Clean up the schema and the data * +*****************************************************************************/ +void cleanup(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + /* clean up the schema */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, + (text *) "drop table customer_tab", + (ub4) strlen((char *)"drop table customer_tab" ), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) + NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, + (text *) "drop table person_tab", + (ub4) strlen((char *)"drop table person_tab" ), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) + NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) "drop type customer", + (ub4) strlen((char *)"drop table customer" ), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) + NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) "drop type person", + (ub4) strlen((char *)"drop table person" ), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) + NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) "drop type addr_tab", + (ub4) strlen((char *)"drop table addr_tab" ), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) + NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) "drop type address", + (ub4) strlen((char *) "drop type address"), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) + NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +} + + +/*****************************************************************************/ +int main() +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCISession *usrhp; + OCIStmt *stmthp; + dvoid *tmp; + + /* initialize the process */ + (void) OCIInitialize((ub4) OCI_THREADED | OCI_OBJECT, + (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)()) 0, (void (*)()) 0 ); + + /* initialize the environmental handle */ + (void) OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + /* get the error handle */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + + /* two server contexts */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp); + /* attach the server */ + (void) OCIServerAttach( srvhp, errhp, (text *) "", (sb4) 0, + (ub4) OCI_DEFAULT); + + /* get the service handle */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp); + + /* set attribute server context in the service context */ + (void) OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp); + + /* get the user handle */ + (void) OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, + (ub4)OCI_HTYPE_SESSION, 0, (dvoid **)0); + + /* set the attribute user name */ + (void) OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"scott", (ub4)strlen((char *)"scott"), + (ub4)OCI_ATTR_USERNAME, errhp); + + /* set the attribute password */ + (void) OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"tiger", (ub4)strlen((char *)"tiger"), + (ub4)OCI_ATTR_PASSWORD, errhp); + + /* authenticate */ + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, + OCI_CRED_RDBMS, OCI_DEFAULT)); + + /* set the attribute user context of the service handle */ + (void) OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, + (ub4)OCI_ATTR_SESSION, errhp); + + /* get the statement handle */ + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, 50, (dvoid **) &tmp)); + + (void) printf("\n*********************************************\n"); + (void) printf("--- Setup the schema and insert the data.\n"); + setup(envhp, svchp, stmthp, errhp); + + (void) printf("\n*********************************************\n"); + (void) printf("--- Select a REF, pin the REF, then display the object.\n"); + select_pin_display(envhp, svchp, stmthp, errhp); + + (void) printf("\n*********************************************\n"); + (void) printf("--- Clean up the schema and the data.\n"); + cleanup(envhp, svchp, stmthp, errhp); + + checkerr(errhp, OCISessionEnd (svchp, errhp, usrhp, OCI_DEFAULT)); + + /* dettach */ + (void) OCIServerDetach( srvhp, errhp, (ub4) OCI_DEFAULT ); + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT)); + checkerr(errhp, OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX)); + checkerr(errhp, OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR)); + checkerr(errhp, OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER)); + + return (0); +} + diff --git a/cdemobj.h b/cdemobj.h new file mode 100644 index 0000000..27c42d4 --- /dev/null +++ b/cdemobj.h @@ -0,0 +1,150 @@ +/* + * $Header: cdemobj.h 17-feb-2005.17:47:43 aliu Exp $ + */ + +/* Copyright (c) 1995, 2005, Oracle. All rights reserved. +*/ + +/* + NAME + cdemobj.h + + DESCRIPTION + This file contains the header information for the cdemobj.c + + RELATED DOCUMENTS + None. + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + None. + + PRIVATE FUNCTION(S) + As defined below. + + EXAMPLES + + NOTES + + MODIFIED (MM/DD/YY) + aliu 02/17/05 - lint issues + aliu 02/16/05 - fix bug 4184313 + aliu 12/07/00 - fix bug 1237851: add #include . + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + skmishra 05/14/97 - stdcc compatibility changes + azhao 03/28/97 - include ocikp.h + echen 11/15/96 - remove unnecessary header files + dchatter 07/18/96 - delete spurious .h files + echen 07/16/96 - Creation +*/ + +#ifndef CDEMOBJ_ORACLE +#define CDEMOBJ_ORACLE + +#ifndef OCI_ORACLE +#include +#endif + +#include + +#include + +#ifndef ORID_ORACLE +#include +#endif + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +struct address +{ + OCINumber no; + OCIString *street; + OCIString *state; + OCIString *zip; +}; +typedef struct address address; + +struct null_address +{ + sb2 null_addr; + sb2 null_no; + sb2 null_street; + sb2 null_state; + sb2 null_zip; +}; +typedef struct null_address null_address; + +struct person +{ + OCIString *fname; + OCIString *lname; + OCINumber age; + OCINumber salary; + OCINumber bonus; + OCINumber retirement_fund; + OCINumber number_of_kids; + OCINumber years_of_school; + OCITable *preaddr; + OCIDate birthday; + OCINumber number_of_pets; + OCIRaw *comment1; + OCILobLocator *comment2; + OCIString *comment3; + address addr; +}; +typedef struct person person; + +struct null_person +{ + OCIInd null_per; + OCIInd null_fname; + OCIInd null_lname; + OCIInd null_age; + OCIInd null_salary; + OCIInd null_bonus; + OCIInd null_retirement_fund; + OCIInd null_number_of_kids; + OCIInd null_years_of_school; + OCIInd null_preaddr; + OCIInd null_birthday; + OCIInd null_number_of_pets; + OCIInd null_comment1; + OCIInd null_comment2; + OCIInd null_comment3; + null_address null_addr; +}; +typedef struct null_person null_person; + +struct customer +{ + OCIString *account; + OCIRef *aperson; +}; +typedef struct customer customer; + +struct null_customer +{ + OCIInd null_cus; + OCIInd null_account; + OCIInd null_aperson; +}; +typedef struct null_customer null_customer; + +int main(/*_ void _*/); + +#endif /* TKPOTTA_ORACLE */ diff --git a/cdemocoll.c b/cdemocoll.c new file mode 100644 index 0000000..4ce4d1d --- /dev/null +++ b/cdemocoll.c @@ -0,0 +1,720 @@ +/* Copyright (c) 2004, 2006, Oracle. All rights reserved. */ + +/* + + NAME + cdemocoll.c - collection demo program in OCI + + DESCRIPTION - demo of insertion(bind) and selection(define) of collection + columns (nested table and varray) as named datatype SQLT_NTY + using OCI interface. + + Note: Before running this program, ensure that the database is + started up and tables of cdemocoll_customer_nt and + cdemocoll_customer_va and types of cdemocoll_int_nt and + cdemocoll_char_va do not exist in SCOTT/TIGER sample account. + + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + aliu 05/06/04 - aliu_add_coll_demo + aliu 05/04/04 - Creation + +*/ + +#ifndef CDEMOCOLL +#define CDEMOCOLL + +/*------------------------------------------------------------------------ + * Include Files + */ + +#ifndef ORATYPES +#include +#endif + +#ifndef STDIO +#include +#endif + +#ifndef STDLIB +#include +#endif + +#ifndef STRING +#include +#endif + +#ifndef OCI_ORACLE +#include +#endif + +#ifndef CDEMOCOLL_ORACLE +#include "cdemocoll.h" +#endif + +/*----------------- End of including files -----------------*/ + +/*--------------------- Public Constants and Variables ----------------------*/ + +/* constants */ +#define MAXBUFLEN 200 + +/* database login information */ +static text *user=(text *)"SCOTT"; +static text *password=(text *)"tiger"; + +/* OCI Handles and Variables */ +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCISvcCtx *svchp; +static OCIError *errhp; +static OCISession *authp; +static OCIStmt *stmthp; + +/* Misellaneous */ +static sword status; +static boolean tab_exists = FALSE; + +/*----------------- End of Constants and Variables -----------------*/ + +/*--------------------- Functions Declaration --------------------*/ + +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void cleanup(/*_ void _*/); +static sb4 connect_server(/*_ void _*/); +static void disconnect_server(/*_ void _*/); +static void drop_table(/*_ void _*/); +static sb4 init_env_handle(/*_ void _*/); +static sb4 init_table(/*_ void _*/); +static sb4 insert_coll(/*_ ub4 custno, ub4 flag _*/); +static sb4 select_coll(/*_ ub4 custno, ub4 flag _*/); + +/*--------------------- End of Functions Declaration --------------------*/ + +#endif + + +/*---------------------------Main function -----------------------------*/ +int main() +{ + ub4 custno; + ub4 flag; + + /* Initialize the environment and allocate handles */ + if (init_env_handle()) + { + printf("FAILED: init_env_handle()!\n"); + return OCI_ERROR; + } + + /* Log on to the server and begin a session */ + if (connect_server()) + { + printf("FAILED: connect_server()!\n"); + cleanup(); + return OCI_ERROR; + } + + /* Initialize the types/tables */ + if (init_table()) + { + printf("FAILED: init_table()\n"); + disconnect_server(); + return OCI_ERROR; + } + + custno = 1; + /* flag = 1: nested table column + otherwise: varray column */ + for (flag = 1; flag <= 2; flag++) { + /* Insertion */ + if (insert_coll(custno, flag)) + { + printf("FAILED: insert_coll()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* Selection */ + if (select_coll(custno, flag)) + { + printf("FAILED: select_coll()!\n"); + disconnect_server(); + return OCI_ERROR; + } + } + + /* Drop types/tables, detach from a server, and clean up the environment */ + disconnect_server(); + + return OCI_SUCCESS; +} + + +/*---------------------------Subfunctions -----------------------------*/ + +/*--------------------------------------------------------*/ +/* Return corresponding messages in differrent cases */ +/*--------------------------------------------------------*/ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text msgbuf[512]; + sb4 errcode = 0; + + memset((void *) msgbuf, (int)'\0', (size_t)512); + + switch (status) + { + case OCI_SUCCESS: break; + case OCI_SUCCESS_WITH_INFO: + printf("status = OCI_SUCCESS_WITH_INFO\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_NEED_DATA: + printf("status = OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("status = OCI_NO_DATA\n"); + break; + case OCI_ERROR: + printf("status = OCI_ERROR\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_INVALID_HANDLE: + printf("status = OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("status = OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("status = OCI_CONTINUE\n"); + break; + default: + break; + } + + return; +} + + +/*--------------------------------------------------------*/ +/* Free the envhp whenever there is an error */ +/*--------------------------------------------------------*/ +void cleanup() +{ + if (envhp) { + OCIHandleFree((dvoid *)envhp, OCI_HTYPE_ENV); + } + + return; +} + + +/*--------------------------------------------------------*/ +/* attach to server, set attributes, and begin session */ +/*--------------------------------------------------------*/ +sb4 connect_server() +{ + /* attach to server */ + if (status = OCIServerAttach((OCIServer *) srvhp, (OCIError *) errhp, + (text *) "", (sb4) strlen(""), (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIServerAttach() on srvhp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set server attribute to service context */ + if (status = OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, + (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on svchp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set user attribute to session */ + if (status = OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) user, (ub4) strlen((char *)user), + (ub4) OCI_ATTR_USERNAME, (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on authp for user\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set password attribute to session */ + if (status = OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *)password), + (ub4) OCI_ATTR_PASSWORD, (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on authp for password\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* Begin a session */ + if (status = OCISessionBegin((OCISvcCtx *) svchp, (OCIError *) errhp, + (OCISession *) authp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCISessionBegin()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set session attribute to service context */ + if (status = OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, + (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on svchp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* End the session, detach server and free handles. */ +/*--------------------------------------------------------*/ +void disconnect_server() +{ + printf("\n\nLogged off and detached from server.\n"); + + /* Drop the tables/types if any */ + if (tab_exists) + drop_table(); + + /* End a session */ + if (status = OCISessionEnd((OCISvcCtx *)svchp, (OCIError *)errhp, + (OCISession *)authp, (ub4) OCI_DEFAULT)) { + checkerr(errhp, status); + cleanup(); + return; + } + + /* Detach from the server */ + if (status = OCIServerDetach((OCIServer *)srvhp, (OCIError *)errhp, + (ub4)OCI_DEFAULT)) { + checkerr(errhp, status); + cleanup(); + return; + } + + /* Free the handles */ + if (stmthp) { + OCIHandleFree((dvoid *)stmthp, (ub4) OCI_HTYPE_STMT); + } + if (authp) { + OCIHandleFree((dvoid *)authp, (ub4) OCI_HTYPE_SESSION); + } + if (svchp) { + OCIHandleFree((dvoid *)svchp, (ub4) OCI_HTYPE_SVCCTX); + } + if (srvhp) { + OCIHandleFree((dvoid *)srvhp, (ub4) OCI_HTYPE_SERVER); + } + if (errhp) { + OCIHandleFree((dvoid *)errhp, (ub4) OCI_HTYPE_ERROR); + } + if (envhp) { + OCIHandleFree((dvoid *)envhp, (ub4) OCI_HTYPE_ENV); + } + + return; +} + + +/*--------------------------------------------------------*/ +/* Drop tables/types */ +/*--------------------------------------------------------*/ +void drop_table() +{ + text *dropstmt[4] = { (text *) "drop table cdemocoll_customer_nt", + (text *) "drop type cdemocoll_int_nt", + (text *) "drop table cdemocoll_customer_va", + (text *) "drop type cdemocoll_char_va" }; + int i=0; + + for (i=0; i<4; i++) { + + /* prepare drop statement */ + if (OCIStmtPrepare(stmthp, errhp, dropstmt[i], (ub4) strlen((char *) dropstmt[i]), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtPrepare() dropstmt\n"); + return; + } + /* execute drop statement */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtExecute() dropstmt\n"); + return; + } + + } /* end of for (i=0; ... ) */ + + return; +} + + +/*--------------------------------------------------------*/ +/* Initialize the environment and allocate handles */ +/*--------------------------------------------------------*/ +sb4 init_env_handle() +{ + /* Environment initialization and creation */ + if (OCIEnvCreate((OCIEnv **) &envhp, (ub4) OCI_OBJECT, (dvoid *) 0, + (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t)) 0, + (void (*)(dvoid *, dvoid *)) 0, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIEnvCreate()\n"); + return OCI_ERROR; + } + + /* allocate error handle */ + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on errhp\n"); + return OCI_ERROR; + } + + /* allocate server handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on srvhp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* allocate service context handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on svchp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* allocate session handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on authp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* Allocate statement handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on stmthp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* create types and tables */ +/*--------------------------------------------------------*/ +sb4 init_table() +{ + int colc; + text *crtstmt[4] = { (text *) "create type cdemocoll_int_nt is table of integer", + (text *) "create table cdemocoll_customer_nt (custno number, income cdemocoll_int_nt)\ + nested table income store as cdemocoll_income_table", + (text *) "create type cdemocoll_char_va is varray(10) of char(20)", + (text *) "create table cdemocoll_customer_va (custno number, names cdemocoll_char_va)" }; + int i=0; + + for (i=0; i<4; i++) { + + /* prepare create statement */ + if (status = OCIStmtPrepare(stmthp, errhp, crtstmt[i], (ub4) strlen((char *) crtstmt[i]), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtPrepare() crtstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + /* execute create statement */ + if (status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtExecute() crtstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* commit the Xn */ + OCITransCommit(svchp, errhp, (ub4)0); + + } /* end of for (i=0; ... ) */ + + /* set flag to be used by disconnect_server() to drop the tables */ + tab_exists = TRUE; + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* insert collection column into the table */ +/* flag = 1: nested table column + otherwise: varray column */ +/*--------------------------------------------------------*/ +sb4 insert_coll(custno, flag) +ub4 custno; +ub4 flag; +{ + text inst[MAXBUFLEN]; + OCIBind *bndp1 = (OCIBind *)0; + OCIBind *bndp2 = (OCIBind *)0; + OCIType *coll_tdo= (OCIType *)0; + OCIColl *ptrcoll = (OCIColl *)0; + ub4 i = 0, elem = 0; + OCINumber ocinum; + OCIString *ocistr = (OCIString *)0; + text *str[5] = { (text *)"Andy", (text *)"Bill", (text *)"Cathy", + (text *)"David", (text *)"Eddy" }; + + if (flag == 1) { + strcpy((char *)inst, (char *)"INSERT INTO cdemocoll_customer_nt VALUES (:num, :coll)"); + } + else { + strcpy((char *)inst, (char *)"INSERT INTO cdemocoll_customer_va VALUES (:num, :coll)"); + } + + printf("\n=> %s for custno %d ......\n", inst, custno); + + /* get type information */ + OCITypeByName(envhp, errhp, svchp, (CONST text *)"", (ub4)0, + (CONST text *) ((flag == 1) ? "CDEMOCOLL_INT_NT" : "CDEMOCOLL_CHAR_VA"), + (ub4) ((flag == 1) ? strlen("CDEMOCOLL_INT_NT") : strlen("CDEMOCOLL_CHAR_VA")), + (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_HEADER, &coll_tdo); + + /* instantiate the collection */ + OCIObjectNew(envhp, errhp, svchp, + ((flag == 1) ? OCI_TYPECODE_TABLE : OCI_TYPECODE_VARRAY), + (OCIType *) coll_tdo, + (dvoid *) 0, OCI_DURATION_SESSION, TRUE, + (dvoid **) &ptrcoll); + + if (flag == 1) { + /* populate the nested table */ + for (i = 0; i < 5; i++) + { + elem = i; + checkerr(errhp,OCINumberFromInt(errhp, &elem, sizeof(elem), OCI_NUMBER_UNSIGNED, + &ocinum)); + checkerr(errhp,OCICollAppend(envhp, errhp, (CONST dvoid *)&ocinum, + (dvoid *) 0, (OCIColl *) ptrcoll)); + } + } + else { + /* populate VARRAY */ + for (i = 0; i < 5; i++) + { + checkerr(errhp, OCIStringAssignText(envhp, + errhp, str[i], (ub4)strlen((char *) str[i]), + &ocistr)); + checkerr(errhp, OCICollAppend(envhp, + errhp, (CONST dvoid *)ocistr, (dvoid *) 0, + (OCIColl *) ptrcoll)); + } + } + + /* insert the collection column into the table */ + printf ("\n ######## inserting the collection ############ \n"); + OCIStmtPrepare(stmthp, errhp, inst, (ub4) strlen((char *)inst), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT); + + i = custno; + OCIBindByName(stmthp, &bndp1, errhp, + (text *)":num", (sb4)strlen(":num"), (dvoid*)&i, sizeof(i), + SQLT_INT, (dvoid*)0, (ub2*)0, (ub2*)0, (ub4)0, (ub4*)0, + OCI_DEFAULT); + + OCIBindByName(stmthp, &bndp2, errhp, + (text *)":coll", (sb4)strlen (":coll"), (dvoid*)0, (sb4)0, + SQLT_NTY, (dvoid*)0, (ub2*)0, (ub2*)0, (ub4)0, (ub4*)0, + OCI_DEFAULT); + if (status = OCIBindObject(bndp2, errhp, coll_tdo, (dvoid **) &ptrcoll, (ub4 *) 0, + (dvoid **)0, (ub4 *) 0)) { + checkerr(errhp, status); + } + + if (status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, OCI_COMMIT_ON_SUCCESS)) { + checkerr(errhp, status); + } + + /* free the collection */ + OCIObjectFree(envhp, errhp, ptrcoll, OCI_OBJECTFREE_FORCE); + + printf("\n=> Insertion done\n"); + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* select collection column from the table */ +/* flag = 1: nested table column + otherwise: varray column */ +/*--------------------------------------------------------*/ +sb4 select_coll(custno, flag) +ub4 custno; +ub4 flag; +{ + text sel[MAXBUFLEN]; + OCIDefine *defp1 = (OCIDefine *)0; + OCIBind *bndp1 = (OCIBind *)0; + OCIType *coll_tdo= (OCIType *)0; + OCIColl *ptrcoll = (OCIColl *)0; + ub4 i = 0; + dvoid *elem = (dvoid *)0; + ub4 size = 0; + boolean exists = FALSE; + int nt_value = 0; + OCIString *va_value = (OCIString *)0; + + if (flag == 1) { + strcpy((char *)sel, (char *)"SELECT income FROM cdemocoll_customer_nt WHERE custno = :num"); + } + else { + strcpy((char *)sel, (char *)"SELECT names FROM cdemocoll_customer_va WHERE custno = :num"); + } + + printf("\n=> %s for custno %d ......\n", sel, custno); + + /* get type information */ + /* get type information */ + OCITypeByName(envhp, errhp, svchp, (CONST text *)"", (ub4)0, + (CONST text *) ((flag == 1) ? "CDEMOCOLL_INT_NT" : "CDEMOCOLL_CHAR_VA"), + (ub4) ((flag == 1) ? strlen("CDEMOCOLL_INT_NT") : strlen("CDEMOCOLL_CHAR_VA")), + (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_HEADER, &coll_tdo); + + /* instantiate the collection */ + OCIObjectNew(envhp, errhp, svchp, + ((flag == 1) ? OCI_TYPECODE_TABLE : OCI_TYPECODE_VARRAY), + (OCIType *) coll_tdo, + (dvoid *) 0, OCI_DURATION_SESSION, TRUE, + (dvoid **) &ptrcoll); + + /* select the collection column from the table */ + printf ("\n ######## selecting the collection ############ \n"); + OCIStmtPrepare(stmthp, errhp, sel, (ub4) strlen((char *)sel), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT); + + OCIDefineByPos(stmthp, &defp1, errhp, (ub4) 1, (dvoid *)0, + (sb4) 0, SQLT_NTY, (dvoid *) 0, + (ub2 *)0, (ub2 *)0, (ub4) OCI_DEFAULT); + if (status = OCIDefineObject(defp1, errhp, coll_tdo, (dvoid **) &ptrcoll, &size, + (dvoid **)0, (ub4 *)0)) { + checkerr(errhp, status); + } + + i = custno; + OCIBindByName(stmthp, &bndp1, errhp, + (text *)":num", (sb4)strlen(":num"), (dvoid*)&i, sizeof(i), + SQLT_INT, (dvoid*)0, (ub2*)0, (ub2*)0, (ub4)0, (ub4*)0, + OCI_DEFAULT); + + if (status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, OCI_DEFAULT)) { + checkerr(errhp, status); + } + + if (status = OCIStmtFetch2(stmthp, errhp, (ub4)1, OCI_FETCH_NEXT, (sb4) 0, OCI_DEFAULT)) { + checkerr(errhp, status); + } + + /* print out the results */ + if (flag == 1) { + /* print out the nested table */ + printf ("\n ######## printing out the nested table ############ \n"); + for (i=0; i < 5; i++) + { + OCICollGetElem(envhp, errhp, (CONST OCIColl *) ptrcoll, (sb4) i, &exists, + (dvoid **)&elem, (dvoid **)0); + if (!exists) + { + printf("Error: end of collection\n"); + break; + } + else { + OCINumberToInt(errhp, elem, sizeof(nt_value), 0, &nt_value); + printf ("%d\n", nt_value); + } + } + } + else { + /* print out VARRAY */ + printf ("\n ######## printing out the VARRAY ############ \n"); + for (i =0; i < 5; i++) + { + checkerr(errhp, OCICollGetElem(envhp, + errhp, (CONST OCIColl *) ptrcoll, (sb4) i, &exists, + (dvoid **)&elem, (dvoid **)0)); + if (!exists) + { + printf("Error: end of collection\n"); + break; + } + else { + va_value = *(OCIString **)elem; + printf("%s\n", (text *)OCIStringPtr(envhp, (CONST OCIString *)va_value)); + } + } + } + + /* free the collection */ + OCIObjectFree(envhp, errhp, ptrcoll, OCI_OBJECTFREE_FORCE); + + printf("\n=> Selection done\n"); + + return OCI_SUCCESS; +} + + +/* end of file cdemocoll.c */ diff --git a/cdemocoll.h b/cdemocoll.h new file mode 100644 index 0000000..d12c615 --- /dev/null +++ b/cdemocoll.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2004, Oracle. All rights reserved. */ + +/* + NAME + cdemocoll.h - collection demo program in OCI + + DESCRIPTION + demo of insertion(bind) and selection(define) of collection + columns (nested table and varray) as named datatype SQLT_NTY + using OCI interface. + + RELATED DOCUMENTS + + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + aliu 05/06/04 - aliu_add_coll_demo + aliu 05/04/04 - Creation + +*/ + +#ifndef CDEMOCOLL_ORACLE +# define CDEMOCOLL_ORACLE + +int main(/*_ void _*/); + +#endif /* CDEMOCOLL_ORACLE */ diff --git a/cdemocor.c b/cdemocor.c new file mode 100644 index 0000000..48a187a --- /dev/null +++ b/cdemocor.c @@ -0,0 +1,1098 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemocor.c 18-feb-2005.15:07:29 aliu Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1995, 2005, Oracle. All rights reserved. +*/ + +/* + NAME + cdemocor.c + DESCRIPTION + Demo COR user interface. Run cdemocor.sql bfirst. + + NOTES + see routines. + + MODIFIED (MM/DD/YY) + aliu 02/17/05 - lint issues + aliu 02/16/05 - fix bug 4184560 + emendez 09/13/00 - fix top 5 olint errors + mpjoshi 07/29/99 - updating file from 806 (Add OCICacheUnpin: HSBEDI) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + svedala 07/02/98 - no handlealloc required for define handles + tanguyen 08/19/97 - + echen 06/04/97 - fix warning mesg + echen 05/31/97 - Creation +*/ + +#ifndef CDEMOCOR_ORACLE +#include "cdemocor.h" +#endif + +/* + * COR is a prefetching mechanism which does not add any more + * functionality but improves performance. This demo shows how + * you can use COR to improve the performance of your application + * by cutting down on the number of network roundtrips. Since it + * may not be easy for you to track the actual network roundtrips + * you can turn VERIFY_COR to TRUE which lets you verify that the + * pin calls find the prefetched objects in the object cache and + * thus do not incur a n/w roundtrip. By setting VERIFY_COR to + * TRUE, you modify the data corresponding to the prefetched + * objects (in the object cache) in the server. When you access + * these prefetched objects on the client side, you get the ones + * locally cached in the object cache (and not the new modified + * ones in the server). + */ +#define VERIFY_COR FALSE + +static const text *const selref = (text *) + "SELECT REF(po) from po_table po where po.po_number = 1"; +static const text *const selall = (text *) + "SELECT REF(po) from po_table po"; +static const text *sch_name_arr[] = {(const text *)0, (const text *)0}; +static ub4 sch_name_len_arr[] = {(ub4)0, (ub4)0}; +static const text *type_name_arr[] = + {(const text *)"PURCHASE_ORDER", (const text *)"CUSTOMER"}; +static ub4 type_name_len_arr[] = {(ub4)14, (ub4)8}; +static const text *version_arr[] = {(const text *)0, (const text *)0}; +static ub4 version_len_arr[] = {(ub4)0, (ub4)0}; + +/*****************************************************************************/ +void checkerr1(errhp, status, file, line) +OCIError *errhp; +sword status; +const char *file; +int line; +{ + text errbuf[512]; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet ((dvoid *) errhp, (ub4) 1, + (text *) NULL, (sb4 *) &errcode, + errbuf, (ub4) sizeof(errbuf), + (ub4) OCI_HTYPE_ERROR); + (void) printf("Error - %s, file %s, line %d\n", + errbuf, file, line); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + +static void demo_cor_1(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIRef *poref = (OCIRef *)0; + OCIIter *itr; + boolean eoc; + purchase_order *po = (purchase_order *)0; + purchase_order *related_po = (purchase_order *)0; + customer *cust = (customer *)0; + OCIDefine *defnp; + OCIComplexObject *corhp, *corhp3; + OCIComplexObjectComp *cordp1, *cordp3; + OCIType *custtdo, *custtdo2; + OCIRef *custref = (OCIRef *)0; + OCIComplexObjectComp *cordp2; + OCIType *po_tdo; + ub4 po_size; + OCIRef *po_ref = (OCIRef *)0; + ub4 level = 0; + ub4 mylevel, siz, paramcount = 0; + dvoid *tdo_arr[2]; + dvoid *tmp; + sword status = OCI_SUCCESS; + OCIParam *parmp; + ub1 outofline = FALSE; + int age, po_num; + address *addr = (address *) 0; + sb4 index; + boolean exist; +#ifdef VERIFY_COR + text *stmt11 = (text *) + "update cust_table set name = 'Anil' where name = 'JOHN'"; + text *stmt12 = (text *) + "update cust_table set name = 'Chin' where name = 'MIKE'"; + text *stmt13 = (text *) + "insert into the (select addr from cust_table where name='Anil') \ + select 'ca', '90417', ref(x) from person_table x where name='JOHN2'"; + text *stmt14 = (text *) + "insert into the (select addr from cust_table where name='Chin') \ + select 'ca', '90417', ref(x) from person_table x where name='JOHN2'"; +#endif + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selref, + (ub4) strlen((char *) selref), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, + (dvoid *) 0, (sb4) 0, SQLT_REF, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) OCI_DEFAULT)); + + /* get type of purchase_order to set in COR descriptor */ + checkerr(errhp, OCITypeArrayByName(envhp, errhp, svchp, 2, + (CONST oratext **) sch_name_arr, + sch_name_len_arr, (CONST oratext **) type_name_arr, + type_name_len_arr, (CONST oratext **) version_arr, + version_len_arr, OCI_DURATION_SESSION, + OCI_TYPEGET_ALL, (OCIType **) tdo_arr)); + po_tdo = (OCIType *)tdo_arr[0]; + custtdo = (OCIType *)tdo_arr[1]; + + checkerr(errhp, OCIDefineObject(defnp, errhp, po_tdo, (dvoid **) &poref, + &po_size, (dvoid **) 0, (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, + (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)); + + /*---------------------------- C O R --------------------------------*/ + /* get COR Handle */ + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&corhp, + (ub4)OCI_HTYPE_COMPLEXOBJECT, 0, + (dvoid **)0)); + + /*---------------------------- put customer -------------------------*/ + /* get COR descriptor for type customer */ + checkerr(errhp, OCIDescriptorAlloc((dvoid *)envhp, (dvoid **)&cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, 0, + (dvoid **)0)); + + /* set customer type in COR descriptor */ + checkerr(errhp, OCIAttrSet((dvoid *)cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, (dvoid *)custtdo, + (ub4)sizeof(dvoid *), (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE, + (OCIError *)errhp)); + + level = 2; + /* set depth level for customer in COR descriptor */ + checkerr(errhp, OCIAttrSet((dvoid *)cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, + (dvoid *)&level, (ub4)sizeof(ub4), + (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE_LEVEL, (OCIError *)errhp)); + + /* set attributes to COR handle */ + if (OCIAttrSet((dvoid *)corhp,(ub4) OCI_HTYPE_COMPLEXOBJECT, + (dvoid *)&outofline, (ub4)sizeof(ub1), + (ub4)OCI_ATTR_COMPLEXOBJECT_COLL_OUTOFLINE, + (OCIError *)errhp)) + (void) printf("BUG: set COR attribute out of line\n"); + + if (OCIAttrSet((dvoid *)corhp,(ub4) OCI_HTYPE_COMPLEXOBJECT, + (dvoid *)&outofline, (ub4)sizeof(ub1), (ub4)OCI_ATTR_SERVER, + (OCIError *)errhp) != OCI_ERROR) + (void) printf("BUG: set COR attribute to server\n"); + + /* get attributes from COR handle */ + if (OCIAttrGet((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *) &mylevel, (ub4 *) &siz, + (ub4)OCI_ATTR_COMPLEXOBJECT_LEVEL, (OCIError *)errhp)) + (void) printf("BUG: get COR attribute\n"); + + if (OCIAttrGet((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *) ¶mcount, (ub4 *) &siz, + (ub4)OCI_ATTR_PARAM_COUNT, (OCIError *)errhp)) + (void) printf("BUG: get COR attribute\n"); + + if (OCIAttrGet((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *) &outofline, (ub4 *) 0, + (ub4)OCI_ATTR_COMPLEXOBJECT_COLL_OUTOFLINE, + (OCIError *)errhp)) + (void) printf("BUG: get COR attribute\n"); + + if (OCIAttrGet((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *) &outofline, (ub4 *) 0, + (ub4)OCI_ATTR_SCALE, (OCIError *)errhp) == OCI_SUCCESS) + (void) printf("BUG: get COR attribute\n"); + + + /* get attributes from COR descriptor */ + if (OCIAttrGet((dvoid *)cordp1, (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, + (dvoid *) &custtdo2, (ub4 *) 0, + (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE, (OCIError *)errhp)) + (void) printf("BUG: get COR attribute\n"); + + if (OCIAttrGet((dvoid *)cordp1, (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, + (dvoid *) &custtdo2, (ub4 *) 0, + (ub4)OCI_ATTR_SCALE, (OCIError *)errhp) == OCI_SUCCESS) + (void) printf("BUG: get COR attribute\n"); + + if (OCIAttrGet((dvoid *)cordp1, (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, + (dvoid *) &mylevel, (ub4 *) 0, + (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE_LEVEL, + (OCIError *)errhp)) + (void) printf("BUG: get COR attribute\n"); + + if (mylevel != level) + (void) printf("BUG: mylevel = %d, level = %d\n", mylevel, level); + + + /* put COR descriptor in COR handle */ + checkerr(errhp, OCIParamSet(corhp, OCI_HTYPE_COMPLEXOBJECT, errhp, + cordp1, OCI_DTYPE_COMPLEXOBJECTCOMP, 1)); + + if (OCIParamGet(corhp, OCI_HTYPE_COMPLEXOBJECT, errhp, (dvoid *) &corhp3, 1) + != OCI_SUCCESS) + (void) printf("BUG: get parm on corhp\n"); + + if (OCIParamGet(stmthp, OCI_HTYPE_STMT, errhp, (dvoid *) &parmp, 1) + != OCI_SUCCESS) + (void) printf("BUG: get parm on stmthp with position 1\n"); + + + /*------------------------- put purchase_order ------------------------*/ + /* get COR descriptor for type purchase_order */ + checkerr(errhp, OCIDescriptorAlloc((dvoid *)envhp, + (dvoid **)&cordp2, (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, 0, + (dvoid **)0)); + + /* set customer type in COR descriptor */ + checkerr(errhp, OCIAttrSet((dvoid *)cordp2, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, (dvoid *)po_tdo, + (ub4)sizeof(dvoid *), (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE, + (OCIError *)errhp)); + + level = 2; + + /* set depth level for customer in COR descriptor */ + checkerr(errhp, OCIAttrSet((dvoid *)cordp2, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, (dvoid *)&level, + (ub4)sizeof(ub4), (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE_LEVEL, + (OCIError *)errhp)); + + /* put COR descriptor in COR handle */ + checkerr(errhp, OCIParamSet(corhp, OCI_HTYPE_COMPLEXOBJECT, + errhp, cordp2, OCI_DTYPE_COMPLEXOBJECTCOMP, 2)); + + + if (OCIParamGet(corhp, OCI_HTYPE_COMPLEXOBJECT, errhp, (dvoid *) &cordp3, 1)) + (void) printf("BUG: get parm on cordp\n"); + + + /* pin the purchase order */ + checkerr(errhp, OCIObjectPin(envhp, errhp, poref, corhp, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, (dvoid **)&po)); + + checkerr(errhp, OCINumberToInt(errhp, &po->po_number, + sizeof(po_num), OCI_NUMBER_SIGNED, + (dvoid *) &po_num)); + (void) printf(" The po number is %d\n", po_num); + +#ifdef VERIFY_COR + /* Modify the data */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt11, + (ub4) strlen((char *) stmt11), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt12, + (ub4) strlen((char *) stmt12), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt13, + (ub4) strlen((char *) stmt13), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt14, + (ub4) strlen((char *) stmt14), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +#endif + + /* pin the customer (shouldn't go over the n/w) */ + /* you should see MIKE and JOHN and should not see newly inserted records */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->cust, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + /* pin the purchase_order (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->related_orders, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&related_po)); + + /* pin the customer (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, related_po->cust, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + checkerr(errhp, OCICacheUnpin(envhp, errhp, svchp)); + checkerr(errhp, OCICacheFree(envhp, errhp, svchp)); + + /* free COR descriptor and COR handle */ + checkerr(errhp, OCIDescriptorFree((dvoid *)cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP)); + checkerr(errhp, OCIDescriptorFree((dvoid *)cordp2, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP)); + checkerr(errhp, OCIHandleFree((dvoid *)corhp, + (ub4)OCI_HTYPE_COMPLEXOBJECT)); +} + + +static void demo_cor_2(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIType *po_tdo; + ub4 po_size; + OCIRef *poref = (OCIRef *)0; + purchase_order *po = (purchase_order *)0; + purchase_order *related_po = (purchase_order *)0; + customer *cust = (customer *)0; + OCIDefine *defnp; + OCIComplexObject *corhp; + ub4 level = 0; + dvoid *tmp; + sword status = OCI_SUCCESS; + int age, po_num; + address *addr = (address *) 0; + sb4 index; + boolean exist; +#ifdef VERIFY_COR + text *stmt11 = (text *) + "update cust_table set name = 'JOHN' where name = 'Anil'"; + text *stmt12 = (text *) + "update cust_table set name = 'MIKE' where name = 'Chin'"; + text *stmt13 = (text *) + "insert into the (select addr from cust_table where name='JOHN') \ + select 'ca', '90418', ref(x) from person_table x where name='JOHN3'"; + text *stmt14 = (text *) + "insert into the (select addr from cust_table where name='MIKE') \ + select 'ca', '90418', ref(x) from person_table x where name='JOHN3'"; +#endif + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) + selref, (ub4) strlen((char *) selref), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, + (dvoid *) 0, (sb4) 0, SQLT_REF, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) OCI_DEFAULT)); + + /* get type of purchase_order to set in COR descriptor */ + OCITypeByName(envhp, errhp, svchp, (text *)0, (ub4)0, + (text *)"PURCHASE_ORDER", + (ub4)strlen((char *)"PURCHASE_ORDER"), + (text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_HEADER, &po_tdo); + + checkerr(errhp, OCIDefineObject(defnp, errhp, po_tdo, + (dvoid **) &poref, &po_size, (dvoid **) 0, + (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, + (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)); + + /*---------------------------- C O R --------------------------------*/ + /* get COR Handle */ + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&corhp, + (ub4)OCI_HTYPE_COMPLEXOBJECT, 0, + (dvoid **)0)); + + level = 5; + /* put level in COR handle */ + checkerr(errhp, OCIAttrSet((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *)&level, (ub4)sizeof(ub4), + (ub4)OCI_ATTR_COMPLEXOBJECT_LEVEL, (OCIError *)errhp)); + + /* pin the purchase order */ + checkerr(errhp, OCIObjectPin(envhp, errhp, poref, corhp, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, (dvoid **)&po)); + +#ifdef VERIFY_COR + /* Modify the data */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt11, + (ub4) strlen((char *) stmt11), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt12, + (ub4) strlen((char *) stmt12), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt13, + (ub4) strlen((char *) stmt13), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt14, + (ub4) strlen((char *) stmt14), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +#endif + + /* pin the customer (shouldn't go over the n/w) */ + /* you should see Anil and Chin */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->cust, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + /* pin the purchase_order (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->related_orders, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&related_po)); + + /* pin the customer (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, related_po->cust, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + checkerr(errhp, OCICacheUnpin(envhp, errhp, svchp)); + checkerr(errhp, OCICacheFree(envhp, errhp, svchp)); + + /* free COR handle */ + checkerr(errhp, OCIHandleFree((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT)); +} + +static void demo_cor_3(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIType *po_tdo; + ub4 po_size; + OCIRef *poref = (OCIRef *)0; + purchase_order *po = (purchase_order *)0; + purchase_order *related_po = (purchase_order *)0; + customer *cust = (customer *)0; + OCIDefine *defnp; + OCIComplexObject *corhp; + ub1 outofline; + dvoid *tmp; + sword status = OCI_SUCCESS; + dvoid *elem = (dvoid *)0; + dvoid *elemind = (dvoid *)0; + sb4 collsiz; + boolean exist; + address *addr = (address *) 0; + null_address *null_addr = (null_address *) 0; + sb4 index = 0, counter = 0; +#ifdef VERIFY_COR + text *stmt11 = (text *) + "update cust_table set name = 'Anil' where name = 'JOHN'"; + text *stmt12 = (text *) + "update cust_table set name = 'Chin' where name = 'MIKE'"; + text *stmt13 = (text *) + "insert into the (select addr from cust_table where name='Anil') \ + select NULL, '90419', ref(x) from person_table x where name='MIKE1'"; + text *stmt14 = (text *) + "insert into the (select addr from cust_table where name='Chin') \ + select NULL, '90419', ref(x) from person_table x where name='MIKE1'"; +#endif + + /*-------------------------- get po ref -----------------------------*/ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selref, + (ub4) strlen((char *) selref), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, (dvoid *) 0, + (sb4) 0, SQLT_REF, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, (ub4) OCI_DEFAULT)); + + /* get type of purchase_order to set in COR descriptor */ + OCITypeByName(envhp, errhp, svchp, (text *)0, (ub4)0, + (text *)"PURCHASE_ORDER", + (ub4)strlen((char *)"PURCHASE_ORDER"), + (text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_HEADER, &po_tdo); + + checkerr(errhp, OCIDefineObject(defnp, errhp, po_tdo, + (dvoid **) &poref, &po_size, (dvoid **) 0, + (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, + (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)); + + /*---------------------------- C O R --------------------------------*/ + /* get COR Handle */ + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&corhp, + (ub4)OCI_HTYPE_COMPLEXOBJECT, 0, + (dvoid **)0)); + + /* pin the purchase order */ + checkerr(errhp, OCIObjectPin(envhp, errhp, poref, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, (dvoid **)&po)); + + outofline = TRUE; + /* put level in COR handle */ + checkerr(errhp, OCIAttrSet((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *)&outofline, (ub4)sizeof(ub1), + (ub4)OCI_ATTR_COMPLEXOBJECT_COLL_OUTOFLINE, + (OCIError *)errhp)); + + /* pin the customer (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->cust, corhp, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + +#ifdef VERIFY_COR + /* Modify the data */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt11, + (ub4) strlen((char *) stmt11), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt12, + (ub4) strlen((char *) stmt12), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + /* add new records */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt13, + (ub4) strlen((char *) stmt13), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt14, + (ub4) strlen((char *) stmt14), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +#endif + + /* should see the new records */ + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &elem, &elemind)); + addr = (address *)elem; + null_addr = (null_address *)elemind; + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + (void) printf(" atomic null indicator is %d\n", null_addr->null_address); + (void) printf(" zip null indicator is %d\n", null_addr->null_zip); + (void) printf(" state null indicator is %d\n", null_addr->null_state); + + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &elem, &elemind)); + addr = (address *)elem; + null_addr = (null_address *)elemind; + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + (void) printf(" atomic null indicator is %d\n", + null_addr->null_address); + (void) printf(" zip null indicator is %d\n", null_addr->null_zip); + (void) printf(" state null indicator is %d\n", null_addr->null_state); + } + + + /* pin the purchase_order (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->related_orders, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&related_po)); + + checkerr(errhp, OCICacheUnpin(envhp, errhp, svchp)); + checkerr(errhp, OCICacheFree(envhp, errhp, svchp)); + + /* free COR handle */ + checkerr(errhp, OCIHandleFree((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT)); +} + +static void demo_cor_4(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIType *po_tdo; + ub4 po_size[3], i; + OCIRef *poref[3]; + purchase_order *po[3]; + purchase_order *related_po = (purchase_order *)0; + customer *cust = (customer *)0; + OCIDefine *defnp; + OCIComplexObject *corhp[3]; + ub4 level = 0; + dvoid *tmp; + sword status = OCI_SUCCESS; + int age, po_num; + address *addr = (address *) 0; + sb4 index; + boolean exist; +#ifdef VERIFY_COR + text *stmt11 = (text *) + "update cust_table set name = 'JOHN' where name = 'Anil'"; + text *stmt12 = (text *) + "update cust_table set name = 'MIKE' where name = 'Chin'"; + text *stmt13 = (text *) + "insert into the (select addr from cust_table where name='JOHN') \ + select 'ca', '90418', ref(x) from person_table x where name='JOHN3'"; + text *stmt14 = (text *) + "insert into the (select addr from cust_table where name='MIKE') \ + select 'ca', '90418', ref(x) from person_table x where name='JOHN3'"; +#endif + + for (i=0; i<3; i++) + poref[i] = (OCIRef *) 0; + + for (i=0; i<3; i++) + po[i] = (purchase_order *) 0; + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selall, + (ub4) strlen((char *) selall), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, + (dvoid *) 0, (sb4) 0, SQLT_REF, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, (ub4) OCI_DEFAULT)); + + /* get type of purchase_order to set in COR descriptor */ + OCITypeByName(envhp, errhp, svchp, (text *)0, (ub4)0, + (text *)"PURCHASE_ORDER", + (ub4)strlen((char *)"PURCHASE_ORDER"), + (text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_HEADER, &po_tdo); + + checkerr(errhp, OCIDefineObject(defnp, errhp, po_tdo, + (dvoid **) poref, po_size, (dvoid **) 0, + (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, + (ub4) 0, (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtFetch(stmthp, errhp, (ub4) 3, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)); + + /*---------------------------- C O R --------------------------------*/ + /* get COR Handle */ + for (i=0; i<3; i++) + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&corhp[i], + (ub4)OCI_HTYPE_COMPLEXOBJECT, 0, + (dvoid **)0); + + level = 1; + /* put level in COR handle */ + for (i=0; i<3; i++) + OCIAttrSet((dvoid *)corhp[i], (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *)&level, (ub4)sizeof(ub4), + (ub4)OCI_ATTR_COMPLEXOBJECT_LEVEL, (OCIError *)errhp); + + checkerr(errhp, OCIObjectArrayPin(envhp, errhp, poref, (ub4) 3, + corhp, (ub4) 3, + OCI_PIN_LATEST, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **) po, 0)); + +#ifdef VERIFY_COR + /* modify the records */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt11, + (ub4) strlen((char *) stmt11), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt12, + (ub4) strlen((char *) stmt12), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + /* add new records */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt13, + (ub4) strlen((char *) stmt13), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt14, + (ub4) strlen((char *) stmt14), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +#endif + + /* pin the purchase order */ + for (i=0; i<3; i++) + { + /* pin the customer (shouldn't go over the n/w) */ + /* you should see Anil and Chin */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po[i]->cust, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, + index, &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + /* pin the purchase_order (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po[i]->related_orders, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&related_po)); + + /* pin the customer (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, related_po->cust, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, + index, &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + } + + checkerr(errhp, OCICacheUnpin(envhp, errhp, svchp)); + checkerr(errhp, OCICacheFree(envhp, errhp, svchp)); + + /* free COR handle */ + for (i=0; i<3; i++) + checkerr(errhp, OCIHandleFree((dvoid *)corhp[i], + (ub4)OCI_HTYPE_COMPLEXOBJECT)); +} + + +int main(int argc, char *argv[]) +{ + OCIEnv *envhp; + OCISvcCtx *svchp; + OCIError *errhp; + OCIServer *srvhp; + OCISession *usrhp; + OCIStmt *stmthp; + sword status = OCI_SUCCESS; + dvoid *tmp = (dvoid *) 0; + + (void) OCIInitialize((ub4) OCI_OBJECT | OCI_DEFAULT, + (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)()) 0, (void (*)()) 0 ); + + (void) OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp)); + + checkerr(errhp, OCIServerAttach( srvhp, errhp, (text *) "", + (sb4) strlen((char *)""), (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp)); + + /* set attribute server context in the service context */ + checkerr(errhp, OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp)); + + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, + (ub4)OCI_HTYPE_SESSION, 0, (dvoid **)0)); + + checkerr(errhp, OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"cdemocor", (ub4)strlen((char *)"cdemocor"), + (ub4)OCI_ATTR_USERNAME, errhp)); + + checkerr(errhp, OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"cdemocor", (ub4)strlen((char *)"cdemocor"), + (ub4)OCI_ATTR_PASSWORD, errhp)); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, + (ub4)OCI_ATTR_SESSION, errhp)); + + /*-------------------------- get po ref -----------------------------*/ + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, 50, + (dvoid **) &tmp)); + + (void) printf("Complex object retrieval demo # 1\n"); + (void) printf(" --> Set level in COR descriptor\n"); + demo_cor_1(envhp, svchp, stmthp, errhp); + (void) printf("Complex object retrieval demo # 2\n"); + (void) printf(" --> Set level in COR handle\n"); + demo_cor_2(envhp, svchp, stmthp, errhp); + (void) printf("Complex object retrieval demo # 3\n"); + (void) printf(" --> Set outofline equal to TRUE\n"); + demo_cor_3(envhp, svchp, stmthp, errhp); + (void) printf("Complex object retrieval demo # 4\n"); + (void) printf(" --> ArrayPin with COR\n"); + demo_cor_4(envhp, svchp, stmthp, errhp); + + OCIDescriptorFree((dvoid *)envhp, (ub4)OCI_HTYPE_ENV); + +} + diff --git a/cdemocor.h b/cdemocor.h new file mode 100644 index 0000000..da6e587 --- /dev/null +++ b/cdemocor.h @@ -0,0 +1,106 @@ +/* + * $Header: cdemocor.h 16-feb-2005.12:23:27 aliu Exp $ + */ + +/* Copyright (c) 1995, 2005, Oracle. All rights reserved. +*/ + +/* + NAME + cdemocor.h + + DESCRIPTION + This file contains the header information for the cdemocor.c + + RELATED DOCUMENTS + None. + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + None. + + PRIVATE FUNCTION(S) + As defined below. + + EXAMPLES + + NOTES + + MODIFIED (MM/DD/YY) + aliu 02/16/05 - fix bug 4184560 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + echen 06/05/97 - remove ifdefed code + echen 05/30/97 - Creation +*/ + +#ifndef CDEMOCOR_ORACLE +#define CDEMOCOR_ORACLE + +#ifndef OCI_ORACLE +#include +#endif + +#include + + +#ifdef __FILE__ +#ifdef __LINE__ +#define checkerr(a, b) checkerr1(a, b, __FILE__, __LINE__) +#else +#define checkerr(a, b) checkerr1(a, b, __FILE__, 0) +#endif +#else +#define checkerr(a, b) checkerr1(a, b, "???", 0) +#endif + + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +struct purchase_order +{ + OCINumber po_number; + OCIRef *cust; + OCIRef *related_orders; +}; +typedef struct purchase_order purchase_order; + +struct customer +{ + OCIString *name; + OCINumber age; + OCITable *addr; +}; +typedef struct customer customer; + +struct address +{ + OCIString *state; /* text state[3]; */ + OCIString *zip; /* text zip[11]; */ +}; +typedef struct address address; + +struct null_address +{ + sb2 null_address; + sb2 null_state; + sb2 null_zip; +}; +typedef struct null_address null_address; + +#endif /* CDEMOCOR_ORACLE */ diff --git a/cdemocor.sql b/cdemocor.sql new file mode 100644 index 0000000..77ccedd --- /dev/null +++ b/cdemocor.sql @@ -0,0 +1,145 @@ +rem +rem $Header: cdemocor.sql 18-jun-2004.14:32:05 stsun Exp $ +rem +rem Copyright (c) 1997, 2004, Oracle. All rights reserved. +rem +rem Owner : echen +rem +rem NAME +rem cdemocor.sql +rem DESCRIPTION +rem A sql script to setup schema before running the demo cdemocor +rem +rem NOTE +rem MODIFIED (MM/DD/YY) +rem stsun 06/18/04 - system/manager instead of sysdba +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem svedala 09/11/98 - a "/" required after create type - bug 717842 +rem cchau 08/18/97 - enable dictionary protection +rem echen 05/30/97 - Creation +rem + +set echo on; + +connect system/manager; + +drop user cdemocor cascade; + +grant connect, resource to cdemocor identified by cdemocor; + +connect cdemocor/cdemocor + +create type person as object (name char(20), age number); +/ + +create type person_tab as table of REF person; +/ + +create type address_object as object (state char(2), zip char(10), + owner REF person); +/ + +create type addr_tab is table of address_object; +/ + +create type CUSTOMER as object +( + name CHAR(20), + age NUMBER, + addr addr_tab +); +/ + +create type PURCHASE_ORDER as object +( + po_number NUMBER, + cust REF CUSTOMER, + related_orders REF PURCHASE_ORDER, + signatories person_tab +); +/ + +create table person_table of person; +create table po_table of purchase_order +nested table signatories store as purchase_order_nt_person_tab; +create table cust_table of customer +nested table addr store as customer_nt_addr_tab; + +INSERT INTO person_table VALUES ('JOHN1', 42); +INSERT INTO person_table VALUES ('JOHN2', 42); +INSERT INTO person_table VALUES ('JOHN3', 42); + +INSERT INTO person_table VALUES ('MIKE1', 29); +INSERT INTO person_table VALUES ('MIKE2', 29); +INSERT INTO person_table VALUES ('MIKE3', 29); + +INSERT INTO person_table VALUES ('GREG1', 22); +INSERT INTO person_table VALUES ('GREG2', 22); +INSERT INTO person_table VALUES ('GREG3', 22); + +INSERT INTO cust_table VALUES ('JOHN', 42, addr_tab()); +INSERT INTO cust_table VALUES ('MIKE', 29, addr_tab()); + +insert into the (select addr from cust_table where name='JOHN') + select 'ca', '90416', ref(x) from person_table x where name='JOHN1'; +insert into the (select addr from cust_table where name='JOHN') + select 'ca', '90417', ref(x) from person_table x where name='JOHN2'; +insert into the (select addr from cust_table where name='JOHN') values (NULL); +insert into the (select addr from cust_table where name='JOHN') + select 'ca', '90418', ref(x) from person_table x where name='JOHN3'; + +insert into the (select addr from cust_table where name='MIKE') + select NULL, '90419', ref(x) from person_table x where name='MIKE1'; +insert into the (select addr from cust_table where name='MIKE') + select 'ca', '90420', ref(x) from person_table x where name='MIKE2'; +insert into the (select addr from cust_table where name='MIKE') + select 'ca', '90421', ref(x) from person_table x where name='MIKE3'; + +INSERT INTO po_table (po_number, signatories) VALUES (1, person_tab()); +INSERT INTO po_table (po_number, signatories) VALUES (2, person_tab()); +INSERT INTO po_table (po_number, signatories) VALUES (3, person_tab()); + +UPDATE po_table + set cust = (select ref(x) from cust_table x where name = 'JOHN') + where po_number = 1; +UPDATE po_table + set cust = (select ref(x) from cust_table x where name = 'MIKE') + where po_number = 2; +UPDATE po_table + set cust = (select ref(x) from cust_table x where name = 'MIKE') + where po_number = 3; + +UPDATE po_table + set related_orders = (select ref(x) from po_table x where po_number = 2) + where po_number = 1; +UPDATE po_table + set related_orders = (select ref(x) from po_table x where po_number = 3) + where po_number = 2; +UPDATE po_table + set related_orders = (select ref(x) from po_table x where po_number = 1) + where po_number = 3; + +insert into the (select signatories from po_table where po_number = 1) + select ref(x) from person_table x where name='JOHN1'; +insert into the (select signatories from po_table where po_number = 1) + select ref(x) from person_table x where name='MIKE1'; +insert into the (select signatories from po_table where po_number = 1) + select ref(x) from person_table x where name='GREG1'; + +insert into the (select signatories from po_table where po_number = 2) + select ref(x) from person_table x where name='JOHN2'; +insert into the (select signatories from po_table where po_number = 2) + select ref(x) from person_table x where name='MIKE2'; +insert into the (select signatories from po_table where po_number = 2) + select ref(x) from person_table x where name='GREG2'; + +insert into the (select signatories from po_table where po_number = 3) + select ref(x) from person_table x where name='JOHN3'; +insert into the (select signatories from po_table where po_number = 3) + select ref(x) from person_table x where name='MIKE3'; +insert into the (select signatories from po_table where po_number = 3) + select ref(x) from person_table x where name='GREG3'; + +commit; + +set echo off; diff --git a/cdemocor1.c b/cdemocor1.c new file mode 100644 index 0000000..a540485 --- /dev/null +++ b/cdemocor1.c @@ -0,0 +1,645 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemocor1.c 13-sep-2000.21:32:33 emendez Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1995, 2000 Oracle Corporation. All rights reserved. +*/ + +/* + NAME + cdemocor1.c + DESCRIPTION + Demo COR user interface. Run cdemocor.sql bfirst. + + COR is a prefetching mechanism which allows for prefetching + objects related to the root object in one network roundtrip + thereby improving performance. This demo shows how + you can use COR to improve the performance of your application. + Since it may not be easy for you to track the actual network + roundtrips you can turn VERIFY_COR to TRUE which lets you verify that + the pin calls find the prefetched objects in the object cache and + thus do not incur a n/w roundtrip. By setting VERIFY_COR to + TRUE, you modify the data corresponding to the prefetched + objects (in the object cache) in the server. When you access + these prefetched objects on the client side, you get the ones + locally cached in the object cache (and not the new modified + ones in the server). + + MODIFIED (MM/DD/YY) + emendez 09/13/00 - fix top 5 olint errors + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + svedala 07/02/98 - no handlealloc required for define handles + tanguyen 08/19/97 - + echen 06/04/97 - fix warning mesg + echen 05/31/97 - Creation +*/ + +#ifndef CDEMOCOR_ORACLE +#include +#endif + +/* In order to verify that COR works set VERIFY_COR to TRUE. The code enclosed + within the ifdef VERIFY_COR macro acts in the following way. Initially, + we perform a complex object retrieval which should have prefetched the + root object and all objects that the root object contains refs to. The + code guarded by the macro is then executed. This updates the objects that + were prefetched in the server. We then try to pin these objects using the + PIN_ANY option. If COR had worked then the objects should already have + been in the cache and therefore, would not be fetched from the server and + thus should not see the changes made by the code enclosed in the VERIFY_COR + macro */ + +#define VERIFY_COR FALSE + +static const text *const selref = (text *) + "SELECT REF(po) from po_table po where po.po_number = 1"; +static const text *const selall = (text *) + "SELECT REF(po) from po_table po"; +static const text *sch_name_arr[] = {(const text *)0, (const text *)0}; +static ub4 sch_name_len_arr[] = {(ub4)0, (ub4)0}; +static const text *type_name_arr[] = + {(const text *)"PURCHASE_ORDER", (const text *)"CUSTOMER"}; +static ub4 type_name_len_arr[] = {(ub4)14, (ub4)8}; +static const text *version_arr[] = {(const text *)0, (const text *)0}; +static ub4 version_len_arr[] = {(ub4)0, (ub4)0}; + +/****************************************************************************/ +/* checkerr1 - checks and displays errors nested in the error handle */ +void checkerr1(errhp, status, file, line) +OCIError *errhp; +sword status; +const char *file; +int line; +{ + text errbuf[512]; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet ((dvoid *) errhp, (ub4) 1, + (text *) NULL, (sb4 *) &errcode, + errbuf, (ub4) sizeof(errbuf), + (ub4) OCI_HTYPE_ERROR); + (void) printf("Error - %s, file %s, line %d\n", + errbuf, file, line); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + +/* COR demonstration using COR descriptors. COR descriptors contain the + information about what type of refs should be followed to prefetch the + objects pointed to from the root object and the depth level i.e the + objects reachable from the root object by traversing l ( where l <= the + depth level) number of refs */ + +static void demo_cor_1(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIRef *poref = (OCIRef *)0; + OCIIter *itr; + boolean eoc; + purchase_order *po = (purchase_order *)0; + purchase_order *related_po = (purchase_order *)0; + customer *cust = (customer *)0; + OCIDefine *defnp; + OCIComplexObject *corhp, *corhp3; + OCIComplexObjectComp *cordp1, *cordp3; + OCIType *custtdo, *custtdo2; + OCIRef *custref = (OCIRef *)0; + OCIComplexObjectComp *cordp2; + OCIType *po_tdo; + ub4 po_size; + OCIRef *po_ref = (OCIRef *)0; + ub4 level = 0; + ub4 mylevel; + dvoid *tdo_arr[2]; + dvoid *tmp; + sword status = OCI_SUCCESS; + OCIParam *parmp; + int age, po_num; + address *addr = (address *) 0; + sb4 index; + boolean exist; +#ifdef VERIFY_COR + text *stmt11 = (text *) + "update cust_table set name = 'Anil' where name = 'JOHN'"; + text *stmt12 = (text *) + "update cust_table set name = 'Chin' where name = 'MIKE'"; + text *stmt13 = (text *) + "insert into the (select addr from cust_table where name='Anil') \ + select 'ca', '90417', ref(x) from person_table x where name='JOHN2'"; + text *stmt14 = (text *) + "insert into the (select addr from cust_table where name='Chin') \ + select 'ca', '90417', ref(x) from person_table x where name='JOHN2'"; +#endif + + /* select ref to purchase order number 1 */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selref, + (ub4) strlen((const char *) selref), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + /* get type of purchase_order and customer to set in COR descriptor */ + checkerr(errhp, OCITypeArrayByName(envhp, errhp, svchp, 2, + (text **) sch_name_arr, + sch_name_len_arr, (text **) type_name_arr, + type_name_len_arr, (text **) version_arr, + version_len_arr, OCI_DURATION_SESSION, + OCI_TYPEGET_ALL, (OCIType **) tdo_arr)); + po_tdo = (OCIType *)tdo_arr[0]; + custtdo = (OCIType *)tdo_arr[1]; + + /* define purchase order REF (poref) */ + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, + (dvoid *) 0, (sb4) 0, SQLT_REF, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIDefineObject(defnp, errhp, po_tdo, (dvoid **) &poref, + &po_size, (dvoid **) 0, (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, + (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)); + + /*---------------------------- C O R --------------------------------*/ + /* allocate COR Handle */ + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&corhp, + (ub4)OCI_HTYPE_COMPLEXOBJECT, 0, + (dvoid **)0)); + + /*---------------------------- put customer -------------------------*/ + /* allocate COR descriptor for specifying prefetch */ + checkerr(errhp, OCIDescriptorAlloc((dvoid *)envhp, (dvoid **)&cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, 0, + (dvoid **)0)); + + /* specify type of objects to be prefetched; in this case 'customer' */ + checkerr(errhp, OCIAttrSet((dvoid *)cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, (dvoid *)custtdo, + (ub4)sizeof(dvoid *), (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE, + (OCIError *)errhp)); + + /* specify depth level for 'customer' */ + level = 2; + checkerr(errhp, OCIAttrSet((dvoid *)cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, + (dvoid *)&level, (ub4)sizeof(ub4), + (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE_LEVEL, (OCIError *)errhp)); + + /* put COR descriptor in COR handle */ + checkerr(errhp, OCIParamSet(corhp, OCI_HTYPE_COMPLEXOBJECT, errhp, + cordp1, OCI_DTYPE_COMPLEXOBJECTCOMP, 1)); + + + /*------------------------- put purchase_order ------------------------*/ + /* allocate COR descriptor for specifying prefetch */ + checkerr(errhp, OCIDescriptorAlloc((dvoid *)envhp, + (dvoid **)&cordp2, (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, 0, + (dvoid **)0)); + + /* specify type of objects to be prefetched; in this case 'purchase order' */ + checkerr(errhp, OCIAttrSet((dvoid *)cordp2, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, (dvoid *)po_tdo, + (ub4)sizeof(dvoid *), (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE, + (OCIError *)errhp)); + + /* set depth level for purchase order in COR descriptor */ + level = 2; + checkerr(errhp, OCIAttrSet((dvoid *)cordp2, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, (dvoid *)&level, + (ub4)sizeof(ub4), (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE_LEVEL, + (OCIError *)errhp)); + + /* put COR descriptor in COR handle */ + checkerr(errhp, OCIParamSet(corhp, OCI_HTYPE_COMPLEXOBJECT, + errhp, cordp2, OCI_DTYPE_COMPLEXOBJECTCOMP, 2)); + + + /* pin the purchase order - complex object retrieval should take place since + we are passing in the instruction using the cor handle pointer ( corhp) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, poref, corhp, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, (dvoid **)&po)); + + /* convert the purchase order number from OCINumber to int for printing */ + checkerr(errhp, OCINumberToInt(errhp, &po->po_number, sizeof(po_num), + OCI_NUMBER_SIGNED, (dvoid *) &po_num)); + (void) printf(" The po number is %d\n", po_num); + +#ifdef VERIFY_COR + /* Modify the data in the server */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt11, + (ub4) strlen((const char *) stmt11), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt12, + (ub4) strlen((const char *) stmt12), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt13, + (ub4) strlen((const char *) stmt13), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt14, + (ub4) strlen((const char *) stmt14), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +#endif + + /* pin the customer (shouldn't go over the n/w since we did cor) */ + /* you should see MIKE and JOHN and should not see newly inserted records + if VERIFY_COR was set to true */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->cust, (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + + /* get the first element of the collection and print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + /* keep getting the indices of the elements and the elements themselves */ + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* get the next element and print it out */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + /* now repeat the process of getting the related purchase orders and printing + them out */ + /* pin the related purchase_order (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->related_orders, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&related_po)); + + /* pin the customer (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, related_po->cust, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + /* We do not need anything in the cache anymore, so free the cache. This + will unpin and free all objects */ + checkerr(errhp, OCICacheFree(envhp, errhp, svchp)); + + /* free COR descriptor and COR handle */ + checkerr(errhp, OCIDescriptorFree((dvoid *)cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP)); + checkerr(errhp, OCIDescriptorFree((dvoid *)cordp2, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP)); + checkerr(errhp, OCIHandleFree((dvoid *)corhp, + (ub4)OCI_HTYPE_COMPLEXOBJECT)); +} + +/* COR demonstration that sets the collection out of line parameter in the + COR descriptor to indicate that the collection need not be brought in its + entirety but only a locator is brought in. The collection can be brought + in on demand later on using the locator. */ + +static void demo_cor_3(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIType *po_tdo; + ub4 po_size; + OCIRef *poref = (OCIRef *)0; + purchase_order *po = (purchase_order *)0; + purchase_order *related_po = (purchase_order *)0; + customer *cust = (customer *)0; + OCIDefine *defnp; + OCIComplexObject *corhp; + ub1 outofline = TRUE; + dvoid *tmp; + sword status = OCI_SUCCESS; + dvoid *elem = (dvoid *)0; + dvoid *elemind = (dvoid *)0; + sb4 collsiz; + boolean exist; + address *addr = (address *) 0; + null_address *null_addr = (null_address *) 0; + sb4 index = 0, counter = 0; + OCIDescribe *dschp = (OCIDescribe *) 0; + OCIParam *parmp; + OCIRef *type_ref = (OCIRef *) 0; + +#ifdef VERIFY_COR + text *stmt11 = (text *) + "update cust_table set name = 'Anil' where name = 'JOHN'"; + text *stmt12 = (text *) + "update cust_table set name = 'Chin' where name = 'MIKE'"; + text *stmt13 = (text *) + "insert into the (select addr from cust_table where name='Anil') \ + select NULL, '90419', ref(x) from person_table x where name='MIKE1'"; + text *stmt14 = (text *) + "insert into the (select addr from cust_table where name='Chin') \ + select NULL, '90419', ref(x) from person_table x where name='MIKE1'"; +#endif + + /*-------------------------- get po ref -----------------------------*/ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selref, + (ub4) strlen((const char *) selref), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, (dvoid *) 0, + (sb4) 0, SQLT_REF, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + checkerr(errhp, OCIDescribeAny(svchp, errhp, (text *)"PURCHASE_ORDER", + (ub4) strlen("PURCHASE_ORDER"), OCI_OTYPE_NAME, (ub1)1, + (ub1) OCI_PTYPE_TYPE, dschp)); + + checkerr(errhp, OCIAttrGet((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, errhp)); + + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &type_ref, (ub4 *) 0, + (ub4) OCI_ATTR_REF_TDO, (OCIError *) errhp)); + + /* get type of purchase_order to set in COR descriptor */ + checkerr(errhp, OCIObjectPin(envhp, errhp, type_ref, (OCIComplexObject *) 0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&po_tdo)); + + checkerr(errhp, OCIDefineObject(defnp, errhp, po_tdo, + (dvoid **) &poref, &po_size, (dvoid **) 0, + (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, + (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)); + + /*---------------------------- C O R --------------------------------*/ + /* get COR Handle */ + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&corhp, + (ub4)OCI_HTYPE_COMPLEXOBJECT, 0, + (dvoid **)0)); + + /* pin the purchase order - no COR done here */ + checkerr(errhp, OCIObjectPin(envhp, errhp, poref, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, (dvoid **)&po)); + + /* By default collections are brought in along with the containing object + (inline). By setting the attribute OCI_ATTR_COMPLEXOBJECT_COLL_OUTOFLINE + to TRUE we indicate that we do not want it to be fetched along with the + containing object, but will fetch it separately on demand (out-of-line) */ + + checkerr(errhp, OCIAttrSet((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *)&outofline, (ub4)sizeof(ub1), + (ub4)OCI_ATTR_COMPLEXOBJECT_COLL_OUTOFLINE, + (OCIError *)errhp)); + + /* pin the customer (should go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->cust, corhp, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + +#ifdef VERIFY_COR + /* Modify the data */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt11, + (ub4) strlen((const char *) stmt11), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt12, + (ub4) strlen((const char *) stmt12), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + /* add new records */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt13, + (ub4) strlen((const char *) stmt13), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt14, + (ub4) strlen((const char *) stmt14), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +#endif + + /* should see the new records */ + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &elem, &elemind)); + addr = (address *)elem; + null_addr = (null_address *)elemind; + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + (void) printf(" atomic null indicator is %d\n", null_addr->null_address); + (void) printf(" zip null indicator is %d\n", null_addr->null_zip); + (void) printf(" state null indicator is %d\n", null_addr->null_state); + + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &elem, &elemind)); + addr = (address *)elem; + null_addr = (null_address *)elemind; + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + (void) printf(" atomic null indicator is %d\n", + null_addr->null_address); + (void) printf(" zip null indicator is %d\n", null_addr->null_zip); + (void) printf(" state null indicator is %d\n", null_addr->null_state); + } + + checkerr(errhp, OCICacheFree(envhp, errhp, svchp)); + + /* free COR handle */ + checkerr(errhp, OCIHandleFree((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT)); +} + +int main(int argc, char *argv[]) +{ + OCIEnv *envhp; + OCISvcCtx *svchp; + OCIError *errhp; + OCIServer *srvhp; + OCISession *usrhp; + OCIStmt *stmthp; + sword status = OCI_SUCCESS; + dvoid *tmp = (dvoid *) 0; + + (void) OCIInitialize((ub4) OCI_OBJECT | OCI_DEFAULT, + (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)()) 0, (void (*)()) 0 ); + + (void) OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp)); + + checkerr(errhp, OCIServerAttach( srvhp, errhp, (text *) "", + (sb4) strlen(""), (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp)); + + /* set attribute server context in the service context */ + checkerr(errhp, OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp)); + + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, + (ub4)OCI_HTYPE_SESSION, 0, (dvoid **)0)); + + checkerr(errhp, OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"cdemocor", (ub4)strlen("cdemocor"), + (ub4)OCI_ATTR_USERNAME, errhp)); + + checkerr(errhp, OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"cdemocor", (ub4)strlen("cdemocor"), + (ub4)OCI_ATTR_PASSWORD, errhp)); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, + (ub4)OCI_ATTR_SESSION, errhp)); + + /*-------------------------- get po ref -----------------------------*/ + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, 50, + (dvoid **) &tmp)); + + (void) printf("Complex object retrieval demo # 1\n"); + (void) printf(" --> Set level in COR descriptor\n"); + demo_cor_1(envhp, svchp, stmthp, errhp); + demo_cor_3(envhp, svchp, stmthp, errhp); + + OCIDescriptorFree((dvoid *)envhp, (ub4)OCI_HTYPE_ENV); + +} + diff --git a/cdemocp.c b/cdemocp.c new file mode 100644 index 0000000..4cd1c21 --- /dev/null +++ b/cdemocp.c @@ -0,0 +1,397 @@ +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. */ +/* + + NAME + cdemocp.c - Basic OCI Connection Pooling functionality + + DESCRIPTION + + This demo invokes multiple threads to insert MAXTHREAD records + into hr.employees table and displays all the inserted records. + + Before running the demo, Please.. + - run rdbms/demo/cdemocp.sql to create pool users. + - make sure that the common schemas are installed. This can + be verified by connecting to hr/hr. If not installed, + please refer to the common schema documentation. + + DMLs on the following columns of hr.employees is done. + If the table structure changes in releases beyond 10iR1, the + demo *may* need to be changed accordingly. + + Name Null? Type + ----------------------------------------- -------- ------------ + EMPLOYEE_ID NOT NULL NUMBER(6) + LAST_NAME NOT NULL VARCHAR2(25) + SALARY NUMBER(8,2) + DEPARTMENT_ID NOT NULL VARCHAR2(10) + JOB_ID NOT NULL VARCHAR2(10) + EMAIL NOT NULL VARCHAR2(25) + HIRE_DATE NOT NULL DATE + + MODIFIED (MM/DD/YY) + msowdaga 04/30/08 - Fix bug 6236196, multiple threads should not share + single error handle + azhao 10/10/06 - case-senstive password change + arrajara 08/07/02 - Move to common schema (scott->hr) and cleanup + jchai 01/28/02 - Merged jchai_change_oci_sp_sc_cp_names + kmohan 04/23/01 - Merged kmohan_cpdemo + mpurayat 04/20/01 - Creation + +*/ + +#include +#include +#include +#include + + +/* Maximum number of threads */ +#define MAXTHREAD 10 +/* Number of columns in select list */ +#define MAXBINDS 7 + +static OCIError *errhp; +static OCIEnv *envhp; +static OCICPool *poolhp; +static OraText *poolName; +static sb4 poolNameLen; + +static int employeeNum[MAXTHREAD]; + +static CONST OraText *database = (OraText *)""; +static CONST OraText *username = (OraText *)"HR"; +static CONST OraText *password = (OraText *)"hr"; +static CONST OraText *appusername = (OraText *)"APPUSER"; +static CONST OraText *apppassword = (OraText *)"apppassword"; + +/* Values to be inserted into employees table */ +static char ename[MAXTHREAD][26]= + {"LASTNAME1","LASTNAME2","LASTNAME3","LASTNAME4","LASTNAME5", + "LASTNAME6","LASTNAME7","LASTNAME8","LASTNAME9","LASTNAME10"}; + +static char ejob[MAXTHREAD][11]= + {"AD_PRES", "AD_VP", "AD_ASST", "FI_MGR", "FI_ACCOUNT", + "AC_MGR", "AC_ACCOUNT", "SA_MAN", "SA_REP", "PU_MAN"}; + +static float esal[MAXTHREAD]={1000.00, 2000.00, 3000.00, 4000.00, 5000.00, + 6000.00, 7000.00, 8000.00, 9000.00, 10000.00}; +static unsigned int edept[MAXTHREAD] = {10,20,10,20,30,10,30,20,10,20}; + +static char email[MAXTHREAD][25]= + {"name1@oracle.com", "name2@oracle.com", "name3@oracle.com", + "name4@oracle.com", "name5@oracle.com", "name6@oracle.com", + "name7@oracle.com", "name8@oracle.com", "name9@oracle.com", + "name10@oracle.com"}; + +static char hdate[MAXTHREAD][10]= + {"21-DEC-01", "22-DEC-01", "23-DEC-01", "24-DEC-01", "25-DEC-01", + "26-DEC-01", "27-DEC-01", "28-DEC-01", "29-DEC-01", "30-DEC-01"}; + +/* Max, min and increment connections */ +static ub4 conMin = 1; +static ub4 conMax = 3; +static ub4 conIncr = 1; + +/* Local functions */ +static void checkerr (OCIError *errhp, sword status); +static void threadFunction (dvoid *arg); +static void queryRows(); +static void deleteRows(); +int main(); + +/*- main -------------------------------------------------------------------*/ +int main() +{ + int i = 0; + sword lstat; + + OCIEnvCreate (&envhp, OCI_THREADED | OCI_OBJECT, (dvoid *)0, NULL, + NULL, NULL, 0, (dvoid *)0); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &poolhp, OCI_HTYPE_CPOOL, + (size_t) 0, (dvoid **) 0); + + /* CREATE THE CONNECTION POOL */ + if (lstat = OCIConnectionPoolCreate(envhp, + errhp,poolhp, &poolName, &poolNameLen, + database,(sb4)strlen((const signed char *)database), + conMin, conMax, conIncr, + appusername,(sb4)strlen((const signed char *)appusername), + apppassword,(sb4)strlen((const signed char *)apppassword) + ,OCI_DEFAULT)) + { + checkerr(errhp,lstat); + exit(1); + } + + /* Delete rows that are already inserted by this demo */ + deleteRows(); + + /* Multiple threads using the connection pool */ + { + OCIThreadId *thrid[MAXTHREAD]; + OCIThreadHandle *thrhp[MAXTHREAD]; + + OCIThreadProcessInit (); + checkerr (errhp, OCIThreadInit (envhp, errhp)); + for (i = 0; i < MAXTHREAD; ++i) + { + checkerr (errhp, OCIThreadIdInit (envhp, errhp, &thrid[i])); + checkerr (errhp, OCIThreadHndInit (envhp, errhp, &thrhp[i])); + } + printf("Multiple threads inserting rows into employees table\n"); + for (i = 0; i < MAXTHREAD; ++i) + { + employeeNum[i]=i; + /* Insert into hr.employees table */ + checkerr (errhp, OCIThreadCreate (envhp, errhp, threadFunction, + (dvoid *) &employeeNum[i], thrid[i], thrhp[i])); + } + for (i = 0; i < MAXTHREAD; ++i) + { + checkerr (errhp, OCIThreadJoin (envhp, errhp, thrhp[i])); + checkerr (errhp, OCIThreadClose (envhp, errhp, thrhp[i])); + checkerr (errhp, OCIThreadIdDestroy (envhp, errhp, &(thrid[i]))); + checkerr (errhp, OCIThreadHndDestroy (envhp, errhp, &(thrhp[i]))); + } + checkerr (errhp, OCIThreadTerm (envhp, errhp)); + } /* ALL THE THREADS ARE COMPLETE */ + + /* Display inserted rows */ + queryRows(); + + checkerr(errhp, OCIConnectionPoolDestroy(poolhp, errhp, OCI_DEFAULT)); + checkerr(errhp, OCIHandleFree((dvoid *)poolhp, OCI_HTYPE_CPOOL)); + checkerr(errhp, OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR)); + return 0; +} +/* - end of main -----------------------------------------------------------*/ + + +/* - Insert records into employees table -----------------------------------*/ +static void threadFunction (dvoid *arg) +{ + OCISvcCtx *svchp = (OCISvcCtx *) 0; + OCIStmt *stmthp = (OCIStmt *)0; + OCIError *errhp2 = (OCIError *) 0; + int empno = *(int *)arg; + sword lstat = 0; + text insertst1[256]; + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp2, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + if (lstat = OCILogon2(envhp, errhp2, &svchp, + (CONST OraText *)username, (ub4)strlen((const signed char *)username), + (CONST OraText *)password, (ub4)strlen((const signed char *)password), + (CONST OraText *)poolName, (ub4)poolNameLen, + OCI_CPOOL)) + { + checkerr(errhp2,lstat); + exit(1); + } + (void) sprintf(insertst1, + "INSERT INTO hr.employees(employee_id, last_name, job_id, salary, \ + department_id, email, hire_date) \ + VALUES (%d,'%s','%s',%7.2f,%d,'%s','%s')", + empno+1,ename[empno],ejob[empno], + esal[empno],edept[empno], email[empno], hdate[empno]); + + printf("Inserting details of %s\n",ename[empno]); + + OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + checkerr(errhp2, OCIStmtPrepare (stmthp, errhp2, (CONST OraText *)insertst1, + (ub4)strlen((const signed char *)insertst1), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + checkerr(errhp2, OCIStmtExecute (svchp, stmthp, errhp2, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT )); + + checkerr(errhp2, OCITransCommit(svchp,errhp2,(ub4)0)); + + checkerr(errhp2, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + checkerr(errhp2, OCILogoff((dvoid *) svchp, errhp2)); + OCIHandleFree((dvoid *)errhp2, OCI_HTYPE_ERROR); +} +/*- end of threadFunction --------------------------------------------------*/ + + +/* Delete rows which are inserted in the previous invocation of this demo --*/ +static void deleteRows() +{ + OCISvcCtx *svchp = (OCISvcCtx *) 0; + sword status = 0; + text deletest1[256]; + sword lstat; + OCIStmt *stmthp = (OCIStmt *)0; + if (lstat = OCILogon2(envhp, errhp, &svchp, + (CONST OraText *)username, (ub4)strlen((const signed char *)username), + (CONST OraText *)password, (ub4)strlen((const signed char *)password), + (CONST OraText *)poolName, (ub4)poolNameLen, + OCI_CPOOL)) + { + checkerr(errhp,lstat); + exit(1); + } + (void) sprintf(deletest1, + "DELETE FROM hr.employees WHERE employee_id BETWEEN 1 AND %d",MAXTHREAD); + OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + checkerr(errhp, OCIStmtPrepare (stmthp, errhp, (text *)deletest1, + (ub4)strlen((const signed char *)deletest1), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT )); + checkerr(errhp, OCITransCommit(svchp,errhp,(ub4)0)); + + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + checkerr(errhp, OCILogoff((dvoid *) svchp, errhp)); + printf("Deleted all rows between 1 and %d\n", MAXTHREAD); + +} +/*- end of deleteRows ------------------------------------------------------*/ + + +/*- Display the contents of hr.employees table -----------------------------*/ +#define DBUFLEN 20 +static void queryRows() +{ + OCISvcCtx *svchp = (OCISvcCtx *) 0; + OCIStmt *stmthp = (OCIStmt *)0; + OCIDefine *defhp[MAXBINDS]; + OCIDate emp_hdate; + sword status = 0; + sword lstat = 0; + text selectst1[256]; + text emp_name[26]; + text emp_job[11]; + text emp_email[26]; + text datebuf[DBUFLEN]; + ub4 emp_no = 0; + ub4 emp_dept = 0; + ub4 datebuflen = DBUFLEN; + float emp_sal = 0.0; + int i = 0; + + /* Logon in Connection Pool mode */ + if (lstat = OCILogon2(envhp, errhp, &svchp, + (CONST OraText *)username, (ub4)strlen((const signed char *)username), + (CONST OraText *)password, (ub4)strlen((const signed char *)password), + (CONST OraText *)poolName, (ub4)poolNameLen, + OCI_CPOOL)) + { + checkerr(errhp,lstat); + exit(1); + } + + (void) sprintf(selectst1, + "SELECT employee_id, last_name, job_id, salary, department_id, \ + email, hire_date \ + FROM hr.employees WHERE employee_id between 1 and %d",MAXTHREAD); + + OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + checkerr(errhp, OCIStmtPrepare (stmthp, errhp, (text *)selectst1, + (ub4)strlen((const signed char *)selectst1), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp[0], errhp, (ub4)1, + (dvoid *)&emp_no, (sb4)sizeof(ub4), (ub2)SQLT_INT, (dvoid *)0, + (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp[1], errhp, (ub4)2, + (dvoid *)&emp_name, (sb4)sizeof(emp_name), (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp[2], errhp, (ub4)3, + (dvoid *)&emp_job, (sb4)sizeof(emp_job), (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp[3], errhp, (ub4)4, + (dvoid *)&emp_sal,(sb4)sizeof(float),(ub2)SQLT_FLT,(dvoid *)0, + (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp[4], errhp, (ub4)5, + (dvoid *)&emp_dept,(sb4)sizeof(ub4),(ub2)SQLT_INT,(dvoid *)0, + (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp[5], errhp, (ub4)6, + (dvoid *)&emp_email,(sb4)sizeof(emp_email),(ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp[6], errhp, (ub4)7, + (dvoid *)&emp_hdate,(sb4)sizeof(emp_hdate),(ub2)SQLT_ODT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + + /* Execute the Query and Fetch MAXTHREAD records */ + if (lstat = OCIStmtExecute (svchp, stmthp, errhp, (ub4)0, + (ub4)0, (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT )) + { + checkerr(errhp,lstat); + exit(1); + } + /* Printing the values */ + + printf("Displaying the inserted records\n"); + status = OCIStmtFetch(stmthp,errhp,1,OCI_FETCH_NEXT,OCI_DEFAULT); + while (status != OCI_NO_DATA) + { + /* Convert OCIDate into text format for printing */ + lstat = OCIDateToText(errhp, &emp_hdate, (text *)0, (ub1)0, + (text*)"American", (ub4)8, &datebuflen, datebuf); + if (lstat) + checkerr(errhp, lstat); + printf( + "Empno:%u Name:%s Job:%s Sal:%7.2f Deptno:%u Email:%s Hiredate:%s\n", + emp_no,emp_name,emp_job,emp_sal,emp_dept, emp_email, datebuf); + status = OCIStmtFetch(stmthp,errhp,1,OCI_FETCH_NEXT,OCI_DEFAULT); + } + + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + checkerr(errhp, OCILogoff((dvoid *) svchp, errhp)); +} +/*- end of queryRows --------------------------------------------------------*/ +#undef DBUFLEN + + +/* Handle oci error ---------------------------------------------------------*/ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} +/* end of demo -------------------------------------------------------------*/ diff --git a/cdemocp.sql b/cdemocp.sql new file mode 100644 index 0000000..42e8a9f --- /dev/null +++ b/cdemocp.sql @@ -0,0 +1,4 @@ +SET SERVEROUTPUT ON +CONNECT system/manager +CREATE USER appuser identified by apppassword; +GRANT CONNECT,RESOURCE,CREATE ANY DIRECTORY,DROP ANY DIRECTORY TO appuser; diff --git a/cdemocpproxy.c b/cdemocpproxy.c new file mode 100644 index 0000000..8f5d7d1 --- /dev/null +++ b/cdemocpproxy.c @@ -0,0 +1,332 @@ +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. */ +/* + + NAME + cdemocpproxy.c - OCI Connection Pooling, proxy functionality + + DESCRIPTION + + This program invokes multiple threads to insert MAXTHREAD records + into EMP table and displays all the inserted records. + + For proxy login we should alter the user permission as the following + ALTER USER scott GRANT CONNECT THROUGH appuser; + + This demo needs the cdemocpproxy.sql file for creating Pool user. + Before running this demo the cdemocpproxy.sql should be executed. + + MODIFIED (MM/DD/YY) + msowdaga 04/30/08 - Fix bug 6236196, multiple threads should not share + single error handle + azhao 10/10/06 - case-senstive password change + jchai 01/28/02 - Merged jchai_change_oci_sp_sc_cp_names + kmohan 04/23/01 - Merged kmohan_cpdemo + mpurayat 04/20/01 - Creation + +*/ + +#include +#include +#include +#include +/* Maximum Number of threads */ +#define MAXTHREAD 10 + +static OCIError *errhp; +static OCIEnv *envhp; +static OCICPool *poolhp; + +static int employeeNum[MAXTHREAD]; + +static OraText *poolName; +static sb4 poolNameLen; +static CONST OraText *database = (OraText *)""; +static CONST OraText *username =(OraText *)"SCOTT"; +static CONST OraText *password =(OraText *)""; /* no password needed for proxy*/ +static CONST OraText *appusername =(OraText *)"APPUSER"; +static CONST OraText *apppassword =(OraText *)"apppassword"; + +/* Values to be inserted into EMP table */ +static char ename[MAXTHREAD][10]={"JOHN","JIMMY","JET","JIM","JEFREE","JAMES", + "JAMMEE","JOSEP","JOHNY","JEGAN"}; +static char ejob[MAXTHREAD][9]={"MANAGER","TYPIST","ASST MGR","CLERK","MANAGER", + "ASST MGR","CLERK","CLERK","TYPIST","TYPIST"}; +static float esal[MAXTHREAD]={10000.00 + ,5000.00 + ,8000.00 + ,6000.00 + ,10000.00 + ,8000.00 + ,6000.00 + ,6000.00 + ,5000.00 + ,5000.00}; +static unsigned int edept[MAXTHREAD] = {10,20,10,20,30,10,30,20,10,20}; + +/* Max,Min, and increment connections */ +static ub4 conMin = 1; +static ub4 conMax = 3; +static ub4 conIncr = 1; + +static void checkerr (OCIError *errhp, sword status); +static void threadFunction (dvoid *arg); +static void queryRows(); +static void deleteRows(); + +int main(argc, argv) +int argc; +char *argv[]; +{ + int i = 0; + sword lstat; + OCIEnvCreate (&envhp, OCI_THREADED, (dvoid *)0, NULL, + NULL, NULL, 0, (dvoid *)0); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &poolhp, OCI_HTYPE_CPOOL, + (size_t) 0, (dvoid **) 0); + + /* CREATE THE CONNECTION POOL */ + if (lstat = OCIConnectionPoolCreate(envhp, + errhp,poolhp, &poolName, &poolNameLen, + database,(sb4)strlen((const signed char *)database), + conMin, conMax, conIncr, + appusername,(sb4)strlen((const signed char *)appusername), + apppassword,(sb4)strlen((const signed char *)apppassword) + ,OCI_DEFAULT)) + { + checkerr(errhp,lstat); + exit(1); + } + /* Delete Inserted rows by this demo previously */ + deleteRows(); + /* Multiple threads using the connection pool */ + { + OCIThreadId *thrid[MAXTHREAD]; + OCIThreadHandle *thrhp[MAXTHREAD]; + + OCIThreadProcessInit (); + checkerr (errhp, OCIThreadInit (envhp, errhp)); + for (i = 0; i < MAXTHREAD; ++i) + { + checkerr (errhp, OCIThreadIdInit (envhp, errhp, &thrid[i])); + checkerr (errhp, OCIThreadHndInit (envhp, errhp, &thrhp[i])); + } + printf("Multiple threads inserting records into EMP table\n"); + for (i = 0; i < MAXTHREAD; ++i) + { + employeeNum[i]=i; + /* Inserting into EMP table */ + checkerr (errhp, OCIThreadCreate (envhp, errhp, threadFunction, + (dvoid *) &employeeNum[i], thrid[i], thrhp[i])); + } + for (i = 0; i < MAXTHREAD; ++i) + { + checkerr (errhp, OCIThreadJoin (envhp, errhp, thrhp[i])); + checkerr (errhp, OCIThreadClose (envhp, errhp, thrhp[i])); + checkerr (errhp, OCIThreadIdDestroy (envhp, errhp, &(thrid[i]))); + checkerr (errhp, OCIThreadHndDestroy (envhp, errhp, &(thrhp[i]))); + } + checkerr (errhp, OCIThreadTerm (envhp, errhp)); + } /* ALL THE THREADS ARE COMPLETE */ + /* This function will select and display all the rows from EMP table */ + printf("Displaying the Inserted records\n"); + queryRows(); + checkerr(errhp, OCIConnectionPoolDestroy(poolhp, errhp, OCI_DEFAULT)); + checkerr(errhp, OCIHandleFree((dvoid *)poolhp, OCI_HTYPE_CPOOL)); + checkerr(errhp, OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR)); + return 0; +} /* end of main () */ + +/* Inserts records into EMP table */ +static void threadFunction (dvoid *arg) +{ + int empno = *(int *)arg; + OCISvcCtx *svchp = (OCISvcCtx *) 0; + text insertst1[256]; + OCIStmt *stmthp = (OCIStmt *)0; + OCIError *errhp2 = (OCIError *) 0; + sword lstat; + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp2, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + if (lstat = OCILogon2(envhp, errhp2, &svchp, + (CONST OraText *)username, (ub4)strlen((const signed char *)username), + (CONST OraText *)password, (ub4)strlen((const signed char *)password), + (CONST OraText *)poolName, (ub4)poolNameLen, + OCI_CPOOL)) + { + checkerr(errhp2,lstat); + exit(1); + } + (void) sprintf(insertst1,"INSERT INTO emp(empno, ename, job, sal, deptno) \ + values (%d,'%s','%s',%7.2f,%d)",empno+1,ename[empno],ejob[empno], + esal[empno],edept[empno]); + + printf("Inserting %s\n",ename[empno]); + + OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + checkerr(errhp2, OCIStmtPrepare (stmthp, errhp2, (CONST OraText *)insertst1, + (ub4)strlen((const signed char *)insertst1), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + checkerr(errhp2, OCIStmtExecute (svchp, stmthp, errhp2, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT )); + + checkerr(errhp2, OCITransCommit(svchp,errhp2,(ub4)0)); + + checkerr(errhp2, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + checkerr(errhp2, OCILogoff((dvoid *) svchp, errhp2)); + OCIHandleFree((dvoid *)errhp2, OCI_HTYPE_ERROR); +} /* end of threadFunction (dvoid *) */ +/* Delete rows which are inserted in the prvious invocation of this demo*/ +static void deleteRows() +{ + OCISvcCtx *svchp = (OCISvcCtx *) 0; + sword status = 0; + text deletest1[256]; + sword lstat; + OCIStmt *stmthp = (OCIStmt *)0; + if (lstat = OCILogon2(envhp, errhp, &svchp, + (CONST OraText *)username, (ub4)strlen((const signed char *)username), + (CONST OraText *)password, (ub4)strlen((const signed char *)password), + (CONST OraText *)poolName, (ub4)poolNameLen, + OCI_CPOOL)) + { + checkerr(errhp,lstat); + exit(1); + } + (void) sprintf(deletest1, + "DELETE FROM emp WHERE empno BETWEEN 1 AND %d",MAXTHREAD); + OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + checkerr(errhp, OCIStmtPrepare (stmthp, errhp, (text *)deletest1, + (ub4)strlen((const signed char *)deletest1), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT )); + checkerr(errhp, OCITransCommit(svchp,errhp,(ub4)0)); + + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + checkerr(errhp, OCILogoff((dvoid *) svchp, errhp)); +} /* End of deleteRows */ + +/* Displays the contents of EMP table */ +static void queryRows() +{ + OCISvcCtx *svchp = (OCISvcCtx *) 0; + sword status = 0; + text selectst1[256]; + OCIStmt *stmthp = (OCIStmt *)0; + sword lstat; + /* Define all output variables */ + OCIDefine *defhp1 = (OCIDefine *)0; + OCIDefine *defhp2 = (OCIDefine *)0; + OCIDefine *defhp3 = (OCIDefine *)0; + OCIDefine *defhp4 = (OCIDefine *)0; + OCIDefine *defhp5 = (OCIDefine *)0; + ub4 emp_no,emp_dept; + text emp_name[10],emp_job[9]; + int i; + float emp_sal; + /* Logon in Connection Pool mode */ + if (lstat = OCILogon2(envhp, errhp, &svchp, + (CONST OraText *)username, (ub4)strlen((const signed char *)username), + (CONST OraText *)password, (ub4)strlen((const signed char *)password), + (CONST OraText *)poolName, (ub4)poolNameLen, + OCI_CPOOL)) + { + checkerr(errhp,lstat); + exit(1); + } + + (void) sprintf(selectst1,"SELECT empno, ename, job, sal, deptno FROM emp\ + WHERE empno between 1 and %d",MAXTHREAD); + + OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + checkerr(errhp, OCIStmtPrepare (stmthp, errhp, (text *)selectst1, + (ub4)strlen((const signed char *)selectst1), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp1, errhp, (ub4)1, + (dvoid *)&emp_no, (sb4)sizeof(ub4), (ub2)SQLT_INT, (dvoid *)0, + (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp2, errhp, (ub4)2, + (dvoid *)&emp_name, (sb4)10, (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp3, errhp, (ub4)3, + (dvoid *)&emp_job, (sb4)9, (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp4, errhp, (ub4)4, + (dvoid *)&emp_sal,(sb4)sizeof(float),(ub2)SQLT_FLT,(dvoid *)0, + (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp5, errhp, (ub4)5, + (dvoid *)&emp_dept,(sb4)sizeof(ub4),(ub2)SQLT_INT,(dvoid *)0, + (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + + /* Execute the Query and Fetch MAXTHREAD records */ + if (lstat = OCIStmtExecute (svchp, stmthp, errhp, (ub4)0, + (ub4)0, (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT )) + { + checkerr(errhp,lstat); + exit(1); + } + /* Printing the values */ + status = OCIStmtFetch(stmthp,errhp,1,OCI_FETCH_NEXT,OCI_DEFAULT); + while (status != OCI_NO_DATA) + { + printf("Emp No : %u Name : %s Job : %s Salary : %7.2f Dept No : %u\n", + emp_no,emp_name,emp_job,emp_sal,emp_dept); + status = OCIStmtFetch(stmthp,errhp,1,OCI_FETCH_NEXT,OCI_DEFAULT); + } + + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + checkerr(errhp, OCILogoff((dvoid *) svchp, errhp)); +} /* end of queryRows() */ + +/* This function prints the error */ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} diff --git a/cdemocpproxy.sql b/cdemocpproxy.sql new file mode 100644 index 0000000..003030b --- /dev/null +++ b/cdemocpproxy.sql @@ -0,0 +1,5 @@ +SET SERVEROUTPUT ON +CONNECT system/manager +CREATE USER appuser identified by apppassword; +GRANT CONNECT,RESOURCE,CREATE ANY DIRECTORY,DROP ANY DIRECTORY TO appuser; +ALTER USER scott GRANT CONNECT THROUGH appuser; diff --git a/cdemodp.c b/cdemodp.c new file mode 100644 index 0000000..6af78a9 --- /dev/null +++ b/cdemodp.c @@ -0,0 +1,2887 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodp.c 28-feb-2005.11:23:54 eegolf Exp $ "; +#endif /* RCSID */ + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* Copyright (c) 1998, 2005, Oracle. All rights reserved. */ +/* */ +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* +** NAME: +** cdemodp.c - C Demo program for Direct Path api +** +** +** DESCRIPTION: +** - Direct Path Api driver program to demonstrate loading. +** +** NOTES: +** Demonstrates usage of the direct path API. +** +** -- cdemodp.c -- +** This is one of two C files needed to create a demo that loads +** data through direct path api. +** +** To build and run the demo, please read directions located in +** the header section of the cdemdp*.c modules. +** +** +** +** MODIFIED (MM/DD/YY) +** eegolf 02/28/05 - Conditionalize for OpenVMS +** eegolf 03/30/04 - Update simple_load routine to tkpidrv.c version +** rphillip 03/12/04 - Delete flush row and always load after cvt error +** cmlim 06/11/02 - do not core dump if a null tbl name is given +** msakayed 11/02/01 - Bug #2094292: add/set OCI_ATTR_DIRPATH_INPUT +** eegolf 03/04/01 - Updated for 9i +** cmlim 09/16/98 - Creation (abrumm 04/07/98) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef VMS +#include +#endif + +#ifndef bit +# define bit(x, y) ((x) & (y)) +#endif + +#ifndef OER +# define OER(x) (x) +#endif + +struct loadctl +{ + ub4 nrow_ctl; /* number of rows in column array */ + ub2 ncol_ctl; /* number of columns in column array */ + OCIEnv *envhp_ctl; /* environment handle */ + OCIServer *srvhp_ctl; /* server handle */ + OCIError *errhp_ctl; /* error handle */ + OCIError *errhp2_ctl; /* yet another error handle */ + OCISvcCtx *svchp_ctl; /* service context */ + OCISession *authp_ctl; /* authentication context */ + OCIParam *colLstDesc_ctl; /* column list parameter handle */ + OCIDirPathCtx *dpctx_ctl; /* direct path context */ + OCIDirPathColArray *dpca_ctl; /* direct path column array handle */ + OCIDirPathColArray *dpobjca_ctl; /* dp column array handle for obj*/ + OCIDirPathColArray *dpnestedobjca_ctl; /* dp col array hndl for nested obj*/ + OCIDirPathStream *dpstr_ctl; /* direct path stream handle */ + ub1 *buf_ctl; /* pre-alloc'd buffer for out-of-line data */ + ub4 bufsz_ctl; /* size of buf_ctl in bytes */ + ub4 bufoff_ctl; /* offset into buf_ctl */ + ub4 *otor_ctl; /* Offset to Recnum mapping */ + ub1 *inbuf_ctl; /* buffer for input records */ + struct pctx pctx_ctl; /* partial field context */ + boolean loadobjcol_ctl; /* load to obj col(s)? T/F */ +}; + +/* Forward references: */ + +STATICF void field_flush(/*_ struct loadctl *ctlp, ub4 rowoff _*/); + +STATICF sword field_set(/*_ struct loadctl *ctlp, struct tbl *tblp, + struct obj *objp, text *recp, ub4 rowoff, ub1 bufflg _*/); + +STATICF void init_obj_load(/*_ struct loadctl *ctlp, struct tbl *tblp, + struct obj *objp _*/); +STATICF void alloc_obj_ca(/*_ struct loadctl *ctlp, struct tbl *tblp, + struct obj *objp _*/); +STATICF void init_load(/*_ struct loadctl *ctl, struct tbl *table, + struct sess *session _*/); + +STATICF void simple_load(/*_ struct loadctl *ctlp, struct tbl *tblp, + struct sess *session, FILE *inputfp _*/); + +STATICF void finish_load(/*_ struct loadctl *ctl _*/); + +STATICF void errprint(/*_ dvoid *errhp, ub4 htype, sb4 *errcodep _*/); + +STATICF void checkerr(/*_ dvoid *errhp, ub4 htype, sword status, + text *note, sb4 state, text *file, sb4 line _*/); +STATICF void cleanup(/*_ struct loadctl *ctlp, sb4 ex_status _*/); +STATICF sword do_convert(/*_ struct loadctl *ctlp, ub4 startoff, ub4 rowcnt, + ub4 *cvtCntp, ub2 *badcoffp _*/); +STATICF sword do_load(/*_ struct loadctl *ctlp, ub4 *loadCntp _*/); +STATICF int main(/*_ int argc, char *argv[] _*/); +STATICF void free_obj_hndls(struct loadctl *ctlp, struct obj *objp); +STATICF void set_and_get_attributes(struct loadctl *ctlp, struct tbl *tblp); +STATICF void reset_obj_ca(/*_ struct loadctl *ctlp, struct tbl *tblp, struct obj *objp _*/); + + +/* OCI_CHECK(errhp, ub4 errhptype, sb4 status, struct loadctl *ctlp, + * OCIfunction()); + * errhp is typically a (OCIError *), and errhptype is OCI_HTYPE_ERROR. + * errhp in some cases may be an (OCIEnv *), and errhptype is OCI_HTYPE_ENV. + */ +#define OCI_CHECK(errhp, htype, status, ctlp, OCIfunc) \ +if (OCI_SUCCESS != ((status) = (OCIfunc))) \ +{ \ + checkerr((dvoid *)(errhp), (ub4)(htype), (sword)(status), (text *)0, \ + (sb4)0, (text *)__FILE__, (sb4)__LINE__); \ + if ((status) != OCI_SUCCESS_WITH_INFO) \ + cleanup((struct loadctl *)ctlp, (sb4)1); \ +} else + +#define CHECKERR(errhp, htype, status) \ + checkerr((dvoid *)errhp, (ub4)(htype), (sword)(status), (text *)0, \ + (sb4)0, (text *)__FILE__, (sb4)__LINE__); + +#define FATAL(note, state) \ +do \ +{ \ + checkerr((dvoid *)0, (ub4)OCI_HTYPE_ERROR, (sword)OCI_SUCCESS, \ + (text *)(note), (sb4)(state), (text *)__FILE__, (sb4)__LINE__); \ + cleanup((ctlp), (sb4)2); \ +} while (0) + +/* External references: */ +externref struct tbl table; +externref struct sess session; + +/* External definitions: */ +externdef FILE *output_fp; /* for error msgs */ + + + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* main */ +/* */ +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + + +int main(argc, argv) +int argc; +char *argv[]; +{ + sword ociret; + struct loadctl ctl; + struct loadctl *ctlp = &ctl; + + output_fp = (session.outfn_sess) ? fopen((char *)session.outfn_sess, "w") + : stderr; + + memset((dvoid *)ctlp, 0, sizeof(struct loadctl)); + + /* set up OCI environment and connect to the ORACLE server */ + + OCI_CHECK((dvoid *)0, (ub4)0, ociret, ctlp, + OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )); + + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIEnvInit((OCIEnv **)&ctlp->envhp_ctl, OCI_DEFAULT, (size_t)0, + (dvoid **)0)); + + /* allocate error handles */ + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->envhp_ctl, + (dvoid **)&ctlp->errhp_ctl, OCI_HTYPE_ERROR, + (size_t)0, (dvoid **)0)); + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->envhp_ctl, + (dvoid **)&ctlp->errhp2_ctl, OCI_HTYPE_ERROR, + (size_t)0, (dvoid **)0)); + + /* server contexts */ + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->envhp_ctl, + (dvoid **)&ctlp->srvhp_ctl, OCI_HTYPE_SERVER, + (size_t)0, (dvoid **)0)); + + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->envhp_ctl, + (dvoid **)&ctlp->svchp_ctl, OCI_HTYPE_SVCCTX, + (size_t)0, (dvoid **)0)); + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIServerAttach(ctlp->srvhp_ctl, ctlp->errhp_ctl, + session.inst_sess, + (sb4)strlen((const char *)session.inst_sess), + OCI_DEFAULT)); + + /* set attribute server context in the service context */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)ctlp->svchp_ctl, OCI_HTYPE_SVCCTX, + (dvoid *)ctlp->srvhp_ctl, (ub4)0, OCI_ATTR_SERVER, + ctlp->errhp_ctl)); + + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->envhp_ctl, + (dvoid **)&ctlp->authp_ctl, (ub4)OCI_HTYPE_SESSION, + (size_t)0, (dvoid **)0)); + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)ctlp->authp_ctl, (ub4)OCI_HTYPE_SESSION, + (dvoid *)session.username_sess, + (ub4)strlen((char *)session.username_sess), + (ub4)OCI_ATTR_USERNAME, ctlp->errhp_ctl)); + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)ctlp->authp_ctl, (ub4)OCI_HTYPE_SESSION, + (dvoid *)session.password_sess, + (ub4)strlen((char *)session.password_sess), + (ub4)OCI_ATTR_PASSWORD, ctlp->errhp_ctl)); + + /* begin a session */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCISessionBegin(ctlp->svchp_ctl, ctlp->errhp_ctl, ctlp->authp_ctl, + OCI_CRED_RDBMS, (ub4)OCI_DEFAULT)); + + /* set authentication context into service context */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)ctlp->svchp_ctl, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)ctlp->authp_ctl, (ub4)0, (ub4)OCI_ATTR_SESSION, + ctlp->errhp_ctl)); + + init_load(ctlp, &table, &session); /* initialize the load */ + simple_load(ctlp, &table, &session, stdin); /* load data */ + finish_load(ctlp); /* finish the load */ + + cleanup(ctlp, (sb4)0); + /* NOTREACHED */ + +return 1; +} + + +/* +**++++++++++++++++++++++++++++++ alloc_obj_ca +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Function allocates the column arrays for any objects or nested object columns. +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure pointer +** tblp table pointer +** objp object pointer +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void alloc_obj_ca(ctlp, tblp, objp) +struct loadctl *ctlp; /* load control structure pointer */ +struct tbl *tblp; /* table pointer */ +struct obj *objp; /* object pointer */ +{ + struct col *colp; + sword ociret; /* return code from OCI calls*/ + ub2 i; + + /* + * Allocate a separate column array for the column object + */ + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)(objp->ctx_obj), + (dvoid **)&(objp->ca_obj), + (ub4)OCI_HTYPE_DIRPATH_FN_COL_ARRAY, + (size_t)0, (dvoid **)0)); + + /* get number of rows in the column array just allocated */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(objp->ca_obj), + OCI_HTYPE_DIRPATH_FN_COL_ARRAY, + (dvoid *)(&objp->nrows_obj), (ub4 *)0, + OCI_ATTR_NUM_ROWS, ctlp->errhp_ctl)); + + /* get number of columns in the column array just allocated */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(objp->ca_obj), + OCI_HTYPE_DIRPATH_FN_COL_ARRAY, + (dvoid *)(&objp->ncol_obj), (ub4 *)0, + OCI_ATTR_NUM_COLS, ctlp->errhp_ctl)); + + /* + * If there are fewer rows in the object column array than in them top-level, + * one, only use as many rows in the other column array. This will happen + * when the object requires more space than all of the other columns inits + * parent table. This simplifies the loop for loading the column arrays + * so that we only have to worry about when we've filled the top-level + * column array. + */ + if (objp->nrows_obj < ctlp->nrow_ctl) + { + ctlp->nrow_ctl = objp->nrows_obj; + } + + /* check each column to see if it is an object, opaque or ref */ + /* and if so, recurse */ + for (i = 0, colp = objp->col_obj; i < objp->ncol_obj; i++, colp++) + { + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + alloc_obj_ca(ctlp, tblp, colp->obj_col); + } + } + +} + + +/* +**++++++++++++++++++++++++++++++ init_obj_load +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Function which prepares the load of an object column. This should only +** be called from init_load or recursively. +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure pointer +** tblp table pointer +** objp object pointer +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void init_obj_load(ctlp, tblp, objp) +struct loadctl *ctlp; +struct tbl *tblp; +struct obj *objp; +{ + struct col *colp; + struct fld *fldp; + sword ociret; /* return code from OCI calls*/ + ub2 i; + ub4 pos; + ub2 numCols; + ub4 len; + ub2 type; + ub1 exprtype; + ub1 parmtyp; + OCIParam *colDesc; /* column parameter descriptor*/ + OCIParam *objColLstDesc; /* obj col's list param handle*/ + + /* + * create a context for this object type and describe the attributes + * that will be loaded for this object. + */ + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->dpctx_ctl, + (dvoid **)&(objp->ctx_obj), + (ub4)OCI_HTYPE_DIRPATH_FN_CTX, + (size_t)0, (dvoid **)0)); + + /* If col is an obj, then its constructor is the type name. (req.) + * If col is an opaque/sql function, then use the expression given. (req.) + * If col is a ref, then can set a fixed tbl name. (optional) + */ + + if (objp->name_obj) /* if expression is available */ + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(objp->ctx_obj), + (ub4)OCI_HTYPE_DIRPATH_FN_CTX, + (dvoid *) objp->name_obj, + (ub4)strlen((const char *) objp->name_obj), + (ub4)OCI_ATTR_NAME, ctlp->errhp_ctl)); + + /* Set the expression type to obj constructor, opaque/sql function, or ref + * table name. + */ + if (bit(objp->flag_obj, OBJ_OBJ)) + exprtype = OCI_DIRPATH_EXPR_OBJ_CONSTR; /* expr is an obj constructor */ + else if (bit(objp->flag_obj, OBJ_OPQ)) + exprtype = OCI_DIRPATH_EXPR_SQL; /* expr is an opaque/sql func */ + else if (bit(objp->flag_obj, OBJ_REF)) + exprtype = OCI_DIRPATH_EXPR_REF_TBLNAME; /* expr is a ref table name */ + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(objp->ctx_obj), + (ub4)OCI_HTYPE_DIRPATH_FN_CTX, + (dvoid *) &exprtype, + (ub4) 0, + (ub4)OCI_ATTR_DIRPATH_EXPR_TYPE, ctlp->errhp_ctl)); + } + + /* set number of columns to be loaded */ + numCols = objp->ncol_obj; + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(objp->ctx_obj), + (ub4)OCI_HTYPE_DIRPATH_FN_CTX, + (dvoid *)&numCols, + (ub4)0, (ub4)OCI_ATTR_NUM_COLS, ctlp->errhp_ctl)); + + /* get the column parameter list */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(objp->ctx_obj), + OCI_HTYPE_DIRPATH_FN_CTX, + (dvoid *)&objColLstDesc, (ub4 *)0, + OCI_ATTR_LIST_COLUMNS, ctlp->errhp_ctl)); + + /* get attributes of the column parameter list */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)objColLstDesc, + OCI_DTYPE_PARAM, + (dvoid *)&parmtyp, (ub4 *)0, + OCI_ATTR_PTYPE, ctlp->errhp_ctl)); + + if (parmtyp != OCI_PTYPE_LIST) + { + fprintf(output_fp, + "ERROR: expected parmtyp of OCI_PTYPE_LIST, got %d\n", + (int)parmtyp); + } + + /* Now set the attributes of each column by getting a parameter + * handle on each column, then setting attributes on the parameter + * handle for the column. + * Note that positions within a column list descriptor are 1-based. + */ + for (i = 0, pos = 1, colp = objp->col_obj, fldp = objp->fld_obj; + i < objp->ncol_obj; + i++, pos++, colp++, fldp++) + { + /* get parameter handle on the column */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIParamGet((CONST dvoid *)objColLstDesc, + (ub4)OCI_DTYPE_PARAM, ctlp->errhp_ctl, + (dvoid **)&colDesc, pos)); + + colp->id_col = i; /* position in column array*/ + + /* set external attributes on the column */ + + /* column name */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)colp->name_col, + (ub4)strlen((const char *)colp->name_col), + (ub4)OCI_ATTR_NAME, ctlp->errhp_ctl)); + + /* column type */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->exttyp_col, (ub4)0, + (ub4)OCI_ATTR_DATA_TYPE, ctlp->errhp_ctl)); + + /* max data size */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&fldp->maxlen_fld, (ub4)0, + (ub4)OCI_ATTR_DATA_SIZE, ctlp->errhp_ctl)); + + /* If column is chrdate or date, set column (input field) date mask + * to trigger client library to check string for a valid date. + * Note: OCIAttrSet() may be called here w/ a null ptr or null string. + */ + if (colp->date_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)colp->datemask_col, + (colp->datemask_col) ? + (ub4)strlen((const char *)colp->datemask_col) :0, + (ub4)OCI_ATTR_DATEFORMAT, ctlp->errhp_ctl)); + } + + if (colp->prec_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->prec_col, (ub4)0, + (ub4)OCI_ATTR_PRECISION, ctlp->errhp_ctl)); + } + + if (colp->scale_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->scale_col, (ub4)0, + (ub4)OCI_ATTR_SCALE, ctlp->errhp_ctl)); + } + + if (colp->csid_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->csid_col, (ub4)0, + (ub4)OCI_ATTR_CHARSET_ID, ctlp->errhp_ctl)); + } + + /* If this is an object, opaque or ref then recurse */ + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + init_obj_load(ctlp, tblp, colp->obj_col); + + /* set the object function context into the param handle */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)(colp->obj_col->ctx_obj), (ub4)0, + (ub4)OCI_ATTR_DIRPATH_FN_CTX, ctlp->errhp_ctl)); + } + + /* free the parameter handle to the column descriptor */ + OCI_CHECK((dvoid *)0, 0, ociret, ctlp, + OCIDescriptorFree((dvoid *)colDesc, OCI_DTYPE_PARAM)); + } + +} + + +/* +**++++++++++++++++++++++++++++++ init_load +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Function which prepares for a direct path load using the direct +** path API on the table described by 'tblp'. +** +** Assumptions: +** +** The loadctl structure given by 'ctlp' has an appropriately initialized +** environment, and service context handles (already connected to +** the server) prior to calling this function. +** +** Parameters: +** +** ctlp load control structure pointer +** tblp table pointer +** sessp session pointer +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void init_load(ctlp, tblp, sessp) +struct loadctl *ctlp; /* load control structure pointer */ +struct tbl *tblp; /* table pointer */ +struct sess *sessp; /* session pointer */ +{ + struct col *colp; + struct fld *fldp; + sword ociret; /* return code from OCI calls */ + OCIDirPathCtx *dpctx; /* direct path context */ + OCIParam *objAttrDesc; /* attribute parameter descriptor */ + OCIParam *colDesc; /* column parameter descriptor */ + ub1 parmtyp; + ub1 *timestamp = (ub1 *)0; + ub4 size; + ub2 i; + ub4 pos; + ub1 dirpathinput = OCI_DIRPATH_INPUT_TEXT; + + /* allocate and initialize a direct path context */ + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->envhp_ctl, + (dvoid **)&ctlp->dpctx_ctl, + (ub4)OCI_HTYPE_DIRPATH_CTX, + (size_t)0, (dvoid **)0)); + + dpctx = ctlp->dpctx_ctl; /* shorthand*/ + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)tblp->name_tbl, + (ub4)0, + (ub4)OCI_ATTR_NAME, ctlp->errhp_ctl)); + + if (tblp->subname_tbl && *tblp->subname_tbl) /* set (sub)partition name*/ + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)tblp->subname_tbl, + (ub4)strlen((const char *)tblp->subname_tbl), + (ub4)OCI_ATTR_SUB_NAME, ctlp->errhp_ctl)); + } + + if (tblp->owner_tbl) /* set schema (owner) name*/ + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)tblp->owner_tbl, + (ub4)strlen((const char *)tblp->owner_tbl), + (ub4)OCI_ATTR_SCHEMA_NAME, ctlp->errhp_ctl)); + } + + /* Note: setting tbl default datemask will not trigger client library + * to check strings for dates - only setting column datemask will. + */ + if (tblp->dfltdatemask_tbl) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)tblp->dfltdatemask_tbl, + (ub4)strlen((const char *)tblp->dfltdatemask_tbl), + (ub4)OCI_ATTR_DATEFORMAT, ctlp->errhp_ctl)); + } + + /* set the data input type to be text */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet ((dvoid *)dpctx, OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&dirpathinput, (ub4)0, + OCI_ATTR_DIRPATH_INPUT, ctlp->errhp_ctl)); + + if (tblp->parallel_tbl) /* set table level parallel option*/ + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&tblp->parallel_tbl, + (ub4)0, (ub4)OCI_ATTR_DIRPATH_PARALLEL, + ctlp->errhp_ctl)); + } + + if (tblp->nolog_tbl) /* set table level nolog option*/ + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&tblp->nolog_tbl, (ub4)0, + (ub4)OCI_ATTR_DIRPATH_NOLOG, ctlp->errhp_ctl)); + } + + if (tblp->objconstr_tbl) /* set obj type of tbl to load if exists */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, + (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *) tblp->objconstr_tbl, + (ub4)strlen((const char *) tblp->objconstr_tbl), + (ub4)OCI_ATTR_DIRPATH_OBJ_CONSTR, ctlp->errhp_ctl)); + + /* set number of columns to be loaded */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&tblp->ncol_tbl, + (ub4)0, (ub4)OCI_ATTR_NUM_COLS, ctlp->errhp_ctl)); + + /* get the column parameter list */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)dpctx, + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&ctlp->colLstDesc_ctl, (ub4 *)0, + OCI_ATTR_LIST_COLUMNS, ctlp->errhp_ctl)); + + /* get attributes of the column parameter list */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)ctlp->colLstDesc_ctl, + OCI_DTYPE_PARAM, + (dvoid *)&parmtyp, (ub4 *)0, + OCI_ATTR_PTYPE, ctlp->errhp_ctl)); + + if (parmtyp != OCI_PTYPE_LIST) + { + fprintf(output_fp, "ERROR: expected parmtyp of OCI_PTYPE_LIST, got%d\n", + (int)parmtyp); + } + + /* Now set the attributes of each column by getting a parameter + * handle on each column, then setting attributes on the parameter + * handle for the column. + * Note that positions within a column list descriptor are 1-based. + */ + for (i = 0, pos = 1, colp = tblp->col_tbl, fldp = tblp->fld_tbl; + i < tblp->ncol_tbl; + i++, pos++, colp++, fldp++) + { + /* get parameter handle on the column */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIParamGet((CONST dvoid *)ctlp->colLstDesc_ctl, + (ub4)OCI_DTYPE_PARAM, ctlp->errhp_ctl, + (dvoid **)&colDesc, pos)); + + colp->id_col = i; /* position in column array*/ + + /* set external attributes on the column */ + + /* column name */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)colp->name_col, + (ub4)strlen((const char *)colp->name_col), + (ub4)OCI_ATTR_NAME, ctlp->errhp_ctl)); + + /* column type */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->exttyp_col, (ub4)0, + (ub4)OCI_ATTR_DATA_TYPE, ctlp->errhp_ctl)); + + /* max data size */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&fldp->maxlen_fld, (ub4)0, + (ub4)OCI_ATTR_DATA_SIZE, ctlp->errhp_ctl)); + + /* If column is chrdate or date, set column (input field) date mask + * to trigger client library to check string for a valid date. + * Note: OCIAttrSet() may be called here w/ a null ptr or null string. + */ + if (colp->date_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)colp->datemask_col, + (colp->datemask_col) ? + (ub4)strlen((const char *)colp->datemask_col) :0, + (ub4)OCI_ATTR_DATEFORMAT, ctlp->errhp_ctl)); + } + + if (colp->prec_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->prec_col, (ub4)0, + (ub4)OCI_ATTR_PRECISION, ctlp->errhp_ctl)); + } + + if (colp->scale_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->scale_col, (ub4)0, + (ub4)OCI_ATTR_SCALE, ctlp->errhp_ctl)); + } + + if (colp->csid_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->csid_col, (ub4)0, + (ub4)OCI_ATTR_CHARSET_ID, ctlp->errhp_ctl)); + } + + if (bit(colp->flag_col, COL_OID)) + { + ub1 flg = 1; + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&flg, (ub4)0, + (ub4)OCI_ATTR_DIRPATH_OID, ctlp->errhp_ctl)); + } + + /* If this is an object, opaque or ref then call init_obj_load */ + /* to handle it. */ + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + init_obj_load(ctlp, tblp, colp->obj_col); + + /* set the object function context into the param handle */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)(colp->obj_col->ctx_obj), (ub4)0, + (ub4)OCI_ATTR_DIRPATH_FN_CTX, ctlp->errhp_ctl)); + + } + + + /* free the parameter handle to the column descriptor */ + OCI_CHECK((dvoid *)0, 0, ociret, ctlp, + OCIDescriptorFree((dvoid *)colDesc, OCI_DTYPE_PARAM)); + } + + /* read back some of the attributes for purpose of illustration */ + for (i = 0, pos = 1, colp = tblp->col_tbl, fldp = tblp->fld_tbl; + i < tblp->ncol_tbl; + i++, pos++, colp++, fldp++) + { + text *s; + ub4 slen; + ub4 maxdsz; + ub2 dty; + + /* get parameter handle on the column */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIParamGet((CONST dvoid *)ctlp->colLstDesc_ctl, + (ub4)OCI_DTYPE_PARAM, ctlp->errhp_ctl, + (dvoid **)&colDesc, pos)); + + + /* get column name */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)colDesc, + OCI_DTYPE_PARAM, + (dvoid *)&s, (ub4 *)&slen, + OCI_ATTR_NAME, ctlp->errhp_ctl)); + + /* check string length */ + if (slen != (ub4)strlen((const char *)colp->name_col)) + { + fprintf(output_fp, + "*** ERROR *** bad col name len in column parameter\n"); + fprintf(output_fp, "\texpected %d, got %d\n", + (int)strlen((const char *)colp->name_col), (int)slen); + } + + if (strncmp((const char *)s, (const char *)colp->name_col, (size_t)slen)) + { + fprintf(output_fp,"*** ERROR *** bad column name in column parameter\n"); + fprintf(output_fp, "\texpected %s, got %s\n", + (char *)colp->name_col, (char *)s); + } + + /* get column type */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)colDesc, + OCI_DTYPE_PARAM, + (dvoid *)&dty, (ub4 *)0, + OCI_ATTR_DATA_TYPE, ctlp->errhp_ctl)); + if (dty != colp->exttyp_col) + { + fprintf(output_fp, "*** ERROR *** bad OCI_ATTR_DATA_TYPE in col param\n"); + fprintf(output_fp, "\tColumn name %s\n", colp->name_col); + fprintf(output_fp, "\t\texpected %d, got %d\n", + (int)colp->exttyp_col, (int)dty); + } + + /* get the max data size */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)colDesc, + OCI_DTYPE_PARAM, + (dvoid *)&maxdsz, (ub4 *)0, + OCI_ATTR_DATA_SIZE, ctlp->errhp_ctl)); + if (maxdsz != fldp->maxlen_fld) + { + fprintf(output_fp, "*** ERROR *** bad OCI_ATTR_DATA_SIZE in col param\n"); + fprintf(output_fp, "\tColumn name %s\n", colp->name_col); + fprintf(output_fp, "\t\texpected %d, got %d\n", + (int)fldp->maxlen_fld, (int)maxdsz); + } + + /* free the parameter handle to the column descriptor */ + OCI_CHECK((dvoid *)0, 0, ociret, ctlp, + OCIDescriptorFree((dvoid *)colDesc, OCI_DTYPE_PARAM)); + } + + { + char *vbuf; + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&tblp->xfrsz_tbl, + (ub4)0, (ub4)OCI_ATTR_BUF_SIZE, ctlp->errhp_ctl)); + + /* minimize read system calls */ + vbuf = (char *)malloc((size_t)tblp->xfrsz_tbl); + if (vbuf != (char *)0) + (void)setvbuf(stdin, vbuf, _IOFBF, (size_t)tblp->xfrsz_tbl); + } + + /* prepare the load */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIDirPathPrepare(dpctx, ctlp->svchp_ctl, ctlp->errhp_ctl)); + + /* Allocate column array and stream handles. + * Note that for the column array and stream handles + * the parent handle is the direct path context. + * Also note that Oracle errors are returned via the + * environment handle associated with the direct path context. + */ + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->dpctx_ctl, (dvoid**)&ctlp->dpca_ctl, + (ub4)OCI_HTYPE_DIRPATH_COLUMN_ARRAY, + (size_t)0, (dvoid **)0)); + + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->dpctx_ctl,(dvoid**)&ctlp->dpstr_ctl, + (ub4)OCI_HTYPE_DIRPATH_STREAM, + (size_t)0, (dvoid **)0)); + + /* get number of rows in the column array just allocated */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpca_ctl), + OCI_HTYPE_DIRPATH_COLUMN_ARRAY, + (dvoid *)(&ctlp->nrow_ctl), (ub4 *)0, + OCI_ATTR_NUM_ROWS, ctlp->errhp_ctl)); + + /* get number of columns in the column array just allocated */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpca_ctl), + OCI_HTYPE_DIRPATH_COLUMN_ARRAY, + (dvoid *)(&ctlp->ncol_ctl), (ub4 *)0, + OCI_ATTR_NUM_COLS, ctlp->errhp_ctl)); + + /* allocate the column arrays for any column objects, opaques or refs */ + for (i = 0, colp = tblp->col_tbl; i < tblp->ncol_tbl; i++, colp++) + { + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + alloc_obj_ca(ctlp, tblp, colp->obj_col); + } + } + + /* allocate buffer for input records */ + ctlp->inbuf_ctl = (ub1 *)malloc(ctlp->nrow_ctl * sessp->maxreclen_sess); + if (ctlp->inbuf_ctl == (ub1 *)0) + { + perror("malloc"); + FATAL("init_load:malloc:inbuf_ctl alloc failure", + ctlp->nrow_ctl * sessp->maxreclen_sess); + } + + /* allocate Offset-TO-Record number mapping array */ + ctlp->otor_ctl = (ub4 *)malloc(ctlp->nrow_ctl * sizeof(ub4)); + if (ctlp->otor_ctl == (ub4 *)0) + { + perror("malloc"); + FATAL("init_load:malloc:otor_ctl alloc failure", + ctlp->nrow_ctl * sizeof(ub4)); + } + + CLEAR_PCTX(ctlp->pctx_ctl); /* initialize partial context*/ + +/* + fprintf(output_fp, "init_load: %ld column array rows\n", + (long)ctlp->nrow_ctl);*/ + + return; + +} + + +/* +**++++++++++++++++++++++++++++++ simple_load +++++++++++++++++++++++++++++++++ +** +** Description: +** +** This function reads input records from 'inputfp', parses the input +** records into fields according to the field description given by +** tblp->fld_tbl, and loads the data into the database. +** +** LOBs can be loaded with this function in a piecewise manner. This +** function is written as a state machine, which cycles through the +** following states: +** RESET, GET_RECORD, FIELD_SET, DO_CONVERT, DO_LOAD, END_OF_INPUT +** +** The normal case of all scalar data, where multiple records fit +** entirely in memory, cycles through the following states: +** RESET, [[GET_RECORD, FIELD_SET]+, DO_CONVERT, DO_LOAD]+, RESET +** +** The case of loading one or more LOB columns, which do not fit entirely +** in memory, has the following state transitions: +** RESET, GET_RECORD, [FIELD_SET, DO_CONVERT, DO_LOAD]+, RESET +** Note: The second and subsequent transitions to the FIELD_SET +** state have a partial record context. +** +** A mapping of column array offset to input record number (otor_ctl[]) +** is maintained by this function for error reporting and recovery. +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure pointer +** tblp table pointer +** sessp session pointer +** inputfp input file pointer +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void simple_load(ctlp, tblp, sessp, inputfp) +struct loadctl *ctlp; /* load control structure pointer */ +struct tbl *tblp; /* table pointer */ +struct sess *sessp; /* session pointer */ +FILE *inputfp; /* input file pointer */ +{ + sword fsetrv; /* return value from field_set */ + sword cvtrv; /* return value from do_convert */ + sword ldrv; /* return value from do_load */ + ub4 startoff; /* starting row offset for conversion */ + ub4 nxtLoadOff; /* column array offset to be loaded next */ + ub4 rowCnt; /* count of rows populated in column array */ + ub4 cvtCnt; /* count of rows converted */ + ub4 lastoff; /* last row offset used in column array */ + sword state; /* current state machine state */ + sword done; /* set to TRUE when load is complete */ + ub4 input_recnum; /* current input record number */ + ub4 load_recnum; /* record number corresponding to last record loaded */ + ub4 err_recnum; /* record number corresponding to error */ + text *recp; + ub4 cvtcontcnt; /* # of times CONVERT_CONTINUE returned */ + sword ociResetErr; /* stream reset return status */ + sword cvtErrorRowNeedsLoad; /* row had conversion error, needs load */ + + /* set initial state */ + input_recnum = 0; + load_recnum = UB4MAXVAL; + err_recnum = 0; + state = RESET; + fsetrv = FIELD_SET_COMPLETE; + cvtrv = CONVERT_SUCCESS; + ldrv = LOAD_SUCCESS; + done = FALSE; + cvtcontcnt = 0; + cvtErrorRowNeedsLoad = FALSE; + + while (!done) + { + switch (state) + { + case RESET: /* Reset column array and direct stream state to be empty*/ + { + ub2 i; + struct col *colp; + startoff = 0; /* reset starting offset into column array*/ + lastoff = 0; /* last entry set of column array*/ + rowCnt = 0; /* count of rows partial and complete*/ + cvtCnt = 0; /* count of converted rows*/ + nxtLoadOff = 0; + + /* Reset column array state in case a previous conversion needed + * to be continued, or a row is expecting more data. + */ + (void) OCIDirPathColArrayReset(ctlp->dpca_ctl, ctlp->errhp_ctl); + /* reset the column arrays for any column objects, opaques or refs */ + for (i = 0, colp = tblp->col_tbl; i < tblp->ncol_tbl; i++, colp++) + { + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + reset_obj_ca(ctlp, tblp, colp->obj_col); + } + } + + /* Reset the stream state since we are starting a new stream + * (i.e. don't want to append to existing data in the stream.) + */ + ociResetErr = OCIDirPathStreamReset(ctlp->dpstr_ctl, ctlp->errhp_ctl); + if (ociResetErr != OCI_SUCCESS) + FATAL("OCIDirPathStreamReset failed", ociResetErr); + state = GET_RECORD; /* get some more input records*/ + /* FALLTHROUGH */ + } + + case GET_RECORD: + { + assert(lastoff < ctlp->nrow_ctl); /* array bounds check*/ + + recp = (text *)(ctlp->inbuf_ctl + (lastoff * sessp->maxreclen_sess)); + + if (fgets((char *)recp, (int)sessp->maxreclen_sess, inputfp) + != (char *)NULL) + { + /* set column array offset to input record number map */ + ctlp->otor_ctl[lastoff] = ++input_recnum; + /* if ((input_recnum % 10000) == 0) + fprintf(output_fp, "record number: %d\n", (int)input_recnum); */ + state = FIELD_SET; + /* FALLTHROUGH */ + } + else + { + if (lastoff) + lastoff--; + state = END_OF_INPUT; + break; + } + } + + case FIELD_SET: + { + /* map input data fields to DB columns, set column array entries */ + fsetrv = field_set(ctlp, tblp, (struct obj *) 0, recp, lastoff, 0); + rowCnt = lastoff + 1; + + if (rowCnt == ctlp->nrow_ctl || fsetrv != FIELD_SET_COMPLETE) + { + /* array is full, or have a large partial column, or the + * secondary buffer is in use by an OUTOFLINE field. + */ + state = DO_CONVERT; + /* FALLTHROUGH */ + } + else + { + lastoff++; /* use next column array slot*/ + state = GET_RECORD; /* get next record*/ + break; + } + } + + case DO_CONVERT: + { + /* Either one of the following is true: + * - the column array is full + * - there is a large partial column + * - the secondary buffer used by field_set() is in use + * - previous conversion returned CONVERT_CONTINUE and + * now the conversion is being resumed. + * + * In any case, convert and load the data. + */ + ub4 cvtBadRoff; /* bad row offset from conversion*/ + ub2 cvtBadCoff; /* bad column offset from conversion*/ + + while (startoff <= lastoff) + { + ub4 cvtCntPerCall = 0; /* rows converted in one call to do_convert*/ + + /* note that each call to do_convert() will convert all contiguousrows + * in the colarray until it hit a row in error while converting. + */ + cvtrv = do_convert(ctlp, startoff, rowCnt, &cvtCntPerCall, + &cvtBadCoff); + cvtCnt += cvtCntPerCall; /* sum of rows converted so far in colarray*/ + if (cvtrv == CONVERT_SUCCESS) + { + /* One or more rows converted successfully, break + * out of the conversion loop and load the rows. + */ + assert(cvtCntPerCall > 0); + state = DO_LOAD; + break; + } + else if (cvtrv == CONVERT_ERROR) + { + /* Conversion error. Reject the bad record and + * continue on with the next record (if any). + * cvtBadRoff is the 0-based index of the bad row in + * the column array. cvtBadCoff is the 0-based index + * of the bad column (of the bad row) in the column + * array. + */ + /* This assert was used in the 10.1.0.4.0 version but removed for + * 10.2 because compiler warning for pointless comparison of unsigned + * interger */ + /* assert(cvtCntPerCall >= (ub4)0); */ + + cvtBadRoff = startoff + cvtCntPerCall; + err_recnum = ctlp->otor_ctl[cvtBadRoff]; /* map to input_recnum*/ + fprintf(output_fp, "Conversion Error on record %d, column %d\n", + (int)err_recnum, (int)cvtBadCoff + 1); + + /* print err msg txt */ + errprint((dvoid *)(ctlp->errhp_ctl), OCI_HTYPE_ERROR, + (sb4 *)0); + + /* Always need to load a stream after a conversion error */ + cvtErrorRowNeedsLoad = TRUE; + + if (cvtBadRoff == lastoff) + { + /* Conversion error occurred on the last populated slot + * of the column array. + * Flush the input stream of any data for this row, + * and re-use this slot for another input record. + */ + field_flush(ctlp, lastoff); + state = GET_RECORD; + startoff = cvtBadRoff; /* only convert the last row*/ + rowCnt = 0; /* already tried converting all rows in col array*/ + assert(startoff <= lastoff); + break; + } + else + { + /* Skip over bad row and continue conversion with next row. + * We don't attempt to fill in this slot with another record. + */ + startoff = cvtBadRoff + 1; + assert(startoff <= lastoff); + continue; + } + } + else if (cvtrv == CONVERT_NEED_DATA) /* partial col encountered*/ + { + /* Partial (large) column encountered, load the piece + * and loop back up to field_set to get the rest of + * the partial column. + * startoff is set to the offset into the column array where + * we need to resume conversion from, which should be the + * last entry that we set (lastoff). + */ + state = DO_LOAD; + + /* Set our row position in column array to resume + * conversion at when DO_LOAD transitions to DO_CONVERT. + */ + /* This assert was used in the 10.1.0.4.0 version but removed for + * 10.2 because compiler warning for pointless comparison of unsigned + * interger */ + /* assert(cvtCntPerCall >= (ub4)0); */ + startoff = startoff + cvtCntPerCall; + /* assert(startoff == lastoff); */ + break; + } + else if (cvtrv == CONVERT_CONTINUE) + { + /* The stream buffer is full and there is more data in + * the column array which needs to be converted. + * Load the stream (DO_LOAD) and transition back to + * DO_CONVERT to convert the remainder of the column array, + * without calling the field setting function in between. + * The sequence {DO_CONVERT, DO_LOAD} may occur many times + * for a long row or column. + * Note that startoff becomes the offset into the column array + * where we need to resume conversion from. + */ + cvtcontcnt++; + state = DO_LOAD; + + /* Set our row position in column array (startoff) to + * resume conversion at when we transition from the + * DO_LOAD state back to DO_CONVERT. + */ + /* This assert was used in the 10.1.0.4.0 version but removed for + * 10.2 because compiler warning for pointless comparison of unsigned + * interger */ + /* assert(cvtCntPerCall >= (ub4)0); */ + startoff = startoff + cvtCntPerCall; + assert(startoff <= lastoff); + + break; + } + } /* end while*/ + break; + } + + case DO_LOAD: + { + ub4 loadCnt; /* count of rows loaded by do_load*/ + + ldrv = do_load(ctlp, &loadCnt); + nxtLoadOff = nxtLoadOff + loadCnt; + cvtErrorRowNeedsLoad = FALSE; + + switch (ldrv) + { + case LOAD_SUCCESS: + { + /* The stream has been loaded successfully. What we do next + * depends on the result of the previous conversion step. + */ + load_recnum = ctlp->otor_ctl[nxtLoadOff - 1]; + if (cvtrv == CONVERT_SUCCESS || cvtrv == CONVERT_ERROR) + { + /* The column array was successfully converted (or the + * last row was in error). + * Fill up another array with more input records. + */ + state = RESET; + } + else if (cvtrv == CONVERT_CONTINUE) + { + /* There is more data in column array to convert and load. */ + state = DO_CONVERT; + + /* Note that when do_convert returns CONVERT_CONTINUE that + * startoff was set to the row offset into the column array + * of where to resume conversion. The loadCnt returned by + * OCIDirPathLoadStream is the number of rows successfully + * loaded. + * Do a sanity check on the attributes here. + */ + if (startoff != nxtLoadOff) /* sanity*/ + fprintf(output_fp, "LOAD_SUCCESS/CONVERT_CONTINUE: %ld:%ld\n", + (long)nxtLoadOff, startoff); + + /* Reset the direct stream state so conversion starts at + * the beginning of the stream. + */ + ociResetErr = OCIDirPathStreamReset(ctlp->dpstr_ctl,ctlp->errhp_ctl); + if (ociResetErr != OCI_SUCCESS) + FATAL("OCIDirPathStreamReset failed", ociResetErr); + } + else + { + /* Note that if the previous conversion step returned + * CONVERT_NEED_DATA then the load step would have returned + * LOAD_NEED_DATA too (not LOAD_SUCCESS). + */ + FATAL("DO_LOAD:LOAD_SUCCESS: unexpected cvtrv", cvtrv); + } + break; + } + + case LOAD_ERROR: + { + sb4 oraerr; + ub4 badRowOff; + + badRowOff = nxtLoadOff; + nxtLoadOff += 1; /* account for bad row*/ + err_recnum = ctlp->otor_ctl[badRowOff]; /* map to input_recnum*/ + fprintf(output_fp, "Error on record %ld\n", (long)err_recnum); + + /* print err msg txt */ + errprint((dvoid *)(ctlp->errhp_ctl), OCI_HTYPE_ERROR, &oraerr); + + /* On a load error, all rows up to the row in error are loaded. + * account for that here by setting load_recnum only when some + * rows have been loaded. + */ + if (loadCnt != 0) + load_recnum = err_recnum - 1; + + if (oraerr == OER(600)) + FATAL("DO_LOAD:LOAD_ERROR: server internal error", oraerr); + + if (err_recnum == input_recnum) + { + /* Error occurred on last input row, which may or may not + * be in a partial state. Flush any remaining input for + * the bad row. + */ + field_flush(ctlp, badRowOff); + } + + /* Continue loading this stream until no errors. Note that + * the stream positions itself to the next row on error. + */ + state = DO_LOAD; + + break; + } + + case LOAD_NEED_DATA: + { + load_recnum = ctlp->otor_ctl[nxtLoadOff]; + if (cvtrv == CONVERT_NEED_DATA) + state = FIELD_SET; /* need more input data*/ + else if (cvtrv == CONVERT_CONTINUE) + state = DO_CONVERT; /* have input data, continue with conversion*/ + else + FATAL("DO_LOAD:LOAD_NEED_DATA: unexpected cvtrv", cvtrv); + + /* Reset the direct stream state so conversion starts at + * the beginning of the stream. + */ + ociResetErr = OCIDirPathStreamReset(ctlp->dpstr_ctl, ctlp->errhp_ctl); + if (ociResetErr != OCI_SUCCESS) + FATAL("OCIDirPathStreamReset failed", ociResetErr); + break; + } + + case LOAD_NO_DATA: + { + /* Attempt to either load an empty stream, or a stream + * which has been completely processed. + */ + if (cvtrv == CONVERT_CONTINUE) + { + /* Reset stream state so we convert into an empty stream buffer.*/ + ociResetErr = OCIDirPathStreamReset(ctlp->dpstr_ctl,ctlp->errhp_ctl); + if (ociResetErr != OCI_SUCCESS) + FATAL("OCIDirPathStreamReset failed", ociResetErr); + state = DO_CONVERT; /* convert remainder of column array*/ + } + else + state = RESET; /* get some more input records*/ + break; + } + + default: + FATAL("DO_LOAD: unexpected return value", ldrv); + break; + } + break; + } + + case END_OF_INPUT: + { + if (cvtCnt || cvtErrorRowNeedsLoad) + state = DO_LOAD; /* deal with data already converted, but not loaded*/ + else if (rowCnt) + state = DO_CONVERT; /* deal with a partially populated column array*/ + else + done = TRUE; + break; + } + + default: + FATAL("SIMPLE_LOAD: unexpected state", state); + break; + } /* end switch (state)*/ + } + +/* + fprintf(output_fp, "do_convert returned CONVERT_CONTINUE %ld times\n", + (long)cvtcontcnt);*/ + + fprintf(output_fp, "Number of input records processed = %ld\n", + (long)input_recnum); + +} + + +/* +**++++++++++++++++++++++++++++++ finish_load +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Completes the loading procedure. +** +** Assumptions: +** +** Does not free server data structures related to the load. +** +** Parameters: +** +** ctlp load control structure pointer +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void finish_load(ctlp) +struct loadctl *ctlp; /* load control structure pointer */ +{ + sword ociret; /* return code from OCI call */ + + /* Execute load finishing logic without freeing server data structures + * related to the load. + */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIDirPathDataSave(ctlp->dpctx_ctl, ctlp->errhp_ctl, + (ub4)OCI_DIRPATH_DATASAVE_FINISH)); + + /* free up server data structures for the load. */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIDirPathFinish(ctlp->dpctx_ctl, ctlp->errhp_ctl)); +} + + +/* +**++++++++++++++++++++++++++++++ do_convert +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Convert the data in the column array to stream format. +** +** Assumptions: +** +** +** Parameters: +** +** ctlp pointer to control structure (IN/OUT) +** rowcnt number of rows in column array (IN) +** startoff starting row offset into column array (IN) +** cvtCntp count of rows successfully converted (OUT) +** badcoffp column offset into col array of bad col (OUT) +** +** Returns: +** +** CONVERT_SUCCESS: +** All data in the column array has been successfully converted. +** *cvtCntp is the number of rows successfully converted. +** CONVERT_ERROR: +** Conversion error occurred on the row after the last successfully +** converted row. +** Client Action: +** Continue converting the column array by calling this function +** again with startoff adjusted to skip over the row in error. +** CONVERT_NEED_DATA: +** All data in the column array has been converted, but the last +** column processed was marked as a partial. +** CONVERT_CONTINUE: +** Not all of the data in the column array has been converted due to +** lack of space in the stream buffer. +** Client Action: +** Load the converted stream data, reset the stream, and call this +** function again without modifying the column array and setting +** startoff to the appropriate position in the array. +** +**------------------------------------------------------------------------- +*/ + +sword do_convert(ctlp, startoff, rowcnt, cvtCntp, badcoffp) +struct loadctl *ctlp; /* pointer to control structure (IN/OUT) */ +ub4 rowcnt; /* number of rows in column array (IN) */ +ub4 startoff; /* starting row offset into column array (IN) */ +ub4 *cvtCntp; /* count of rows successfully converted (OUT) */ +ub2 *badcoffp; /* column offset into col array of bad col (OUT) */ +{ + sword retval = CONVERT_SUCCESS; + sword ocierr, ocierr2; + ub2 badcol = 0; + + *cvtCntp = 0; + + if (startoff >= rowcnt) + FATAL("DO_CONVERT: bad startoff", startoff); + + if (rowcnt) + { + /* convert array to stream, filter out bad records */ + ocierr = OCIDirPathColArrayToStream(ctlp->dpca_ctl, ctlp->dpctx_ctl, + ctlp->dpstr_ctl, ctlp->errhp_ctl, + rowcnt, startoff); + switch (ocierr) + { + case OCI_SUCCESS: /* everything succesfully converted to stream */ + retval = CONVERT_SUCCESS; + break; + + case OCI_ERROR: /* some error, most likely a conversion error */ + /* Tell the caller that a conversion error occurred along + * with the number of rows successfully converted (*cvtCntp). + * Note that the caller is responsible for adjusting startoff + * accordingly and calling us again to resume conversion of + * the remaining rows. + */ + retval = CONVERT_ERROR; /* conversion error */ + break; + + case OCI_CONTINUE: /* stream buffer is full */ + /* The stream buffer could not contain all of the data in + * the column array. + * The client should load the converted data, and loop + * back to convert the remaining data in the column array. + */ + retval = CONVERT_CONTINUE; + break; + + case OCI_NEED_DATA: /* partial column encountered */ + /* Everything converted, but have a partial column. + * Load this stream, and return to caller for next piece. + */ + retval = CONVERT_NEED_DATA; + break; + + default: /* unexpected OCI return value! */ + FATAL("do_convert:OCIDirPathColArrayToStream:Unexpected OCI return code", + ocierr); + /* NOTREACHED */ + break; + } + + OCI_CHECK(ctlp->errhp2_ctl, OCI_HTYPE_ERROR, ocierr2, ctlp, + OCIAttrGet((CONST dvoid *)ctlp->dpca_ctl, + OCI_HTYPE_DIRPATH_COLUMN_ARRAY, + (dvoid *)(cvtCntp), (ub4 *)0, + OCI_ATTR_ROW_COUNT, ctlp->errhp2_ctl)); + + OCI_CHECK(ctlp->errhp2_ctl, OCI_HTYPE_ERROR, ocierr2, ctlp, + OCIAttrGet((CONST dvoid *)ctlp->dpca_ctl, + OCI_HTYPE_DIRPATH_COLUMN_ARRAY, + (dvoid *)(&badcol), (ub4 *)0, + OCI_ATTR_COL_COUNT, ctlp->errhp2_ctl)); + } + + *badcoffp = badcol; + + return retval; +} + + +/* +**++++++++++++++++++++++++++++++ do_load +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Load a direct path stream. +** +** Assumptions: +** +** errhp_ctl contains error information when an error is returned +** from this function. +** +** Parameters: +** +** ctlp: Pointer to control structure. +** loadCntp: Count of rows loaded on this call. +** +** Returns: +** +** LOAD_SUCCESS: +** All data loaded succesfully. +** Client Action: +** Supply another stream and call again, or finish the load. +** +** LOAD_ERROR: +** Error while loading occured. *loadCntp is the number of +** rows successfully loaded this call. +** Client Action: +** Use *loadCntp to compute current column array position and +** map the column array position to the input record and reject +** the record. +** +** if (this is a continuation of a row) +** { +** /o server has data for this row buffered o/ +** flush the row data +** } +** +** if (end-of-stream has not been reached) +** { +** call this function again, +** stream loading will resume with the next row in the stream. +** } +** else if (end-of-stream has been reached) +** { +** build another stream and call this function again, +** or finish the load. +** } +** +** LOAD_NEED_DATA: +** Last row was not complete. +** Client Action: +** Caller needs to supply more data for the row (a column is +** being pieced.) Note that the row offset can be determined +** by either the cvtCnt returned from do_convert, or from the +** loadCntp returned by do_load. The column offset for the +** column being pieced is available as an attribute of +** the column array. +** +**------------------------------------------------------------------------- +*/ + +sword do_load(ctlp, loadCntp) +struct loadctl *ctlp; /* pointer to control structure (IN/OUT) */ +ub4 *loadCntp; /* number of rows loaded (OUT) */ +{ + sword ocierr; /* OCI return value */ + sword retval; /* return value from this function */ + sword getRowCnt = FALSE; /* return row count if TRUE */ + + if (loadCntp != (ub4 *)0) + { + *loadCntp = 0; + getRowCnt = TRUE; + } + + /* Load the stream. + * Note that the position in the stream is maintained internally to + * the stream handle, along with offset information for the column + * array which produced the stream. When the conversion to stream + * format is done, the data is appended to the stream. It is the + * responsibility of the caller to reset the stream when appropriate. + * On errors, the position is moved to the next row, or the end of + * the stream if the error occurs on the last row. The next LoadStream + * call will start on the next row, if any. + * If a LoadStream call is made, and end of stream has been reached, + * OCI_NO_DATA is returned. + */ + +#if 1 + ocierr = OCIDirPathLoadStream(ctlp->dpctx_ctl, ctlp->dpstr_ctl, + ctlp->errhp_ctl); +#else + { + ub1 *bufaddr; + ub4 buflen; + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ocierr, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpstr_ctl), + OCI_HTYPE_DIRPATH_STREAM, + (dvoid *)&bufaddr, (ub4 *)0, + OCI_ATTR_BUF_ADDR, ctlp->errhp_ctl)); + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ocierr, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpstr_ctl), + OCI_HTYPE_DIRPATH_STREAM, + (dvoid *)&buflen, (ub4 *)0, + OCI_ATTR_BUF_SIZE, ctlp->errhp_ctl)); + write(1, (char *)bufaddr, (int)buflen); + fprintf(output_fp, "Wrote %d bytes from stream\n", (int)buflen); + getRowCnt = FALSE; + } +#endif + + switch (ocierr) + { + case OCI_SUCCESS: + /* all data succcesfully loaded */ + retval = LOAD_SUCCESS; + break; + + case OCI_ERROR: + /* Error occurred while loading: could be a partition mapping + * error, null constraint violation, or an out of space + * condition. In any case, we return the number of rows + * processed (successfully loaded). + */ + retval = LOAD_ERROR; + break; + + case OCI_NEED_DATA: + /* Last row was not complete. + * The caller needs to supply another piece. + */ + retval = LOAD_NEED_DATA; + break; + + case OCI_NO_DATA: + /* the stream was empty */ + retval = LOAD_NO_DATA; + break; + + default: + FATAL("do_load:OCIDirPathLoadStream:Unexpected OCI return code", ocierr); + /* NOTREACHED */ + break; + } + + if (getRowCnt) + { + sword ocierr2; + + OCI_CHECK(ctlp->errhp2_ctl, OCI_HTYPE_ERROR, ocierr2, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpstr_ctl), + OCI_HTYPE_DIRPATH_STREAM, + (dvoid *)loadCntp, (ub4 *)0, + OCI_ATTR_ROW_COUNT, ctlp->errhp2_ctl)); + } + + return retval; +} + + +/* +**++++++++++++++++++++++++++++++ field_flush +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Helper function which cleans up the partial context state, and clears it. +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure pointer +** rowoff column array row offset +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void field_flush(ctlp, rowoff) +struct loadctl *ctlp; /* load control structure pointer */ +ub4 rowoff; /* column array row offset */ +{ + if (ctlp->pctx_ctl.valid_pctx) + { + /* Partial context is valid; make sure the request is + * for the context corresponding to the current row. + */ + assert(rowoff == ctlp->pctx_ctl.row_pctx); + (void) close(ctlp->pctx_ctl.fd_pctx); + free((void *)ctlp->pctx_ctl.fnm_pctx); + } + CLEAR_PCTX(ctlp->pctx_ctl); +} + + +/* +**++++++++++++++++++++++++++++++ field_set +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Sets the input data fields to their corresponding data columns. +** +** Simple field setting. +** Computes address and length of fields in the input record, +** and sets the corresponding column array entry for each input field. +** +** This function only deals with positional fields. +** +** Leading white space is trimmed from the field if FLD_STRIP_LEAD_BLANK +** is set. +** +** Trailing white space is trimmed from the field if FLD_STRIP_TRAIL_BLANK +** is set. +** +** Fields which consist of all spaces are loaded as null columns. +** +** Fields which are marked as FLD_OUTOFLINE are interpreted +** as being file names which can be passed directly to an +** open system call. +** +** NOTES: Discuss how partials are handled. +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure +** tblp table descriptor +** recp input record +** rowoff column array row offset +** bufflg buffer in use flag +** +** Returns: +** +** FIELD_SET_COMPLETE: +** All fields are complete, the partial context is not valid. +** +** FIELD_SET_BUF +** All fields are complete, the partial context is not valid, but +** data is buffered in a secondary buffer and the column array has +** one or more pointers into the secondary buffer. The caller +** must convert the column array to stream format before calling +** this function again. +** +** FIELD_SET_PARTIAL: +** A field is in the partial state, the partial context is valid +** and is required to continue processing the field. Note that +** when a field is partial, the row which contains the column +** corresponding to the field is partial also. +** +** FIELD_SET_ERROR: +** A read error occured on a secondary (out-of-line) data file. +** +**------------------------------------------------------------------------- +*/ + +/* Deal with WIN32 CR-LF weirdness */ +#if defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32) +#define TKPIDRV_OPEN_MODE (O_RDONLY | O_BINARY) +#else +#define TKPIDRV_OPEN_MODE (O_RDONLY) +#endif + +STATICF sword field_set(ctlp, tblp, objp, recp, rowoff, bufflg) +struct loadctl *ctlp; /* load control structure */ +struct tbl *tblp; /* table descriptor */ +struct obj *objp; /* object descriptor */ +text *recp; /* input record */ +ub4 rowoff; /* column array row offset */ +ub1 bufflg; /* buffer in use flag */ +{ + ub1 *cval; + ub4 ncols; + ub4 thiscol; + ub4 clen, j; /* column length */ + ub1 cflg; + sword ociret; + sword done = FALSE; + int fd; /* file descriptor for out-of-line data */ + char *filename; /* filename for out-of-line data */ + sword partial; + static int count = 0; + struct col *cols; + struct fld *flds; + OCIDirPathColArray * ca; + ub4 recsz = 0; /* Current size of record read in */ + ub1 prntflg = 0; /* Print warning message flag */ + ub4 i = 0; + + /* recsz = strlen ((const char *)recp); */ + /* strlen won't work for binary numbers in record. */ + while (!done) + { + for (i = 0; recp[i] != '\n' ; i++) + { + recsz = recsz + 1; + } + done = TRUE; + } + /* Reset the buffer offset if not recursing */ + if (!bufflg) + ctlp->bufoff_ctl = 0; + + if ((partial = (sword)ctlp->pctx_ctl.valid_pctx) == TRUE) + { + /* partial context is valid; resume where we left off */ + assert(rowoff == ctlp->pctx_ctl.row_pctx); + thiscol = ctlp->pctx_ctl.col_pctx; + } + else + thiscol = 0; + + if (objp != 0) + { + cols = objp->col_obj; + flds = objp->fld_obj; + ncols = objp->ncol_obj; + ca = objp->ca_obj; + } + else + { + cols = tblp->col_tbl; + flds = tblp->fld_tbl; + ncols = tblp->ncol_tbl; + ca = ctlp->dpca_ctl; + } + + for (/* empty */; thiscol < ncols; thiscol++) + { + struct col *colp = &cols[thiscol]; + struct fld *fldp = &flds[thiscol]; + + if (partial) + { + /* partials are always from a secondary file */ + fd = ctlp->pctx_ctl.fd_pctx; + filename = ctlp->pctx_ctl.fnm_pctx; + } + else /* !partial*/ + { + fd = -1; + filename = (char *)0; + cval = (ub1 *)recp + fldp->begpos_fld - 1; + + /* + ** Check the field length is not longer than the current record length. + ** If it is, issue a warning and set the clen to the record length - + ** the beginning field position. + */ + if (fldp->endpos_fld > recsz ) + { + if (!prntflg) + { + fprintf(output_fp, + "Warning: Max field length, %d for record %d, is greater than the current record size %d.\n", + fldp->endpos_fld, (rowoff+1), recsz); + prntflg = 1; + } + clen = recsz - fldp->begpos_fld + 1; + } + else + clen = fldp->endpos_fld - fldp->begpos_fld + 1; + + j = 0; + if (bit(fldp->flag_fld, FLD_STRIP_LEAD_BLANK)) + { + /* trim leading white space */ + for (/*empty*/; j < clen; j++) + if (!isspace((int)cval[j])) + break; + } + + if (j >= clen) + clen = 0; /* null column, handled below*/ + else + { + if (bit(fldp->flag_fld, FLD_STRIP_TRAIL_BLANK)) + { + /* trim trailing white space or new line char within field length. */ + while ((clen && isspace((int)cval[clen - 1]))|| + (clen && ((int)cval[clen - 1]== '\n'))) + clen--; + } + cval = cval + j; + clen = clen - j; + } + + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + goto obj; + + if (clen) + { + if (bit(fldp->flag_fld, FLD_INLINE)) + { + cflg = OCI_DIRPATH_COL_COMPLETE; + } + else if (bit(fldp->flag_fld, FLD_OUTOFLINE)) + { + filename = (char *)malloc((size_t)clen+1); + if (!filename) + { + perror("malloc"); + FATAL("field_set: cannot malloc buf for filename", (clen + 1)); + } + (void) memcpy((dvoid *)filename, (dvoid *)cval, (size_t)clen); + filename[clen] = 0; + fd = open(filename, TKPIDRV_OPEN_MODE); + SET_PCTX(ctlp->pctx_ctl, rowoff, thiscol, (ub4)0, fd, filename); + LEN_PCTX(ctlp->pctx_ctl) = 0; + } + else + { + FATAL("field_set: unknown field type", fldp->flag_fld); + } + } + else + { + cflg = OCI_DIRPATH_COL_NULL; /* all spaces become null*/ + cval = (ub1 *)0; + } + } + + if (bit(fldp->flag_fld, FLD_OUTOFLINE)) + { + char *buf; + ub4 bufsz; + int cnt; + + if (!ctlp->buf_ctl) + { + ctlp->buf_ctl = (ub1 *)malloc((size_t)SECONDARY_BUF_SIZE); + ctlp->bufsz_ctl = SECONDARY_BUF_SIZE; + } + + if ((ctlp->bufsz_ctl - ctlp->bufoff_ctl) > SECONDARY_BUF_SLOP) + { + buf = (char *)ctlp->buf_ctl + ctlp->bufoff_ctl; /* buffer pointer*/ + bufsz = (int)ctlp->bufsz_ctl - ctlp->bufoff_ctl; /* buffer size*/ + + if (fd == -1) + cnt = 0; + else + cnt = read(fd, buf, bufsz); + + if (cnt != -1) + { + cval = (ub1 *)buf; + clen = (ub4)cnt; + + if (cnt < bufsz) /* all file data has been read*/ + { + /* mark column as null or complete */ + if (cnt == 0 && LEN_PCTX(ctlp->pctx_ctl) == 0) + cflg = OCI_DIRPATH_COL_NULL; + else + cflg = OCI_DIRPATH_COL_COMPLETE; + + field_flush(ctlp, rowoff); /* close file, free filename*/ + + /* adjust offset into buffer for use by next field */ + ctlp->bufoff_ctl += cnt; + } + else + cflg = OCI_DIRPATH_COL_PARTIAL; + } + else + { + /* XXX: do something on read failure, like return an error context*/ + field_flush(ctlp, rowoff); /* close file, free filename*/ + return FIELD_SET_ERROR; + } + } + else + { + /* no room in secondary buffer, return a 0 length partial + * and pick it up next time. + */ + cflg = OCI_DIRPATH_COL_PARTIAL; + clen = 0; + cval = (ub1 *)NULL; + } + } + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIDirPathColArrayEntrySet(ca, ctlp->errhp_ctl, + rowoff, colp->id_col, + cval, clen, cflg)); + + if (cflg == OCI_DIRPATH_COL_PARTIAL) + { + /* Partials only occur for OutOfLine data + * remember the row offset, column offset, + * total length of the column so far, + * and file descriptor to get data from on + * subsequent calls to this function. + */ + LEN_PCTX(ctlp->pctx_ctl) += clen; + return FIELD_SET_PARTIAL; + } + +obj: + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + /* check for NULL for the whole object. If clen is not empty, then the + * object is not null. + */ + + objp = colp->obj_col; + if (clen) + { + field_set(ctlp, tblp, colp->obj_col, recp, objp->rowoff_obj, 1); + objp->rowoff_obj++; + + /* Set the entry in the parent column array to be the column array + * for the object/ + */ + cflg = OCI_DIRPATH_COL_COMPLETE; + clen = sizeof(objp->ca_obj); + cval = (ub1 *) objp->ca_obj; + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIDirPathColArrayEntrySet(ca, ctlp->errhp_ctl, + rowoff, colp->id_col, + cval, clen, cflg)); + + } + else + { + /* set the entry in the column array to be NULL flag */ + cflg = OCI_DIRPATH_COL_NULL; + clen = 0; + cval = (ub1 *)NULL; + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIDirPathColArrayEntrySet(ca, ctlp->errhp_ctl, + rowoff, colp->id_col, + cval, clen, cflg)); + } + + } + + } /* end of setting attr values in col array */ + + CLEAR_PCTX(ctlp->pctx_ctl); + if (ctlp->bufoff_ctl) /* data in secondary buffer for this row*/ + return FIELD_SET_BUF; + else + return FIELD_SET_COMPLETE; + +} + + +/* +**++++++++++++++++++++++++++++++ errprint +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Assumptions: +** +** Parameters: +** +** errhp +** htype +** errcodep +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void errprint(errhp, htype, errcodep) +dvoid *errhp; +ub4 htype; +sb4 *errcodep; +{ + text errbuf[512]; + + if (errhp) + { + sb4 errcode; + + if (errcodep == (sb4 *)0) + errcodep = &errcode; + + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, errcodep, + errbuf, (ub4) sizeof(errbuf), htype); + (void) fprintf(output_fp, "Error - %.*s\n", 512, errbuf); + } +} + + +/* +**++++++++++++++++++++++++++++++ checkerr +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Assumptions: +** +** Parameters: +** +** errhp +** htype +** status +** note +** code +** file +** line +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void checkerr(errhp, htype, status, note, code, file, line) +dvoid *errhp; +ub4 htype; +sword status; +text *note; +sb4 code; +text *file; +sb4 line; +{ + sb4 errcode = 0; + + if ((status != OCI_SUCCESS)) + (void) fprintf(output_fp, "OCI Error %ld occurred at File %s:%ld\n", + (long)status, (char *)file, (long)line); + + if (note) + (void) fprintf(output_fp, "File %s:%ld (code=%ld) %s\n", + (char *)file, (long)line, (long)code, (char *)note); + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) fprintf(output_fp, "Error - OCI_SUCCESS_WITH_INFO\n"); + errprint(errhp, htype, &errcode); + break; + case OCI_NEED_DATA: + (void) fprintf(output_fp, "Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) fprintf(output_fp, "Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + errprint(errhp, htype, &errcode); + break; + case OCI_INVALID_HANDLE: + (void) fprintf(output_fp, "Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) fprintf(output_fp, "Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) fprintf(output_fp, "Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +/* +**++++++++++++++++++++++++++++++ cleanup +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Frees up handles and exit with the supplied exit status code. +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure pointer +** ex_status +** +** Returns: +** ex_status +** +**------------------------------------------------------------------------- +*/ + +STATICF void cleanup(ctlp, ex_status) +struct loadctl *ctlp; /* load control structure pointer */ +sb4 ex_status; +{ + sword ociret; + + /* Free the column array and stream handles if they have been + * allocated. We don't need to do this since freeing the direct + * path context will free the heap which these child handles have + * been allocated from. I'm doing this just to exercise the code + * path to free these handles. + */ + if (ctlp->dpca_ctl) + { + ociret = OCIHandleFree((dvoid *)ctlp->dpca_ctl, + OCI_HTYPE_DIRPATH_COLUMN_ARRAY); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + + if (ctlp->dpstr_ctl) + { + ociret = OCIHandleFree((dvoid *)ctlp->dpstr_ctl, + OCI_HTYPE_DIRPATH_STREAM); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + + /* free object-related dpapi handles if loading to obj/opq/ref cols */ + if (ctlp->loadobjcol_ctl) + { + ub2 i; + struct col *colp; + struct tbl *tblp = &table; + + for (i = 0, colp = tblp->col_tbl; i < tblp->ncol_tbl; i++, colp++) + { + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + free_obj_hndls(ctlp, colp->obj_col); + + if (colp->obj_col->ca_obj) + { + ociret = OCIHandleFree((dvoid *)(colp->obj_col->ca_obj), + OCI_HTYPE_DIRPATH_FN_COL_ARRAY); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + + if (colp->obj_col->ctx_obj) + { + ociret = OCIHandleFree((dvoid *)(colp->obj_col->ctx_obj), + OCI_HTYPE_DIRPATH_FN_CTX); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + } + } + } + + if (ctlp->dpctx_ctl) + { + ociret = OCIHandleFree((dvoid *)ctlp->dpctx_ctl, OCI_HTYPE_DIRPATH_CTX); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + + if (ctlp->errhp_ctl && ctlp->srvhp_ctl) + { + (void) OCIServerDetach(ctlp->srvhp_ctl, ctlp->errhp_ctl, OCI_DEFAULT ); + ociret = OCIHandleFree((dvoid *)ctlp->srvhp_ctl, OCI_HTYPE_SERVER); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + + if (ctlp->svchp_ctl) + (void) OCIHandleFree((dvoid *) ctlp->svchp_ctl, OCI_HTYPE_SVCCTX); + if (ctlp->errhp_ctl) + (void) OCIHandleFree((dvoid *) ctlp->errhp_ctl, OCI_HTYPE_ERROR); + + if ((output_fp != stdout) && (output_fp != stderr)) + fclose(output_fp); + + exit((int)ex_status); +} + + +/* +**++++++++++++++++++++++++++++ free_obj_hndls +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Frees up dpapi object handles (function column array & function context). +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure pointer +** objp object structure pointer +** +** Returns: +** Nothing. +** +**------------------------------------------------------------------------- +*/ +STATICF void free_obj_hndls(ctlp, objp) +struct loadctl *ctlp; +struct obj *objp; +{ + ub2 i; + struct col *colp; /* column pointer */ + sword ociret; + + for (i = 0, colp = objp->col_obj; i < objp->ncol_obj; i++, colp++) + { + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + free_obj_hndls(ctlp, colp->obj_col); + + if (colp->obj_col->ca_obj) + { + ociret = OCIHandleFree((dvoid *)(colp->obj_col->ca_obj), + OCI_HTYPE_DIRPATH_FN_COL_ARRAY); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + + if (colp->obj_col->ctx_obj) + { + ociret = OCIHandleFree((dvoid *)(colp->obj_col->ctx_obj), + OCI_HTYPE_DIRPATH_FN_CTX); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + } + } +} + +/* +**+++++++++++++++++++++++++set_and_get_attributes++++++++++++++++++++++++++++ +** +** Description: +** This routine has been provided to improve code coverage of +** setting and retrieving direct path attributes via OCI. It +** sets and gets the direct path attributes that are not exercised +** in any other regression test. +** +** Assumptions: +** None +** Parameters: +** ctlp load control structure pointer +** +** Returns: +** Nothing +**------------------------------------------------------------------------- +*/ + +STATICF void set_and_get_attributes(struct loadctl *ctlp, struct tbl *tblp) +{ + sword ociret; + ub1 parallel_opt, nolog_opt, bad_value=100; + ub1 parallel_enabled=0, nolog_enabled=0; + ub1 mode, load_mode = OCI_DIRPATH_LOAD; + ub1 input_type = OCI_DIRPATH_INPUT_TEXT; + ub1 lock_wait, convert_value=1; + ub1 skip_index_maint=OCI_DIRPATH_INDEX_MAINT_SKIP_ALL; + ub2 charsetid=OCI_UTF16ID, ret_charsetid; + ub4 rows_loaded=0, scn_base=0, scn_wrap=0; + ub4 version_text=1, parallel_extent = 100000; + ub4 ret_version, ret_stream_version; + ub4 stream_version = OCI_DIRPATH_STREAM_VERSION_1; + ub4 out_stream_version, stream_offset; + ub4 attr_nam_len=3; + ub4 dcache_size=0, ret_obj_constr_len; + ub8 granule_size=0, granule_offset=512; + text attr_nam[3]={'b','u','y'},obj_constr[3]={'h','i','\0'}; + text *attrp_nam = attr_nam; + text *obj_constr_ptr = obj_constr; + text *ret_obj_constr_ptr; + text fileinfo[16]="doesnt_exist.dat"; + + /* Improve code coverage in the routines, kpusattr and kpugattr, which + * are the routines behind the OCI routines, OCIAttrSet and OCIAttrGet. + */ + + /*********************************************************************** + * This next section of code will SET the following direct path + * attributes: + * dirpath_mode - mode of direct path context (load, convert) + * version - user assigned version + * stream version - version of stream supported + * storage_initial - initial extent size + * storage_next - next extent size + * file - DB file to load into + * charset_id - character set id + * version (associated with direct path stream handle) + * attr_name - attribute name + * obj_constr - object constructor name + * skip_index_maint- index maintenance method + * convert_value - set to 1 to indicate conversion needed + * granule_offset - offset to last granule + */ + + /* Set the dirpath mode to load */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&load_mode, 0, + OCI_ATTR_DIRPATH_MODE, ctlp->errhp_ctl)); + + /* Set the dirpath version to 1 */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&version_text, 0, + OCI_ATTR_VERSION, ctlp->errhp_ctl)); + + /* Set the dirpath stream version to 100 */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&stream_version, 0, + OCI_ATTR_DIRPATH_STREAM_VERSION, ctlp->errhp_ctl)); + + /* Set the storage for the first parallel extent to 100,000 */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)¶llel_extent, 0, + OCI_ATTR_DIRPATH_STORAGE_INITIAL, ctlp->errhp_ctl)); + + /* Set the storage for subsequent parallel extents to 100,000 */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)¶llel_extent, 0, + OCI_ATTR_DIRPATH_STORAGE_NEXT, ctlp->errhp_ctl)); + + /* Initialize parallel file name to dummy name */ + /* Note: The following code to set the parallel file name + * twice is intentional. The 2nd setting of this + * name is to exercise a path where a file name has + * been set and the memory buffer containing this + * name is freed before processing this new input + * file name. + */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&fileinfo, sizeof(fileinfo), + OCI_ATTR_DIRPATH_FILE, ctlp->errhp_ctl)); + + /* Initialize parallel file name to dummy name */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&fileinfo, sizeof(fileinfo), + OCI_ATTR_DIRPATH_FILE, ctlp->errhp_ctl)); + + /* Set the character set id to UTF16*/ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&charsetid, 0, + OCI_ATTR_CHARSET_ID, ctlp->errhp_ctl)); + + /* Set client interface version. */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpstr_ctl), + OCI_HTYPE_DIRPATH_STREAM, + (dvoid *)&stream_version, 0, + OCI_ATTR_VERSION, ctlp->errhp_ctl)); + + /* Set the attribute name to a dummy name. This name attribute is + initialized/set in existing code. This setting here is to exercise + the path where the name has already been set and this is the second + time. */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid **)&attrp_nam, attr_nam_len, + OCI_ATTR_NAME, ctlp->errhp_ctl)); + + /* Set the object constructor name to a dummy name. This name attribute is + initialized/set in existing code. This setting here is to exercise + the path where the name has already been set and this is the second + time. */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)obj_constr_ptr, 0, + OCI_ATTR_DIRPATH_OBJ_CONSTR, ctlp->errhp_ctl)); + + /* Set the attribute, dirpath_index_maint_method, to skip all */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + (ub4)OCI_HTYPE_DIRPATH_CTX, + &skip_index_maint, 0, + OCI_ATTR_DIRPATH_INDEX_MAINT_METHOD, + ctlp->errhp_ctl)); + + /* Set the attribute, dirpath_convert, to 1 (meaning conversion needed) */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + (ub4)OCI_HTYPE_DIRPATH_CTX, + &convert_value, 0, + OCI_ATTR_DIRPATH_CONVERT, ctlp->errhp_ctl)); + + /* Set the size of the granule offset to 512 */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + (ub4)OCI_HTYPE_DIRPATH_CTX, + &granule_offset, 0, + OCI_ATTR_DIRPATH_GRANULE_OFFSET, ctlp->errhp_ctl)); + + /* Exercise several error paths. The OCI_CHECK macro is not used + * since an error is expected as the return status. The attributes + * given are not valid for the specified handle. + */ + + ociret = OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid **) &obj_constr_ptr, + (ub4)strlen((const char *)obj_constr_ptr), + OCI_ATTR_ENV, ctlp->errhp_ctl); + + ociret = OCIAttrSet((dvoid *)(ctlp->dpstr_ctl), + (ub4)OCI_HTYPE_DIRPATH_STREAM, + (dvoid **) &obj_constr_ptr, + (ub4)strlen((const char *)obj_constr_ptr), + OCI_ATTR_ENV, ctlp->errhp_ctl); + + ociret = OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&mode,(ub4 *)0, + OCI_ATTR_ENV, ctlp->errhp_ctl); + + + /*******************************************************************/ + /* Now this section will retrieve (GET) the direct path attributes */ + /*******************************************************************/ + /* Using the direct path context handle, fetch the following + * 15 items: + * direct path mode + * number of rows loaded + * attribute name + * character set id + * nolog + * parallel + * stream version + * version + * dcache_size + * obj_constr + * scn base value + * scn wrap value + * dirpath input format + * granule size for unload + * dirpath value for whether the dpapi should wait for lock + */ + + /* Get the dirpath mode */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&mode,(ub4 *)0, + OCI_ATTR_DIRPATH_MODE, ctlp->errhp_ctl)); + + /* Verify the mode. */ + if (mode != load_mode) + { + fprintf(output_fp, + "ERROR: expected direct path load mode of %d, got %d\n", + load_mode, mode); + } + + /* Get the number of rows loaded */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + &rows_loaded,(ub4 *)0, + OCI_ATTR_NUM_ROWS, ctlp->errhp_ctl)); + + /* Then write this value back to the attribute - expect error on return*/ + + ociret = OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + &rows_loaded, (ub4)0, + OCI_ATTR_NUM_ROWS, ctlp->errhp_ctl); + + /* Get the attribute name */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid **)&attrp_nam, &attr_nam_len, + OCI_ATTR_NAME, ctlp->errhp_ctl)); + + + /* Get the character set id */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&ret_charsetid,(ub4 *)0, + OCI_ATTR_CHARSET_ID, ctlp->errhp_ctl)); + + /* Verify the character set id. */ + if (charsetid != ret_charsetid) + { + fprintf(output_fp, + "ERROR: expected character set id of %d, got %d\n", + charsetid, ret_charsetid); + } + + /* Is parallelism enabled? */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(ctlp->dpctx_ctl), (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)¶llel_opt, + (ub4 *)0, (ub4)OCI_ATTR_DIRPATH_PARALLEL, + ctlp->errhp_ctl)); + + if (tblp->parallel_tbl) parallel_enabled = TRUE; + + /* Verify that the correct setting for parallel was returned. */ + if (parallel_opt != parallel_enabled) + { + fprintf(output_fp, + "ERROR: expected parallel value of %d, got %d\n", + parallel_enabled, parallel_opt); + } + + /* Logging enabled? */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(ctlp->dpctx_ctl), (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&nolog_opt, (ub4 *)0, + (ub4)OCI_ATTR_DIRPATH_NOLOG, ctlp->errhp_ctl)); + + if (tblp->nolog_tbl) nolog_enabled = TRUE; + + /* Verify that the correct value for nolog was returned. */ + if (nolog_opt != nolog_enabled) + { + fprintf(output_fp, + "ERROR: expected value of nolog to be %d, got %d\n", + nolog_enabled, nolog_opt); + } + + /* Get the version of the server interface for dirpath */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&ret_version,(ub4 *)0, + OCI_ATTR_VERSION, ctlp->errhp_ctl)); + + + /* Get the dirpath stream version */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&ret_stream_version,(ub4 *)0, + OCI_ATTR_DIRPATH_STREAM_VERSION, ctlp->errhp_ctl)); + + /* Verify the stream version number. */ + if (stream_version != ret_stream_version) + { + fprintf(output_fp, + "ERROR: expected direct path stream version of %d, got %d\n", + stream_version, ret_stream_version); + } + + /* Get the object constructor name */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(ctlp->dpctx_ctl), + (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid **) &ret_obj_constr_ptr, &ret_obj_constr_len, + (ub4)OCI_ATTR_DIRPATH_OBJ_CONSTR, ctlp->errhp_ctl)); + + /* Verify the object constructor name. First check string length. */ + if (ret_obj_constr_len != strlen((const char *)obj_constr_ptr)) + { + fprintf(output_fp, "ERROR: bad object constructor name len\n"); + fprintf(output_fp, "\texpected %d, got %d\n", + strlen((const char *)obj_constr_ptr), ret_obj_constr_len); + } + + if (strncmp((const char *)obj_constr_ptr, + (const char *)ret_obj_constr_ptr, (size_t)ret_obj_constr_len)) + { + fprintf(output_fp,"*** ERROR *** bad object constructor name\n"); + fprintf(output_fp, "\texpected %s, got %s\n", + (char *)obj_constr_ptr, (char *)ret_obj_constr_ptr); + } + + /* Get the max. size of date cache */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&dcache_size, (ub4 *)0, + OCI_ATTR_DIRPATH_DCACHE_SIZE, ctlp->errhp_ctl)); + + /* Retrieve the SCN base and wrap values */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + &scn_base, (ub4 *)0, + OCI_ATTR_SCN_BASE, ctlp->errhp_ctl)); + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + &scn_wrap, (ub4 *)0, + OCI_ATTR_SCN_WRAP, ctlp->errhp_ctl)); + + /* Get the format of the input data (stream or text) */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + &input_type, (ub4 *)0, + OCI_ATTR_DIRPATH_INPUT, ctlp->errhp_ctl)); + + /* Was it the size of a granule for an unload operation? */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + &granule_size, (ub4 *)0, + OCI_ATTR_DIRPATH_GRANULE_SIZE, ctlp->errhp_ctl)); + + /* Is the dpapi going to wait to acquire a lock that is held? */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + &lock_wait, (ub4 *)0, + OCI_ATTR_DIRPATH_LOCK_WAIT, ctlp->errhp_ctl)); + + /*******************************************************************/ + /* Using the direct path stream handle, fetch the stream version and + * offset + */ + + /* First, the stream version */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpstr_ctl), + OCI_HTYPE_DIRPATH_STREAM, + &out_stream_version, (ub4 *)0, + OCI_ATTR_VERSION, ctlp->errhp_ctl)); + + /* Verify the stream version number. */ + if (stream_version != out_stream_version) + { + fprintf(output_fp, + "ERROR: expected (using stream handle) a stream version of %d, got %d\n", + stream_version, out_stream_version); + } + + /* Now the stream offset */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpstr_ctl), + OCI_HTYPE_DIRPATH_STREAM, + &stream_offset, (ub4 *)0, + OCI_ATTR_STREAM_OFFSET, ctlp->errhp_ctl)); + + + /* Now the default case - generates an error since the attribute + type is not valid for this handle. */ + + ociret = OCIAttrGet((CONST dvoid *)(ctlp->dpstr_ctl), + OCI_HTYPE_DIRPATH_STREAM, + &stream_offset, (ub4 *)0, + OCI_ATTR_DATEFORMAT, ctlp->errhp_ctl); + + +} + + +/* +**++++++++++++++++++++++++++++++ reset_obj_ca +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Function resets the column arrays for any objects or nested object columns. +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure pointer +** tblp table pointer +** objp object pointer +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void reset_obj_ca(ctlp, tblp, objp) +struct loadctl *ctlp; /* load control structure */ +struct tbl *tblp; /* table descriptor */ +struct obj *objp; /* object descriptor */ +{ + struct col *colp; + ub2 i; + + (void) OCIDirPathColArrayReset(objp->ca_obj, ctlp->errhp_ctl); + + objp->rowoff_obj = 0; + + /* check each column to see if it is an object, opaque or ref */ + /* and if so, recurse */ + for (i = 0, colp = objp->col_obj; i < objp->ncol_obj; i++, colp++) + { + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + reset_obj_ca(ctlp, tblp, colp->obj_col); + } + } + +} + +/* end of file cdemodp.c */ diff --git a/cdemodp.h b/cdemodp.h new file mode 100644 index 0000000..a934b0d --- /dev/null +++ b/cdemodp.h @@ -0,0 +1,114 @@ +/* + * $Header: cdemodp.h 16-feb-2004.10:53:40 eegolf Exp $ + */ + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* Copyright (c) 2004, 20001, Oracle Corporation. All rights reserved. */ +/* All Rights Reserved. */ +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +/* +** NAME: +** cdemodp.h - C Demo prog for Direct Path api +** +** DESCRIPTION: +** - Common header file for cdemodp driver and client progs. +** +** NOTES: +** +** +** MODIFIED (MM/DD/YY) +** eegolf 02/16/04 - Fix for bug 3441006, change "table" variable name +** cmlim 04/03/01 - remove flag_tbl field +** +** eegolf 02/21/01 - added new 9i items +** cmlim 09/16/98 - Creation +** +*/ + + +#ifndef cdemodp_ORACLE +# define cdemodp_ORACLE + +# include + +# ifndef externdef +# define externdef +# endif + +/* External column attributes */ +struct col +{ + text *name_col; /* column name */ + ub2 id_col; /* column load id */ + ub2 exttyp_col; /* external type */ + text *datemask_col; /* datemask, if applicable */ + ub1 prec_col; /* precision, if applicable */ + sb1 scale_col; /* scale, if applicable */ + ub2 csid_col; /* character set id */ + ub1 date_col; /* is column a chrdate or date? 1=TRUE. 0=FALSE */ + struct obj * obj_col; /* description of object, if applicable */ +#define COL_OID 0x1 /* col is an OID */ + ub4 flag_col; +}; + +/* Input field descriptor + * For this example (and simplicity), + * fields are strictly positional. + */ +struct fld +{ + ub4 begpos_fld; /* 1-based beginning position */ + ub4 endpos_fld; /* 1-based ending position */ + ub4 maxlen_fld; /* max length for out of line field */ + ub4 flag_fld; +#define FLD_INLINE 0x1 +#define FLD_OUTOFLINE 0x2 +#define FLD_STRIP_LEAD_BLANK 0x4 +#define FLD_STRIP_TRAIL_BLANK 0x8 +}; + +struct obj +{ + text *name_obj; /* type name*/ + ub2 ncol_obj; /* number of columns in col_obj*/ + struct col *col_obj; /* column attributes*/ + struct fld *fld_obj; /* field descriptor*/ + ub4 rowoff_obj; /* current row offset in the column array*/ + ub4 nrows_obj; /* number of rows in col array*/ + OCIDirPathFuncCtx *ctx_obj; /* Function context for this obj column*/ + OCIDirPathColArray *ca_obj; /* column array for this obj column*/ + ub4 flag_obj; /* type of obj */ +#define OBJ_OBJ 0x1 /* obj col */ +#define OBJ_OPQ 0x2 /* opaque/sql str col */ +#define OBJ_REF 0x4 /* ref col */ +}; + +struct tbl +{ + text *owner_tbl; /* table owner */ + text *name_tbl; /* table name */ + text *subname_tbl; /* subname, if applicable */ + ub2 ncol_tbl; /* number of columns in col_tbl */ + text *dfltdatemask_tbl; /* table level default date mask */ + struct col *col_tbl; /* column attributes */ + struct fld *fld_tbl; /* field descriptor */ + ub1 parallel_tbl; /* parallel: 1 for true */ + ub1 nolog_tbl; /* no logging: 1 for true */ + ub4 xfrsz_tbl; /* transfer buffer size in bytes */ + text *objconstr_tbl; /* obj constr/type if loading a derived obj */ +}; + +struct sess /* options for a direct path load session */ +{ + text *username_sess; /* user */ + text *password_sess; /* password */ + text *inst_sess; /* remote instance name */ + text *outfn_sess; /* output filename */ + ub4 maxreclen_sess; /* max size of input record in bytes */ +}; + + +#define table table1 /* Bug 3441006 can't use "table" */ + /* for compile on HP Tru64 unix */ +#endif /* cdemodp_ORACLE */ diff --git a/cdemodp0.h b/cdemodp0.h new file mode 100644 index 0000000..db7efec --- /dev/null +++ b/cdemodp0.h @@ -0,0 +1,109 @@ +/* + * $Header: cdemodp0.h 14-jul-99.12:43:24 mjaeger Exp $ + */ + +/* Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + NAME + cdemodp0.h - C Demo program for Direct Path api + + DESCRIPTION + - Internal data structs, macros, & defines for cdemodp driver. + + NOTES + Structures, macros, constants used only by cdemodp.c. + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + abrumm 12/22/98 - lint + cmlim 11/17/98 - take away hardcoded MAX_RECLEN; now a session parm + cmlim 10/06/98 - correct typo + cmlim 10/02/98 - added externref + cmlim 09/16/98 - internal data structs, macros, & defines for cdemodp + cmlim 09/16/98 - Creation (abrumm 04/07/98) + +*/ + + +#ifndef cdemodp0_ORACLE +# define cdemodp0_ORACLE + +# include +# include + +/* partial field context structure, maintained by field setting function */ +struct pctx +{ + ub1 valid_pctx; /* partial context is valid */ + ub4 pieceCnt_pctx; /* count of partial pieces */ + ub4 row_pctx; /* which row in column array */ + ub4 col_pctx; /* which column in column array */ + ub4 len_pctx; /* length of this column so far */ + int fd_pctx; /* open file descriptor data is coming from */ + char *fnm_pctx; /* filename for data source */ +}; + +/* CLEAR_PCTX(struct pctx pctx) + * Macro to clear the partial context state + */ +#define CLEAR_PCTX(pctx) \ + ((pctx).valid_pctx = FALSE, (pctx).pieceCnt_pctx = 0, \ + (pctx).row_pctx = UB4MAXVAL, (pctx).col_pctx = UB4MAXVAL, \ + (pctx).len_pctx = 0, (pctx).fd_pctx = -1, \ + (pctx).fnm_pctx = (char *)0) + +#define SET_PCTX(pctx, rowoff, coloff, clen, fd, fnm) \ + ((pctx).valid_pctx = TRUE, (pctx).pieceCnt_pctx++, \ + (pctx).row_pctx = (rowoff), (pctx).col_pctx = (coloff), \ + (pctx).len_pctx += (ub4)(clen), (pctx).fd_pctx = (fd), \ + (pctx).fnm_pctx = (fnm)) + +#define LEN_PCTX(pctx) ((pctx).len_pctx) + +/* Does the input record correspond to the first piece of a row? + * Note that a row which is not pieced is a first piece too. + */ +#define FIRST_PIECE(pctx) \ +( (pctx).valid_pctx == FALSE || \ + ((pctx).valid_pctx == TRUE && ((pctx).pieceCnt_pctx == 1))) + +/* return values from field_set() */ +#define FIELD_SET_COMPLETE 0 +#define FIELD_SET_ERROR 1 +#define FIELD_SET_BUF 2 +#define FIELD_SET_PARTIAL 3 + +/* return values from do_convert() */ +#define CONVERT_SUCCESS 0 +#define CONVERT_ERROR 1 +#define CONVERT_NEED_DATA 2 +#define CONVERT_CONTINUE 3 + +/* return values from do_load() */ +#define LOAD_SUCCESS 0 +#define LOAD_ERROR 1 +#define LOAD_NEED_DATA 2 +#define LOAD_NO_DATA 3 + +/* state values for simple_load() */ +#define RESET 1 /* initial state, reset data structures to empty */ +#define GET_RECORD 2 /* get input records */ +#define FIELD_SET 3 /* assign fields of input records to columns */ +#define DO_CONVERT 4 /* convert column array input to stream format */ +#define DO_LOAD 5 /* load the direct stream */ +#define END_OF_INPUT 6 /* no more input data */ + +/* Secondary buffer sizes for OUTOFLINE fields; no science here, just a WAG */ +#define SECONDARY_BUF_SIZE (1024*1024) /* size of secondary buffer */ +#define SECONDARY_BUF_SLOP (8*1024) /* get another field if this much avail */ + +#define STATICF + +#ifndef externref +# define externref extern +#endif + + +#endif /* cdemodp0_ORACLE */ diff --git a/cdemodp_lip.c b/cdemodp_lip.c new file mode 100644 index 0000000..e3f9eee --- /dev/null +++ b/cdemodp_lip.c @@ -0,0 +1,171 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodp_lip.c 15-aug-2006.09:24:35 jkaloger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 2006, Oracle. All rights reserved. +*/ + +/* + * -- cdemodp_lip.c -- + * An example program that loads data via direct path api. + * + * Directions: + * 1. make -f demo_rdbms.mk build_dp EXE=cdemodp_lip OBJS=cdemodp_lip.o + * <== make cdemodp_lip executable + * 2. sqlplus scott/tiger @cdemodp_lip.sql <== create lineitem_dp tbl + * 3. cdemodp_lip < cdemodp_lip.dat <== run executable + * 4. to retrieve data, select from "lineitem_dp" as "scott/tiger" + * + */ + +/* + NAME + cdemodp_lip.c - C Demo for Direct Path api for LineItem Partitioned + table. + + DESCRIPTION + - A client module describing lineitem partition table. + To be used with cdemodp driver prog. + + NOTES + Loads the lineitem1 partition of the lineitem table. + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + msakayed 04/07/03 - fix max_len for l_shipinstruct + cmlim 09/11/01 - fix lint + svedala 01/07/00 - use "DD-MON-RR" mask for date fields + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + cmlim 06/07/99 - set date_col to indicate if col is chrdate or date + abrumm 12/22/98 - account for change to sess structure + cmlim 11/17/98 - add attributes and session options + cmlim 10/11/98 - add directions for running demo program + abrumm 10/14/98 - only table needs to be extern + cmlim 10/02/98 - remove sn.h + cmlim 09/16/98 - a client module (lineitem partition tbl) for cdemodp + cmlim 09/16/98 - Creation + */ +#include +#include +#include + +externdef struct col column[] = +{ + { + (text *)"l_orderkey", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_partkey", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_suppkey", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_linenumber", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_quantity", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_extendedprice", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_discount", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_tax", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_returnflag", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_linestatus", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_shipdate", 0, SQLT_CHR, (text *) "DD-MON-RR", + (sword)0, (sword)0, (ub2)0, (ub1)1 + }, + { + (text *)"l_commitdate", 0, SQLT_CHR, (text *) "DD-MON-RR", + (sword)0, (sword)0, (ub2)0, (ub1)1 + }, + { + (text *)"l_receiptdate", 0, SQLT_CHR, (text *) "DD-MON-RR", + (sword)0, (sword)0, (ub2)0, (ub1)1 + }, + { + (text *)"l_shipinstruct", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_shipmode", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_comment", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 6, 6, FLD_INLINE }, /* l_orderkey */ + { 7, 11, 5, FLD_INLINE }, /* l_partkey */ + { 12, 15, 4, FLD_INLINE }, /* l_suppkey */ + { 16, 16, 1, FLD_INLINE }, /* l_linenumber */ + { 17, 18, 2, FLD_INLINE }, /* l_quantity */ + { 19, 26, 8, FLD_INLINE }, /* l_extendedprice */ + { 27, 29, 3, FLD_INLINE }, /* l_discount */ + { 30, 32, 3, FLD_INLINE }, /* l_tax */ + { 33, 33, 1, FLD_INLINE }, /* l_returnflag */ + { 34, 34, 1, FLD_INLINE }, /* l_linestatus */ + { 35, 43, 9, FLD_INLINE }, /* l_shipdate */ + { 44, 52, 9, FLD_INLINE }, /* l_commitdate */ + { 53, 61, 9, FLD_INLINE }, /* l_receiptdate */ + { 62, 78, 17, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* l_shipinstruct */ + { 79, 85, 7, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* l_shipmode */ + { 86,128, 43, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* l_comment */ +}; + +/* Note setting of subname field */ +externdef struct tbl table = +{ + (text *)"scott", /* table owner */ + (text *)"lineitem_dp", /* table name */ + (text *)"lineitem1", /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024) /* transfer buffer size */ +}; + +externdef struct sess session = +{ + (text *)"scott", /* user */ + (text *)"tiger", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemodp_lip.c */ + diff --git a/cdemodr1.c b/cdemodr1.c new file mode 100644 index 0000000..1fe09f7 --- /dev/null +++ b/cdemodr1.c @@ -0,0 +1,1318 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodr1.c 14-jul-99.13:07:43 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemord1.c - C DEMO program for DML with RETURNING clause - #1. + + DESCRIPTION + This Demo program demonstrates the use of INSERT/UPDATE/DELETE + statements with a RETURNING clause in it. + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + Adopted from tkp8rv1.c; need to run cdemodr1.sql before running + this demo program. + + MODIFIED (MM/DD/YY) + svedala 10/18/99 - + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + azhao 08/19/97 - remove explicit bindhp allocation + echen 07/30/97 - fix bug 516406 + azhao 05/30/97 - Creation + +*/ + +#include + +/*------------------------ Global Variables -------------------------------*/ + +static boolean logged_on = FALSE; + +/* TAB1 columns */ +static int in1[MAXITER]; /* for INTEGER */ +static text in2[MAXITER][40]; /* for CHAR(40) */ +static text in3[MAXITER][40]; /* for VARCHAR2(40) */ +static float in4[MAXITER]; /* for FLOAT */ +static int in5[MAXITER]; /* for DECIMAL */ +static float in6[MAXITER]; /* for DECIMAL(8,3) */ +static int in7[MAXITER]; /* for NUMERIC */ +static float in8[MAXITER]; /* for NUMERIC(7,2) */ +static ub1 in9[MAXITER][7]; /* for DATE */ +static ub1 in10[MAXITER][40]; /* for RAW(40) */ + +/* output buffers */ +static int *p1[MAXITER]; /* for INTEGER */ +static text *p2[MAXITER]; /* for CHAR(40) */ +static text *p3[MAXITER]; /* for VARCHAR2(40) */ +static float *p4[MAXITER]; /* for FLOAT */ +static int *p5[MAXITER]; /* for DECIMAL */ +static float *p6[MAXITER]; /* for DECIMAL(8,3) */ +static int *p7[MAXITER]; /* for NUMERIC */ +static float *p8[MAXITER]; /* for NUMERIC(7,2) */ +static ub1 *p9[MAXITER]; /* for DATE */ +static ub1 *p10[MAXITER]; /* for RAW(40) */ + +static short *ind[MAXCOLS][MAXITER]; /* indicators */ +static ub2 *rc[MAXCOLS][MAXITER]; /* return codes */ +static ub4 *rl[MAXCOLS][MAXITER]; /* return lengths */ + +/* skip values for binding TAB1 */ +static ub4 s1 = (ub4) sizeof(in1[0]); +static ub4 s2 = (ub4) sizeof(in2[0]); +static ub4 s3 = (ub4) sizeof(in3[0]); +static ub4 s4 = (ub4) sizeof(in4[0]); +static ub4 s5 = (ub4) sizeof(in5[0]); +static ub4 s6 = (ub4) sizeof(in6[0]); +static ub4 s7 = (ub4) sizeof(in7[0]); +static ub4 s8 = (ub4) sizeof(in8[0]); +static ub4 s9 = (ub4) sizeof(in9[0]); +static ub4 s10= (ub4) sizeof(in10[0]); + +/* Rows returned in each iteration */ +static ub2 rowsret[MAXITER]; + +/* indicator skips */ +static ub4 indsk[MAXCOLS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +/* return length skips */ +static ub4 rlsk[MAXCOLS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +/* return code skips */ +static ub4 rcsk[MAXCOLS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +static int lowc1[MAXITER], highc1[MAXITER]; + +static ub4 pos[MAXCOLS]; + +static OCIError *errhp; + +/*------------------------end of Global variables--------------------*/ + + +/*========================== UTILITY FUNCTIONS ======================*/ +/* + * These functions are generic functions that can be used in any + * OCI program. + */ + +/* ----------------------------------------------------------------- */ +/* Initialize environment, allocate handles */ +/* ----------------------------------------------------------------- */ +sword init_handles(envhp, svchp, errhp, srvhp, authp, init_mode) +OCIEnv **envhp; +OCISvcCtx **svchp; +OCIError **errhp; +OCIServer **srvhp; +OCISession **authp; +ub4 init_mode; +{ + (void) printf("Environment setup ....\n"); + + /* Initialize the OCI Process */ + if (OCIInitialize(init_mode, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + /* Inititialize the OCI Environment */ + if (OCIEnvInit((OCIEnv **) envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + /* Allocate a service handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on svchp\n"); + return OCI_ERROR; + } + + /* Allocate an error handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on errhp\n"); + return OCI_ERROR; + } + + /* Allocate a server handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on srvhp\n"); + return OCI_ERROR; + } + + /* Allocate a authentication handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on authp\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/* ----------------------------------------------------------------- */ +/* Attach to server with a given mode. */ +/* ----------------------------------------------------------------- */ +sword attach_server(mode, srvhp, errhp, svchp) +ub4 mode; +OCIServer *srvhp; +OCIError *errhp; +OCISvcCtx *svchp; +{ + text *cstring = (text *)""; + + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + /* Set the server handle in the service handle */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet() server attribute\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} +/* ----------------------------------------------------------------- */ +/* Logon to the database using given username, password & credentials*/ +/* ----------------------------------------------------------------- */ +sword log_on(authp, errhp, svchp, uid, pwd, credt, mode) +OCISession *authp; +OCIError *errhp; +OCISvcCtx *svchp; +text *uid; +text *pwd; +ub4 credt; +ub4 mode; +{ + /* Set attributes in the authentication handle */ + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *) uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet() userid\n"); + return OCI_ERROR; + } + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *) pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + (void) printf("Logging on as %s ....\n", uid); + + if (OCISessionBegin(svchp, errhp, authp, credt, mode)) + { + (void) printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + (void) printf("%s logged on.\n", uid); + + /* Set the authentication handle in the Service handle */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet() session\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/*---------------------------------------------------------------------*/ +/* Allocate all required bind handles */ +/*---------------------------------------------------------------------*/ + +sword init_bind_handle(stmthp, bndhp, nbinds) +OCIStmt *stmthp; +OCIBind *bndhp[]; +int nbinds; +{ + int i; + /* + * This function init the specified number of bind handles + * from the given statement handle. + */ + for (i = 0; i < nbinds; i++) + bndhp[i] = (OCIBind *) 0; + + return OCI_SUCCESS; +} + +/* ----------------------------------------------------------------- */ +/* Print the returned raw data. */ +/* ----------------------------------------------------------------- */ +void print_raw(raw, rawlen) +ub1 *raw; +ub4 rawlen; +{ + ub4 i; + ub4 lim; + ub4 clen = 0; + + if (rawlen > 120) + { + ub4 llen = rawlen; + + while (llen > 120) + { + lim = clen + 120; + for(i = clen; i < lim; ++i) + (void) printf("%02.2x", (ub4) raw[i] & 0xFF); + + (void) printf("\n"); + llen -= 120; + clen += 120; + } + lim = clen + llen; + } + else + lim = rawlen; + + for(i = clen; i < lim; ++i) + (void) printf("%02.2x", (ub4) raw[i] & 0xFF); + + (void) printf("\n"); + + return; +} + +/* ----------------------------------------------------------------- */ +/* Free the specified handles */ +/* ----------------------------------------------------------------- */ +void free_handles(envhp, svchp, srvhp, errhp, authp, stmthp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +OCIStmt *stmthp; +{ + (void) printf("Freeing handles ...\n"); + + if (srvhp) + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + if (authp) + (void) OCIHandleFree((dvoid *) authp, (ub4) OCI_HTYPE_SESSION); + if (stmthp) + (void) OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT); + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV); + + return; +} + +/* ----------------------------------------------------------------- */ +/* Print the error message */ +/* ----------------------------------------------------------------- */ +void report_error(errhp) +OCIError *errhp; +{ + text msgbuf[512]; + sb4 errcode = 0; + + (void) OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("ERROR CODE = %d\n", errcode); + (void) printf("%.*s\n", 512, msgbuf); + return; +} + +/*-------------------------------------------------------------------*/ +/* Logout and detach from the server */ +/*-------------------------------------------------------------------*/ +void logout_detach_server(svchp, srvhp, errhp, authp, userid) +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +text *userid; +{ + if (OCISessionEnd(svchp, errhp, authp, (ub4) 0)) + { + (void) printf("FAILED: OCISessionEnd()\n"); + report_error(errhp); + } + + (void) printf("%s Logged off.\n", userid); + + if (OCIServerDetach(srvhp, errhp, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionEnd()\n"); + report_error(errhp); + } + + (void) printf("Detached from server.\n"); + + return; +} + +/*---------------------------------------------------------------------*/ +/* Finish demo and clean up */ +/*---------------------------------------------------------------------*/ +sword finish_demo(loggedon, envhp, svchp, srvhp, errhp, authp, stmthp, userid) +boolean loggedon; +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +OCIStmt *stmthp; +text *userid; +{ + + if (loggedon) + logout_detach_server(svchp, srvhp, errhp, authp, userid); + + free_handles(envhp, svchp, srvhp, errhp, authp, stmthp); + + return OCI_SUCCESS; +} + +/*===================== END OF UTILITY FUNCTIONS ======================*/ + +/*========================= MAIN ======================================*/ +int main(argc, argv) +int argc; +char *argv[]; +{ + text *username = (text *)"scott"; + text *password = (text *)"tiger"; + + OCIEnv *envhp; + OCIServer *srvhp; + OCISvcCtx *svchp; + OCISession *authp; + OCIStmt *stmthp = (OCIStmt *) NULL; + OCIBind *bndhp[MAXBINDS]; + int i; + + + /* Initialize the Environment and allocate handles */ + if (init_handles(&envhp, &svchp, &errhp, &srvhp, &authp, (ub4)OCI_DEFAULT)) + { + (void) printf("FAILED: init_handles()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + /* Attach to the database server */ + if (attach_server((ub4) OCI_DEFAULT, srvhp, errhp, svchp)) + { + (void) printf("FAILED: attach_server()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + /* Logon to the server and begin a session */ + if (log_on(authp, errhp, svchp, username, password, + (ub4) OCI_CRED_RDBMS, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: log_on()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + logged_on = TRUE; + + /* Allocate a statement handle */ + if (OCIHandleAlloc((dvoid *)envhp, (dvoid **) &stmthp, + (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: alloc statement handle\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + /* bind handles will be implicitly allocated in the bind calls */ + /* need to initialize them to null prior to first usage in bind calls */ + + for (i = 0; i < MAXBINDS; i++) + bndhp[i] = (OCIBind *) 0; + + /* Demonstrate INSERT with RETURNING clause */ + if (demo_insert(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: demo_insert()\n"); + else + (void) printf("SUCCESS: demo_insert()\n"); + + /* Demonstrate UPDATE with RETURNING clause */ + if (demo_update(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: demo_update()\n"); + else + (void) printf("SUCCESS: demo_update()\n"); + + /* Demonstrate DELETE with RETURNING clause */ + if (demo_delete(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: demo_delete()\n"); + else + (void) printf("SUCCESS: demo_delete()\n"); + + /* clean up */ + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); +} + +/* =================== End Main =====================================*/ + +/* ===================== Local Functions ============================*/ +/* ----------------------------------------------------------------- */ +/* bind all the columns of TAB1 by positions. */ +/* ----------------------------------------------------------------- */ +static sword bind_pos(OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp) +{ + + if (OCIBindByPos(stmthp, &bndhp[0], errhp, (ub4) 1, + (dvoid *) &in1[0], (sb4) sizeof(in1[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[1], errhp, (ub4) 2, + (dvoid *) in2[0], (sb4) sizeof(in2[0]), SQLT_AFC, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[2], errhp, (ub4) 3, + (dvoid *) in3[0], (sb4) sizeof(in3[0]), SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[3], errhp, (ub4) 4, + (dvoid *) &in4[0], (sb4) sizeof(in4[0]), SQLT_FLT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[4], errhp, (ub4) 5, + (dvoid *) &in5[0], (sb4) sizeof(in5[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[5], errhp, (ub4) 6, + (dvoid *) &in6[0], (sb4) sizeof(in6[0]), SQLT_FLT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[6], errhp, (ub4) 7, + (dvoid *) &in7[0], (sb4) sizeof(in7[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[7], errhp, (ub4) 8, + (dvoid *) &in8[0], (sb4) sizeof(in8[0]), SQLT_FLT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[8], errhp, (ub4) 9, + (dvoid *) in9[0], (sb4) sizeof(in9[0]), SQLT_DAT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[9], errhp, (ub4) 10, + (dvoid *) in10[0], (sb4) sizeof(in10[0]), SQLT_BIN, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* bind all the columns of TAB1 by name. */ +/* ----------------------------------------------------------------- */ +static sword bind_name(OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp) +{ + + if (OCIBindByName(stmthp, &bndhp[10], errhp, + (text *) ":out1", (sb4) strlen((char *) ":out1"), + (dvoid *) 0, (sb4) sizeof(int), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[11], errhp, + (text *) ":out2", (sb4) strlen((char *) ":out2"), + (dvoid *) 0, (sb4) MAXCOLLEN, SQLT_AFC, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[12], errhp, + (text *) ":out3", (sb4) strlen((char *) ":out3"), + (dvoid *) 0, (sb4) MAXCOLLEN, SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[13], errhp, + (text *) ":out4", (sb4) strlen((char *) ":out4"), + (dvoid *) 0, (sb4) sizeof(float), SQLT_FLT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[14], errhp, + (text *) ":out5", (sb4) strlen((char *) ":out5"), + (dvoid *) 0, (sb4) sizeof(int), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[15], errhp, + (text *) ":out6", (sb4) strlen((char *) ":out6"), + (dvoid *) 0, (sb4) sizeof(float), SQLT_FLT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[16], errhp, + (text *) ":out7", (sb4) strlen((char *) ":out7"), + (dvoid *) 0, (sb4) sizeof(int), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[17], errhp, + (text *) ":out8", (sb4) strlen((char *) ":out8"), + (dvoid *) 0, (sb4) sizeof(float), SQLT_FLT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[18], errhp, + (text *) ":out9", (sb4) strlen((char *) ":out9"), + (dvoid *) 0, (sb4) DATBUFLEN, SQLT_DAT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[19], errhp, + (text *) ":out10", (sb4) strlen((char *) ":out10"), + (dvoid *) 0, (sb4) MAXCOLLEN, SQLT_BIN, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC)) + { + (void) printf("FAILED: OCIBindByName()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* bind array structs for TAB1 columns. */ +/* ----------------------------------------------------------------- */ +static sword bind_array(OCIBind *bndhp[], OCIError *errhp) +{ + if (OCIBindArrayOfStruct(bndhp[0], errhp, s1, indsk[0], rlsk[0], rcsk[0]) + || OCIBindArrayOfStruct(bndhp[1], errhp, s2, indsk[1], rlsk[1], rcsk[1]) + || OCIBindArrayOfStruct(bndhp[2], errhp, s3, indsk[2], rlsk[2], rcsk[2]) + || OCIBindArrayOfStruct(bndhp[3], errhp, s4, indsk[3], rlsk[3], rcsk[3]) + || OCIBindArrayOfStruct(bndhp[4], errhp, s5, indsk[4], rlsk[4], rcsk[4]) + || OCIBindArrayOfStruct(bndhp[5], errhp, s6, indsk[5], rlsk[5], rcsk[5]) + || OCIBindArrayOfStruct(bndhp[6], errhp, s7, indsk[6], rlsk[6], rcsk[6]) + || OCIBindArrayOfStruct(bndhp[7], errhp, s8, indsk[7], rlsk[7], rcsk[7]) + || OCIBindArrayOfStruct(bndhp[8], errhp, s9, indsk[8], rlsk[8], rcsk[8]) + || OCIBindArrayOfStruct(bndhp[9], errhp, s10, indsk[9], rlsk[9], rcsk[9])) + { + (void) printf("FAILED: OCIBindArrayOfStruct()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* bind dynamic for returning TAB1 columns. */ +/* ----------------------------------------------------------------- */ +static sword bind_dynamic(OCIBind *bndhp[], OCIError *errhp) +{ + /* + * Note here that both IN & OUT BIND callback functions have to be + * provided. However, since the bind variables in the RETURNING + * clause are pure OUT Binds the IN callback fuctions (cbf_no_data) + * is essentially a "do-nothing" function. + * + * Also note here that although in this demonstration the IN and OUT + * callback functions are same, in practice you can have a different + * callback function for each bind handle. + */ + + ub4 i; + + for (i = 0; i < MAXCOLS; i++) + pos[i] = i; + + if (OCIBindDynamic(bndhp[10], errhp, (dvoid *) &pos[0], cbf_no_data, + (dvoid *) &pos[0], cbf_get_data) + || OCIBindDynamic(bndhp[11], errhp, (dvoid *) &pos[1], cbf_no_data, + (dvoid *) &pos[1], cbf_get_data) + || OCIBindDynamic(bndhp[12], errhp, (dvoid *) &pos[2], cbf_no_data, + (dvoid *) &pos[2], cbf_get_data) + || OCIBindDynamic(bndhp[13], errhp, (dvoid *) &pos[3], cbf_no_data, + (dvoid *) &pos[3], cbf_get_data) + || OCIBindDynamic(bndhp[14], errhp, (dvoid *) &pos[4], cbf_no_data, + (dvoid *) &pos[4], cbf_get_data) + || OCIBindDynamic(bndhp[15], errhp, (dvoid *) &pos[5], cbf_no_data, + (dvoid *) &pos[5], cbf_get_data) + || OCIBindDynamic(bndhp[16], errhp, (dvoid *) &pos[6], cbf_no_data, + (dvoid *) &pos[6], cbf_get_data) + || OCIBindDynamic(bndhp[17], errhp, (dvoid *) &pos[7], cbf_no_data, + (dvoid *) &pos[7], cbf_get_data) + || OCIBindDynamic(bndhp[18], errhp, (dvoid *) &pos[8], cbf_no_data, + (dvoid *) &pos[8], cbf_get_data) + || OCIBindDynamic(bndhp[19], errhp, (dvoid *) &pos[9], cbf_no_data, + (dvoid *) &pos[9], cbf_get_data)) + { + (void) printf("FAILED: OCIBindDynamic()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* bind input variables. */ +/* ----------------------------------------------------------------- */ +static sword bind_input(OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp) +{ + /* bind the input data by positions */ + if (bind_pos(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* bind input array attributes*/ + return (bind_array(bndhp, errhp)); +} + + + +/* ----------------------------------------------------------------- */ +/* bind output variables. */ +/* ----------------------------------------------------------------- */ +static sword bind_output(OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp) +{ + + /* bind the returning bind buffers by names */ + if (bind_name(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* bind the returning bind buffers dynamically */ + return (bind_dynamic(bndhp, errhp)); +} + + +/* ----------------------------------------------------------------- */ +/* bind row indicator variables. */ +/* ----------------------------------------------------------------- */ +static sword bind_low_high(OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp) +{ + if (OCIBindByName(stmthp, &bndhp[23], errhp, + (text *) ":low", (sb4) strlen((char *) ":low"), + (dvoid *) &lowc1[0], (sb4) sizeof(lowc1[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByName(stmthp, &bndhp[24], errhp, + (text *) ":high", (sb4) strlen((char *) ":high"), + (dvoid *) &highc1[0], (sb4) sizeof(highc1[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByName()\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (OCIBindArrayOfStruct(bndhp[23], errhp, s1, indsk[0], rlsk[0], rcsk[0]) + || OCIBindArrayOfStruct(bndhp[24], errhp, s1, indsk[0], rlsk[0], rcsk[0])) + { + (void) printf("FAILED: OCIBindArrayOfStruct()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* Demontrate INSERT with RETURNING clause. */ +/* ----------------------------------------------------------------- */ +static sword demo_insert(OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp) +{ + int i, j; + + /* + * This function inserts values for 10 columns in table TAB1 and + * uses the RETURN clause to get back the inserted column values. + * It inserts MAXITER (10) such rows. Thus it expects MAXITER values + * for each column to be returned. + */ + /* The Insert Statement with RETURNING clause */ + text *sqlstmt = (text *) + "INSERT INTO TAB1 VALUES (:1, :2, :3, :4, :5, :6, :7, :8, :9, :10) \ + RETURNING C1, C2, C3, C4, C5, C6, C7, C8, C9, C10 \ + INTO :out1, :out2, :out3, :out4, :out5, :out6, \ + :out7, :out8, :out9, :out10"; + + /* Prepare the statement */ + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + + + /* Initialise the buffers for update */ + for (i = 0; i < MAXITER; i++) + { + in1[i] = i + 1; + memset((void *)in2[i], (int) 'A'+i%26, (size_t) 40); + memset((void *)in3[i], (int) 'a'+i%26, (size_t) 40); + in4[i] = 400.555 + (float) i; + in5[i] = 500 + i; + in6[i] = 600.250 + (float) i; + in7[i] = 700 + i; + in8[i] = 800.350 + (float) i; + in9[i][0] = 119; + in9[i][1] = 185 + (ub1)i%10; + in9[i][2] = (ub1)i%12 + 1; + in9[i][3] = (ub1)i%25 + 1; + in9[i][4] = 0; + in9[i][5] = 0; + in9[i][6] = 0; + for (j = 0; j < 40; j++) + in10[i][j] = (ub1) (i%0x10); + + rowsret[i] = 0; + } + + /* Bind all the input buffers to place holders (:1, :2. :3, etc ) */ + if (bind_input(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* Bind all the output buffers to place holders (:out1, :out2 etc */ + if (bind_output(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* Execute the Insert statement */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) MAXITER, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + + /* Commit the changes */ + (void) OCITransCommit(svchp, errhp, (ub4) 0); + + /* Print out the values in the return rows */ + (void) printf("\n\n DEMONSTRATING INSERT....RETURNING \n"); + (void) print_return_data((int)MAXITER); + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* Demonstrate UPDATE with RETURNING clause. */ +/* ----------------------------------------------------------------- */ +static sword demo_update(OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp) +{ + int i, j; + int range_size = 3; /* iterations */ + + + /* + * This function updates columns in table TAB1, for certain rows + * depending on the values of the :low and :high values in + * in the WHERE clause. It executes this statement 3 times, (3 iterations) + * each time with a different set of values for :low and :high + * Thus for each iteration, multiple rows are returned depending + * on the number of rows that matched the WHERE clause. + * + * The rows it updates here are the rows that were inserted by the + * cdemodr1.sql script. + */ + + /* The Update Statement with RETURNING clause */ + text *sqlstmt = (text *) + "UPDATE TAB1 SET C1 = C1 + :1, C2 = :2, C3 = :3, \ + C4 = C4 + :4, C5 = C5 + :5, C6 = C6 + :6, \ + C7 = C7 + :7, C8 = C8 + :8, C9 = :9, C10 = :10 \ + WHERE C1 >= :low AND C1 <= :high \ + RETURNING C1, C2, C3, C4, C5, C6, C7, C8, C9, C10 \ + INTO :out1, :out2, :out3, :out4, :out5, :out6, \ + :out7, :out8, :out9, :out10"; + + /* Prepare the statement */ + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() update\n"); + report_error(errhp); + return OCI_ERROR; + } + + /* Initialise the buffers for insertion */ + for (i = 0; i < MAXITER; i++) + { + in1[i] = 300 + i; + memset((void *)in2[i], (int) 'a'+i%26, (size_t) 40); + memset((void *)in3[i], (int) 'A'+i%26, (size_t) 40); + in4[i] = 400.555 + (float)i; + in5[i] = 500 + i; + in6[i] = 600.280 + (float)i; + in7[i] = 700 + i; + in8[i] = 800.620 + (float)i; + in9[i][0] = 119; + in9[i][1] = 185 - (ub1)i%10; + in9[i][2] = (ub1)i%12 + 1; + in9[i][3] = (ub1)i%25 + 1; + in9[i][4] = 0; + in9[i][5] = 0; + in9[i][6] = 0; + for (j = 0; j < 40; j++) + in10[i][j] = (ub1) (i%0x08); + + rowsret[i] =0; + } + + /* Bind all the input buffers to place holders (:1, :2. :3, etc ) */ + if (bind_input(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* Bind all the output buffers to place holders (:out1, :out2 etc */ + if (bind_output(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* bind row indicator low, high */ + if (bind_low_high(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* update rows + between 101 and 103; -- expecting 3 rows returned (update 3 rows) + between 105 and 106; -- expecting 2 rows returned (update 2 rows) + between 109 and 113; -- expecting 5 rows returned (update 5 rows) + */ + lowc1[0] = 101; + highc1[0] = 103; + + lowc1[1] = 105; + highc1[1] = 106; + + lowc1[2] = 109; + highc1[2] = 113; + + (void) printf("\n\n DEMONSTRATING UPDATE....RETURNING \n"); + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) range_size, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() update\n"); + report_error(errhp); + return OCI_ERROR; + } + + /* Commit the changes */ + (void) OCITransCommit(svchp, errhp, (ub4) 0); + + /* Print out the values in the return rows */ + (void) print_return_data(range_size); + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* Demonstrate DELETE with RETURNING clause. */ +/* ----------------------------------------------------------------- */ +static sword demo_delete(OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp) +{ + int i, range_size = 3; /* iterations */ + sword retval; + + /* + * This function deletes certain rows from table TAB1 + * depending on the values of the :low and :high values in + * the WHERE clause. It executes this statement 3 times, (3 iterations) + * each time with a different set of values for :low and :high + * Thus for each iteration, multiples rows are returned depending + * on the number of rows that matched the WHERE clause. + * + * The rows it deletes here are the rows that were inserted by the + * cdemodr1.sql script. + */ + + /* The Delete Statement with RETURNING clause */ + text *sqlstmt = (text *) + "DELETE FROM TAB1 WHERE C1 >= :low AND C1 <= :high \ + RETURNING C1, C2, C3, C4, C5, C6, C7, C8, C9, C10 \ + INTO :out1, :out2, :out3, :out4, :out5, :out6, \ + :out7, :out8, :out9, :out10"; + + /* Prepare the statement */ + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() delete\n"); + report_error(errhp); + return OCI_ERROR; + } + + /* Bind all the output buffers to place holders (:out1, :out2 etc */ + if (bind_output(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* bind row indicator low, high */ + if (bind_low_high(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* delete rows + between 201 and 203; -- expecting 3 rows returned (3 rows deleted) + between 205 and 209; -- expecting 5 rows returned (2 rows deleted) + between 211 and 213; -- expecting 3 rows returned (5 rows deleted) + */ + lowc1[0] = 201; + highc1[0] = 203; + + lowc1[1] = 205; + highc1[1] = 209; + + lowc1[2] = 211; + highc1[2] = 213; + + + for (i=0; i + + PRIVATE FUNCTION(S) + + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 10/01/98 - include stdlib.h - bug 714175 + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + echen 07/30/97 - fix bug 516406 + azhao 05/30/97 - Creation + +*/ + +/*------------------------------------------------------------------------ + * Include Files + */ + +#include +#include +#include +#include +/* +#include +*/ + +/*------------------------------------------------------------------------ + * Define Constants + */ + +#define MAXBINDS 25 +#define MAXROWS 5 /* max no of rows returned per iter */ +#define MAXCOLS 10 +#define MAXITER 10 /* max no of iters in execute */ +#define MAXCOLLEN 40 /* if changed, update cdemodr1.sql */ +#define DATBUFLEN 7 + +int main(/*_ int argc, char *argv[] _*/); +static sword init_handles(/*_ OCIEnv **envhp, OCISvcCtx **svchp, + OCIError **errhp, OCIServer **svrhp, + OCISession **authp, ub4 mode _*/); + +static sword attach_server(/*_ ub4 mode, OCIServer *srvhp, + OCIError *errhp, OCISvcCtx *svchp _*/); +static sword log_on(/*_ OCISession *authp, OCIError *errhp, OCISvcCtx *svchp, + text *uid, text *pwd, ub4 credt, ub4 mode _*/); +static sword init_bind_handle(/*_ OCIStmt *stmthp, OCIBind *bndhp[], + int nbinds _*/); +static void print_raw(/*_ ub1 *raw, ub4 rawlen _*/); + +static void free_handles(/*_ OCIEnv *envhp, OCISvcCtx *svchp, OCIServer *srvhp, + OCIError *errhp, OCISession *authp, OCIStmt *stmthp _*/); +void report_error(/*_ OCIError *errhp _*/); +void logout_detach_server(/*_ OCISvcCtx *svchp, OCIServer *srvhp, + OCIError *errhp, OCISession *authp, + text *userid _*/); +sword finish_demo(/*_ boolean loggedon, OCIEnv *envhp, OCISvcCtx *svchp, + OCIServer *srvhp, OCIError *errhp, OCISession *authp, + OCIStmt *stmthp, text *userid _*/); +static sword demo_insert(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); +static sword demo_update(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); +static sword demo_delete(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); +static sword bind_name(/*_ OCIStmt *stmthp, OCIBind *bndhp[], + OCIError *errhp _*/); +static sword bind_pos(/*_ OCIStmt *stmthp, OCIBind *bndhp[], + OCIError *errhp _*/); +static sword bind_input(/*_ OCIStmt *stmthp, OCIBind *bndhp[], + OCIError *errhp _*/); +static sword bind_output(/*_ OCIStmt *stmthp, OCIBind *bndhp[], + OCIError *errhp _*/); +static sword bind_array(/*_ OCIBind *bndhp[], OCIError *errhp _*/); +static sword bind_dynamic(/*_ OCIBind *bndhp[], OCIError *errhp _*/); +static sb4 cbf_no_data(/*_ dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index, + dvoid **bufpp, ub4 *alenpp, ub1 *piecep, dvoid **indpp _*/); +static sb4 cbf_get_data(/*_ dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index, + dvoid **bufpp, ub4 **alenpp, ub1 *piecep, + dvoid **indpp, ub2 **rcodepp _*/); +static sword alloc_buffer(/*_ ub4 pos, ub4 iter, ub4 rows _*/); +static sword print_return_data(/*_ int iter _*/); + diff --git a/cdemodr1.sql b/cdemodr1.sql new file mode 100644 index 0000000..c267f58 --- /dev/null +++ b/cdemodr1.sql @@ -0,0 +1,132 @@ +rem +rem $Header: cdemodr1.sql 14-jul-99.13:49:48 mjaeger Exp $ +rem +rem cdemodr1.sql +rem +rem Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemodr1.sql - +rem +rem DESCRIPTION +rem +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem azhao 05/30/97 - Created +rem + +connect scott/tiger +drop table tab1; + +create table tab1 (c1 integer, c2 char(40), c3 varchar2(40), c4 float, + c5 decimal, c6 decimal(8,3), c7 numeric, c8 numeric(7,2), + C9 date, C10 raw(40)); + +rem +rem Insert some data for UPDATE +rem + +insert into tab1 values (101, 'To be updated, row 101', 'varchar2, row 101', + 201.520, 301, 401.450, 501, 601.550, '01-JAN-85', + '123456789012345678901234567890'); +insert into tab1 values (102, 'To be updated, row 102', 'varchar2, row 102', + 202.520, 302, 402.450, 502, 602.550, '02-FEB-86', + '234567890123456789012345678901'); +insert into tab1 values (103, 'To be updated, row 103', 'varchar2, row 103', + 203.520, 303, 403.450, 503, 603.550, '03-MAR-87', + '345678901234567890123456789012'); +insert into tab1 values (104, 'To be updated, row 104', 'varchar2, row 104', + 204.520, 304, 404.450, 504, 604.550, '04-APR-88', + '456789012345678901234567890123'); +insert into tab1 values (105, 'To be updated, row 105', 'varchar2, row 105', + 205.520, 305, 405.450, 505, 605.550, '05-MAY-89', + '567890123456789012345678901234'); +insert into tab1 values (106, 'To be updated, row 106', 'varchar2, row 106', + 206.520, 306, 406.450, 506, 606.550, '06-JUN-90', + '678901234567890123456789012345'); +insert into tab1 values (107, 'To be updated, row 107', 'varchar2, row 107', + 207.520, 307, 407.450, 507, 607.550, '07-JUL-91', + '789012345678901234567890123456'); +insert into tab1 values (108, 'To be updated, row 108', 'varchar2, row 108', + 208.520, 308, 408.450, 508, 608.550, '08-AUG-92', + '890123456789012345678901234567'); +insert into tab1 values (109, 'To be updated, row 109', 'varchar2, row 109', + 209.520, 309, 409.450, 509, 609.550, '09-SEP-93', + '901234567890123456789012345678'); +insert into tab1 values (110, 'To be updated, row 110', 'varchar2, row 110', + 210.520, 310, 410.450, 510, 610.550, '10-OCT-94', + '012345678901234567890123456789'); +insert into tab1 values (111, 'To be updated, row 111', 'varchar2, row 111', + 211.520, 311, 411.450, 511, 611.550, '11-NOV-95', + '123456789012345678901234567890'); +insert into tab1 values (112, 'To be updated, row 112', 'varchar2, row 112', + 212.520, 312, 412.450, 512, 612.550, '12-DEC-96', + '234567890123456789012345678901'); +insert into tab1 values (113, 'To be updated, row 113', 'varchar2, row 113', + 213.520, 313, 413.450, 513, 613.550, '13-JAN-97', + '345678901234567890123456789012'); +insert into tab1 values (114, 'To be updated, row 114', 'varchar2, row 114', + 214.520, 314, 414.450, 514, 614.550, '14-FEB-98', + '456789012345678901234567890123'); +insert into tab1 values (115, 'To be updated, row 115', 'varchar2, row 115', + 215.520, 315, 415.450, 515, 615.550, '15-MAR-99', + '567890123456789012345678901234'); + +rem +rem Insert some data for DELETE +rem + +insert into tab1 values (201, null, 'varchar2, row 201', + 2001.520, 3001, 4001.4500, 5001, 6001.550, '01-JAN-95', + '123456789012345678901234567890'); +insert into tab1 values (202, 'To be deleted, row 202', null, + 2002.520, 3002, 4002.4500, 5002, 6002.550, '02-FEB-94', + '234567890123456789012345678901'); +insert into tab1 values (203, 'To be deleted, row 203', 'varchar2, row 203', + null, 3003, 4003.4500, 5003, 6003.550, '03-MAR-93', + '345678901234567890123456789012'); +insert into tab1 values (204, 'To be deleted, row 204', 'varchar2, row 204', + 2004.520, 3004, 4004.4500, 5004, 6004.550, '04-APR-92', + '456789012345678901234567890123'); +insert into tab1 values (205, 'To be deleted, row 205', 'varchar2, row 205', + 2005.520, null, 4005.4500, 5005, 6005.550, '05-MAY-91', + '567890123456789012345678901234'); +insert into tab1 values (206, 'To be deleted, row 206', 'varchar2, row 206', + 2006.520, 3006, null, 5006, 6006.550, '06-JUN-90', + '678901234567890123456789012345'); +insert into tab1 values (207, 'To be deleted, row 207', 'varchar2, row 207', + 2007.520, 3007, 4007.4500, null, 6007.550, '07-JUL-89', + '789012345678901234567890123456'); +insert into tab1 values (208, 'To be deleted, row 208', 'varchar2, row 208', + 2008.520, 3008, 4008.4500, 5008, null, '08-AUG-88', + '890123456789012345678901234567'); +insert into tab1 values (209, 'To be deleted, row 209', 'varchar2, row 209', + 2009.520, 3009, 4009.4500, 5009, 6009.550, '09-SEP-87', + '901234567890123456789012345678'); +insert into tab1 values (210, 'To be deleted, row 210', 'varchar2, row 210', + 2010.520, 3010, 4010.4500, 5010, 6010.550, '10-OCT-86', + '012345678901234567890123456789'); +insert into tab1 values (211, 'To be deleted, row 211', 'varchar2, row 211', + 2011.520, 3011, 4011.4500, 5011, 6011.550, null, + '123456789012345678901234567890'); +insert into tab1 values (212, 'To be deleted, row 212', 'varchar2, row 212', + 2012.520, 3012, 4012.4500, 5012, 6012.550, '12-DEC-84', + null); +insert into tab1 values (213, 'To be deleted, row 213', 'varchar2, row 213', + 2013.520, 3013, 4013.4500, 5013, 6013.550, '13-JAN-83', + '345678901234567890123456789012'); +insert into tab1 values (214, 'To be deleted, row 214', 'varchar2, row 214', + 2014.520, 3014, 4014.4500, 5014, 6014.550, '14-FEB-82', + '456789012345678901234567890123'); +insert into tab1 values (215, 'To be deleted, row 215', 'varchar2, row 215', + 2015.520, 3015, 4015.4500, 5015, 6015.550, '15-MAR-81', + '567890123456789012345678901234'); + +commit; + +quit + diff --git a/cdemodr2.c b/cdemodr2.c new file mode 100644 index 0000000..9425436 --- /dev/null +++ b/cdemodr2.c @@ -0,0 +1,1283 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodr2.c 10-oct-2006.14:39:58 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemodr2.c - DML Returning LOBs. + + DESCRIPTION + Demonstrate INSERT/UPDATE/DELETE statements RETURNING LOBS + + demo table: TAB2 (C1 INTEGER, C2 BLOB, C3 CLOB) + + Before running cdemodr2, run cdemodr2.sql to create and populate + TAB2 with some initial data. + + demo_insert() -- inserts 10 rows (with C1 = 1, 2, 3, ..., 10) + in null BLOBs, CLOBs for C2, C3, respectively. + The returned lob locators corresponding to these + BLOBs, CLOBs are then used for lob read/write. + + select_locator() -- shows that the locators returned from the INSERT + statement in demo_insert() are valid. + + demo_update() -- updates the rows within 3 ranges of C1. The + lob locators used for updating C2, C3 have been + returned from demo_insert(), used by select_locator() + to select the BLOBs, CLOBs from a different range of C1. + + demo_delete() -- deletes the rows within 3 ranges of C1. The returned + lob locators can be read but not written because those + rows associated with the returned locators have be deleted. + + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + svedala 10/18/99 - + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 08/19/97 - replace OCIStmtBindByName with OCIBindByName + azhao 06/03/97 - Creation + +*/ + +/*------------------------Inclusions-------------------------------*/ + +#include + +static boolean logged_on = FALSE; + +/* TAB2 columns */ +static int in1[MAXITER]; /* for INTEGER */ +static OCILobLocator *in2[MAXITER]; /* for BLOB */ +static OCILobLocator *in3[MAXITER]; /* for CLOB */ + +/* output buffers */ +static int *p1[MAXITER]; /* for INTEGER */ +static OCILobLocator **p2[MAXITER]; /* for BLOB */ +static OCILobLocator **p3[MAXITER]; /* for CLOB */ + +static short *ind[MAXCOLS][MAXITER]; /* indicators */ +static ub2 *rc[MAXCOLS][MAXITER]; /* return codes */ +static ub4 *rl[MAXCOLS][MAXITER]; /* return lengths */ + +/* skip values for binding TAB2 */ +static ub4 s1 = (ub4) sizeof(in1[0]); +static ub4 s2 = (ub4) sizeof(in2[0]); +static ub4 s3 = (ub4) sizeof(in3[0]); + +/* Rows returned in each iteration */ +static ub2 rowsret[MAXITER]; + +/* indicator skips */ +static ub4 indsk[MAXCOLS] = { 0, 0, 0 }; +/* return length skips */ +static ub4 rlsk[MAXCOLS] = { 0, 0, 0 }; +/* return code skips */ +static ub4 rcsk[MAXCOLS] = { 0, 0, 0 }; + +static int lowc1[MAXITER], highc1[MAXITER]; + +static ub4 pos[MAXCOLS]; + +static OCIEnv *envhp; +static OCIError *errhp; + +static sb2 null_ind = -1; + + +/*------------------------end of Global variables--------------------*/ + + +/*========================== UTILITY FUNCTIONS ======================*/ +/* + * These functions are generic functions that can be used in any + * OCI program. + */ +/* ----------------------------------------------------------------- */ +/* Initialize environment, allocate handles */ +/* ----------------------------------------------------------------- */ +sword init_handles(envhp, svchp, errhp, srvhp, authp, init_mode) +OCIEnv **envhp; +OCISvcCtx **svchp; +OCIError **errhp; +OCIServer **srvhp; +OCISession **authp; +ub4 init_mode; +{ + (void) printf("Environment setup ....\n"); + + /* Initialize the OCI Process */ + if (OCIInitialize(init_mode, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + /* Inititialize the OCI Environment */ + if (OCIEnvInit((OCIEnv **) envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + /* Allocate a service handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on svchp\n"); + return OCI_ERROR; + } + + /* Allocate an error handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on errhp\n"); + return OCI_ERROR; + } + + /* Allocate a server handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on srvhp\n"); + return OCI_ERROR; + } + + /* Allocate a authentication handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on authp\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/* ----------------------------------------------------------------- */ +/* Attach to server with a given mode. */ +/* ----------------------------------------------------------------- */ +sword attach_server(mode, srvhp, errhp, svchp) +ub4 mode; +OCIServer *srvhp; +OCIError *errhp; +OCISvcCtx *svchp; +{ + text *cstring = (text *)""; + + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + /* Set the server handle in the service handle */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet() server attribute\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} +/* ----------------------------------------------------------------- */ +/* Logon to the database using given username, password & credentials*/ +/* ----------------------------------------------------------------- */ +sword log_on(authp, errhp, svchp, uid, pwd, credt, mode) +OCISession *authp; +OCIError *errhp; +OCISvcCtx *svchp; +text *uid; +text *pwd; +ub4 credt; +ub4 mode; +{ + /* Set attributes in the authentication handle */ + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *) uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet() userid\n"); + return OCI_ERROR; + } + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *) pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + (void) printf("Logging on as %s ....\n", uid); + + if (OCISessionBegin(svchp, errhp, authp, credt, mode)) + { + (void) printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + (void) printf("%s logged on.\n", uid); + + /* Set the authentication handle in the Service handle */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet() session\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/*---------------------------------------------------------------------*/ +/* Allocate all required bind handles */ +/*---------------------------------------------------------------------*/ + +sword alloc_bind_handle(stmthp, bndhp, nbinds) +OCIStmt *stmthp; +OCIBind *bndhp[]; +int nbinds; +{ + int i; + /* + * This function allocates the specified number of bind handles + * from the given statement handle. + */ + for (i = 0; i < nbinds; i++) + if (OCIHandleAlloc((dvoid *)stmthp, (dvoid **)&bndhp[i], + (ub4)OCI_HTYPE_BIND, (CONST size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() bind handle\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/* ----------------------------------------------------------------- */ +/* Print the returned raw data. */ +/* ----------------------------------------------------------------- */ +void print_raw(raw, rawlen) +ub1 *raw; +ub4 rawlen; +{ + ub4 i; + ub4 lim; + ub4 clen = 0; + + if (rawlen > 120) + { + ub4 llen = rawlen; + + while (llen > 120) + { + lim = clen + 120; + for(i = clen; i < lim; ++i) + (void) printf("%02.2x", (ub4) raw[i] & 0xFF); + + (void) printf("\n"); + llen -= 120; + clen += 120; + } + lim = clen + llen; + } + else + lim = rawlen; + + for(i = clen; i < lim; ++i) + (void) printf("%02.2x", (ub4) raw[i] & 0xFF); + + (void) printf("\n"); + + return; +} + +/* ----------------------------------------------------------------- */ +/* Free the specified handles */ +/* ----------------------------------------------------------------- */ +void free_handles(envhp, svchp, srvhp, errhp, authp, stmthp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +OCIStmt *stmthp; +{ + (void) printf("Freeing handles ...\n"); + + if (srvhp) + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + if (authp) + (void) OCIHandleFree((dvoid *) authp, (ub4) OCI_HTYPE_SESSION); + if (stmthp) + (void) OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT); + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV); + + return; +} + +/* ----------------------------------------------------------------- */ +/* Print the error message */ +/* ----------------------------------------------------------------- */ +void report_error(errhp) +OCIError *errhp; +{ + text msgbuf[512]; + sb4 errcode = 0; + + (void) OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("ERROR CODE = %d\n", errcode); + (void) printf("%.*s\n", 512, msgbuf); + return; +} + +/*-------------------------------------------------------------------*/ +/* Logout and detach from the server */ +/*-------------------------------------------------------------------*/ +void logout_detach_server(svchp, srvhp, errhp, authp, userid) +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +text *userid; +{ + if (OCISessionEnd(svchp, errhp, authp, (ub4) 0)) + { + (void) printf("FAILED: OCISessionEnd()\n"); + report_error(errhp); + } + + (void) printf("%s Logged off.\n", userid); + + if (OCIServerDetach(srvhp, errhp, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionEnd()\n"); + report_error(errhp); + } + + (void) printf("Detached from server.\n"); + + return; +} + +/*---------------------------------------------------------------------*/ +/* Finish demo and clean up */ +/*---------------------------------------------------------------------*/ +sword finish_demo(loggedon, envhp, svchp, srvhp, errhp, authp, stmthp, userid) +boolean loggedon; +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +OCIStmt *stmthp; +text *userid; +{ + + if (loggedon) + logout_detach_server(svchp, srvhp, errhp, authp, userid); + + free_handles(envhp, svchp, srvhp, errhp, authp, stmthp); + + return OCI_SUCCESS; +} + +/*===================== END OF UTILITY FUNCTIONS ======================*/ + + +int main(argc, argv) +int argc; +char *argv[]; +{ + text *username = (text *)"SCOTT"; + text *password = (text *)"tiger"; + + OCIServer *srvhp; + OCISvcCtx *svchp; + OCISession *authp; + OCIStmt *stmthp = (OCIStmt *) NULL; + OCIBind *bndhp[MAXBINDS]; + int i; + + if (init_handles(&envhp, &svchp, &errhp, &srvhp, &authp, (ub4)OCI_DEFAULT)) + { + (void) printf("FAILED: init_handles()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + if (attach_server((ub4) OCI_DEFAULT, srvhp, errhp, svchp)) + { + (void) printf("FAILED: attach_server()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + if (log_on(authp, errhp, svchp, username, password, + (ub4) OCI_CRED_RDBMS, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: log_on()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + logged_on = TRUE; + + if (OCIHandleAlloc((dvoid *)envhp, (dvoid **) &stmthp, + (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: alloc statement handle\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + /* bind handles will be implicitly allocated in the bind calls */ + /* need to initialize them to null prior to first usage in bind calls */ + + for (i = 0; i < MAXBINDS; i++) + bndhp[i] = (OCIBind *) 0; + + + if (demo_insert(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: demo_insert()\n"); + else + (void) printf("SUCCESS: demo_insert()\n"); + + if (select_locator(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: select_locator()\n"); + else + (void) printf("SUCCESS: select_locator()\n"); + + if (demo_update(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: demo_update()\n"); + else + (void) printf("SUCCESS: demo_update()\n"); + + + if (demo_delete(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: demo_delete()\n"); + else + (void) printf("SUCCESS: demo_delete()\n"); + + locator_free(in2, MAXITER); + locator_free(in3, MAXITER); + + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); +} + + + + +/* ----------------------------------------------------------------- */ +/* bind all the columns of TAB2 by positions. */ +/* ----------------------------------------------------------------- */ +sword bind_in_name(stmthp, bndhp, errhp) +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + + if (OCIBindByName(stmthp, &bndhp[0], errhp, + (text *) ":c1", (sb4) strlen((char *) ":c1"), + (dvoid *) &in1[0], (sb4) sizeof(in1[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByName(stmthp, &bndhp[1], errhp, + (text *) ":c2", (sb4) strlen((char *) ":c2"), + (dvoid *) &in2[0], (sb4) -1, SQLT_BLOB, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByName(stmthp, &bndhp[2], errhp, + (text *) ":c3", (sb4) strlen((char *) ":c3"), + (dvoid *) &in3[0], (sb4) -1, SQLT_CLOB, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByName()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* bind all the columns of TAB2 by name. */ +/* ----------------------------------------------------------------- */ +sword bind_name(stmthp, bndhp, errhp) +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + + if (OCIBindByName(stmthp, &bndhp[10], errhp, + (text *) ":out1", (sb4) strlen((char *) ":out1"), + (dvoid *) 0, (sb4) sizeof(int), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[11], errhp, + (text *) ":out2", (sb4) strlen((char *) ":out2"), + (dvoid *) 0, (sb4) -1, SQLT_BLOB, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[12], errhp, + (text *) ":out3", (sb4) strlen((char *) ":out3"), + (dvoid *) 0, (sb4) -1, SQLT_CLOB, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC)) + { + (void) printf("FAILED: OCIBindByName()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* bind array structs for TAB2 columns. */ +/* ----------------------------------------------------------------- */ +sword bind_array(bndhp, errhp) +OCIBind *bndhp[]; +OCIError *errhp; +{ + if (OCIBindArrayOfStruct(bndhp[0], errhp, s1, indsk[0], rlsk[0], rcsk[0]) + || OCIBindArrayOfStruct(bndhp[1], errhp, s2, indsk[1], rlsk[1], rcsk[1]) + || OCIBindArrayOfStruct(bndhp[2], errhp, s3, indsk[2], rlsk[2], rcsk[2])) + { + (void) printf("FAILED: OCIBindArrayOfStruct()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* bind dynamic for returning TAB2 columns. */ +/* ----------------------------------------------------------------- */ +sword bind_dynamic(bndhp, errhp) +OCIBind *bndhp[]; +OCIError *errhp; +{ + int i; + + for (i = 0; i < MAXCOLS; i++) + pos[i] = i; + + if (OCIBindDynamic(bndhp[10], errhp, (dvoid *)&pos[0], cbf_no_data, + (dvoid *)&pos[0], cbf_get_data) + || OCIBindDynamic(bndhp[11], errhp, (dvoid *)&pos[1], cbf_no_data, + (dvoid *)&pos[1], cbf_get_data) + || OCIBindDynamic(bndhp[12], errhp, (dvoid *)&pos[2], cbf_no_data, + (dvoid *)&pos[2], cbf_get_data)) + { + (void) printf("FAILED: OCIBindDynamic()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* bind input variables. */ +/* ----------------------------------------------------------------- */ +sword bind_input(stmthp, bndhp, errhp) +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + /* by the input data by names */ + if (bind_in_name(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* by input array */ + return (bind_array(bndhp, errhp)); +} + + + +/* ----------------------------------------------------------------- */ +/* bind output variables. */ +/* ----------------------------------------------------------------- */ +sword bind_output(stmthp, bndhp, errhp) +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + + /* by the returning data by names */ + if (bind_name(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* by dynamic of returning data by names */ + return (bind_dynamic(bndhp, errhp)); +} + + + +/* ----------------------------------------------------------------- */ +/* bind row indicator variables. */ +/* ----------------------------------------------------------------- */ +sword bind_low_high(stmthp, bndhp, errhp) +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + if (OCIBindByName(stmthp, &bndhp[23], errhp, + (text *) ":low", (sb4) strlen((char *) ":low"), + (dvoid *) &lowc1[0], (sb4) sizeof(lowc1[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByName(stmthp, &bndhp[24], errhp, + (text *) ":high", (sb4) strlen((char *) ":high"), + (dvoid *) &highc1[0], (sb4) sizeof(highc1[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByName()\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (OCIBindArrayOfStruct(bndhp[23], errhp, s1, indsk[0], rlsk[0], rcsk[0]) + || OCIBindArrayOfStruct(bndhp[24], errhp, s1, indsk[0], rlsk[0], rcsk[0])) + { + (void) printf("FAILED: OCIBindArrayOfStruct()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + + +/* ----------------------------------------------------------------- */ +/* test for INSERT with RETURNING clause. */ +/* ----------------------------------------------------------------- */ +sword demo_insert(svchp, stmthp, bndhp, errhp) +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + int i, j; + int num[MAXITER]; + text *sqlstmt =(text *)"INSERT INTO TAB2(C1,C2,C3) VALUES \ + (:c1, empty_blob(), empty_clob()) \ + RETURNING C1, C2, C3 INTO \ + :out1, :out2, :out3"; + + (void) printf("\n\n========== TESTING INSERT....RETURNING \n"); + for (i = 0; i < MAXITER; i++) + num[i] = i; + + for (i = 0; i < 1; i++) + { + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (OCIBindByName(stmthp, &bndhp[0], errhp, + (text *) ":c1", (sb4) strlen((char *) ":c1"), + (dvoid *) &num[0], (sb4) sizeof(num[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) ) + { + (void) printf("FAILED: OCIStmtPrepare() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (OCIBindArrayOfStruct(bndhp[0], errhp, s1, indsk[0], rlsk[0], rcsk[0])) + { + (void) printf("FAILED: OCIStmtPrepare() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (bind_output(stmthp, bndhp, errhp)) + return OCI_ERROR; + + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) MAXITER, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + } + + (void) check_lob((int)MAXITER, svchp); + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* test for UPDATE with RETURNING clause. */ +/* ----------------------------------------------------------------- */ +sword demo_update(svchp, stmthp, bndhp, errhp) +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + int i, j; + int range_size = 3; + + text *sqlstmt = (text *) + "UPDATE TAB2 SET C1 = C1 + :c1, C2 = :c2, C3 = :c3 \ + WHERE C1 >= :low AND C1 <= :high \ + RETURNING C1, C2, C3 INTO :out1, :out2, :out3"; + + (void) printf("\n\n========== TESTING UPDATE....RETURNING \n"); + + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() update\n"); + report_error(errhp); + return OCI_ERROR; + } + + + for (i = 0; i < MAXITER; i++) + { + in1[i] = 301 + i; + + /* in2[], in3[] have been loaded in select_locator() */ + + rowsret[i] =0; + } + + /* bind input */ + if (bind_input(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* bind output */ + if (bind_output(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* bind row indicator low, high */ + if (bind_low_high(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* update rows + between 101 and 103; -- expecting 3 rows returned. + between 105 and 106; -- expecting 2 rows returned. + between 108 and 110; -- expecting 3 rows returned. + */ + + lowc1[0] = 101; + highc1[0] = 103; + + lowc1[1] = 105; + highc1[1] = 106; + + lowc1[2] = 109; + highc1[2] = 113; + + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) range_size, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() update\n"); + report_error(errhp); + return OCI_ERROR; + } + + (void) check_lob(range_size, svchp); + + return OCI_SUCCESS; +} + + + + +/* ----------------------------------------------------------------- */ +/* test for DELETE with RETURNING clause. */ +/* ----------------------------------------------------------------- */ +sword demo_delete(svchp, stmthp, bndhp, errhp) +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + int i, range_size = 3; + sword retval; + + text *sqlstmt = (text *) + "DELETE FROM TAB2 WHERE C1 >= :low AND C1 <= :high \ + RETURNING C1, C2, C3 INTO :out1, :out2, :out3"; + + (void) printf("\n\n========== TESTING DELETE....RETURNING \n"); + + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() delete\n"); + report_error(errhp); + return OCI_ERROR; + } + + /* bind output */ + if (bind_output(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* bind row indicator low, high */ + if (bind_low_high(stmthp, bndhp, errhp)) + return OCI_ERROR; + + + /* delete rows + between 201 and 202; -- expecting 2 rows returned. + between 204 and 206; -- expecting 3 rows returned. + between 208 and 209; -- expecting 2 rows returned. + */ + + lowc1[0] = 201; + highc1[0] = 202; + + lowc1[1] = 204; + highc1[1] = 206; + + lowc1[2] = 208; + highc1[2] = 209; + + + for (i=0; i + + PRIVATE FUNCTION(S) + + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 10/01/98 - include stdlib.h - bug 714175 + azhao 06/03/97 - new file + azhao 06/03/97 - Creation + +*/ + +#include +#include +#include +#include + + +#define MAXBINDS 25 +#define MAXROWS 5 /* max no of rows returned per iter */ +#define MAXCOLS 4 +#define MAXITER 10 /* max no of iters in execute */ +#define MAXBUFLEN 40 + +int main(/*_ int argc, char *argv[] _*/); +sword init_handles(/*_ OCIEnv **envhp, OCISvcCtx **svchp, + OCIError **errhp, OCIServer **svrhp, + OCISession **authp, ub4 mode _*/); + +sword attach_server(/*_ ub4 mode, OCIServer *srvhp, + OCIError *errhp, OCISvcCtx *svchp _*/); +sword log_on(/*_ OCISession *authp, OCIError *errhp, OCISvcCtx *svchp, + text *uid, text *pwd, ub4 credt, ub4 mode _*/); +sword alloc_bind_handle(/*_ OCIStmt *stmthp, OCIBind *bndhp[], + int nbinds _*/); +void print_raw(/*_ ub1 *raw, ub4 rawlen _*/); + +void free_handles(/*_ OCIEnv *envhp, OCISvcCtx *svchp, OCIServer *srvhp, + OCIError *errhp, OCISession *authp, OCIStmt *stmthp _*/); +void report_error(/*_ OCIError *errhp _*/); +void logout_detach_server(/*_ OCISvcCtx *svchp, OCIServer *srvhp, + OCIError *errhp, OCISession *authp, + text *userid _*/); +sword finish_demo(/*_ boolean loggedon, OCIEnv *envhp, OCISvcCtx *svchp, + OCIServer *srvhp, OCIError *errhp, OCISession *authp, + OCIStmt *stmthp, text *userid _*/); +sword demo_insert(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); +sword demo_update(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); +sword demo_delete(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_name(/*_ OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_in_name(/*_ OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_low_high(/*_ OCIStmt *stmthp, OCIBind *bndhp[], + OCIError *errhp _*/); +sword bind_input(/*_ OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_output(/*_ OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_array(/*_ OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_dynamic(/*_ OCIBind *bndhp[], OCIError *errhp _*/); +sb4 cbf_no_data(/*_ dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index, + dvoid **bufpp, ub4 *alenpp, ub1 *piecep, dvoid **indpp _*/); +sb4 cbf_get_data(/*_ dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index, + dvoid **bufpp, ub4 **alenpp, ub1 *piecep, + dvoid **indpp, ub2 **rcodepp _*/); +sword alloc_buffer(/*_ ub4 pos, ub4 iter, ub4 rows _*/); +sword read_piece(/*_ OCISvcCtx *svchp, OCILobLocator *lob, ub2 lobtype _*/); +sword write_piece(/*_ OCISvcCtx *svchp, OCILobLocator *lob, ub2 lobtype _*/); +sword check_lob(/*_ int iter, OCISvcCtx *svchp _*/); +sword locator_alloc(/*_ OCILobLocator *lob[], ub4 nlobs _*/); +sword locator_free(/*_ OCILobLocator *lob[], ub4 nlobs _*/); +sword select_locator(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); + diff --git a/cdemodr2.sql b/cdemodr2.sql new file mode 100644 index 0000000..fb234c5 --- /dev/null +++ b/cdemodr2.sql @@ -0,0 +1,61 @@ +rem +rem $Header: cdemodr2.sql 14-jul-99.13:50:24 mjaeger Exp $ +rem +rem cdemodr2.sql +rem +rem Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemodr2.sql - create and populate test table TAB2. +rem +rem DESCRIPTION +rem Demonstrate INSERT/UPDATE/DELETE statements RETURNING LOBS. +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem azhao 06/03/97 - Created +rem + +connect scott/tiger +drop table tab2; + +create table tab2 (c1 integer, c2 blob, c3 clob); + +rem +rem insert some rows for UPDATE later +rem + +insert into tab2 values(101, null, null); +insert into tab2 values(102, null, null); +insert into tab2 values(103, null, null); +insert into tab2 values(104, null, null); +insert into tab2 values(105, null, null); +insert into tab2 values(106, null, null); +insert into tab2 values(107, null, null); +insert into tab2 values(108, null, null); +insert into tab2 values(109, null, null); +insert into tab2 values(110, null, null); + +rem +rem insert some rows for DELETE later +rem + +insert into tab2 values(201, '111', 'AAA'); +insert into tab2 values(202, '111', 'BBB'); +insert into tab2 values(203, '333', 'CCC'); +insert into tab2 values(204, '444', 'DDD'); +insert into tab2 values(205, '555', 'EEE'); +insert into tab2 values(206, '666', 'FFF'); +insert into tab2 values(207, '777', 'GGG'); +insert into tab2 values(208, '888', 'HHH'); +insert into tab2 values(209, '999', 'III'); +insert into tab2 values(210, '000', 'JJJ'); + + +commit; + +quit + diff --git a/cdemodr3.c b/cdemodr3.c new file mode 100644 index 0000000..741e3d2 --- /dev/null +++ b/cdemodr3.c @@ -0,0 +1,703 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodr3.c 10-oct-2006.14:39:59 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemodr3.c - DML Returning Demo + + DESCRIPTION + Demonstrate INSERT statement RETURNING REF + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + svedala 10/18/99 - + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 08/19/97 - replace OCIStmtBindByName with OCIBindByName + azhao 06/03/97 - Creation + +*/ + +/*------------------------Inclusions-------------------------------*/ + +#include + +static boolean logged_on = FALSE; + +static OCIRef *addrref[MAXITER]; /* for returned REF */ +static OCIType *addrtdo = (OCIType *) 0; + +static text in_state[MAXITER][2]; +static text in_zip[MAXITER][10]; +static text *out_zip[MAXITER]; /* for returned ZIP */ + +static short *ind[MAXCOLS][MAXITER]; /* indicators */ +static ub2 *rc[MAXCOLS][MAXITER]; /* return codes */ +static ub4 *rl[MAXCOLS][MAXITER]; /* return lengths */ + +/* Rows returned in each iteration */ +static ub2 rowsret[MAXITER]; + +static ub4 pos[MAXCOLS]; +static sb2 null_ind = -1; + + +static OCIEnv *envhp; +static OCIError *errhp; +static OCISvcCtx *svchp; + +/*------------------------end of Inclusions-----------------------------*/ + + +/*========================== UTILITY FUNCTIONS ======================*/ +/* + * These functions are generic functions that can be used in any + * OCI program. + */ +/* ----------------------------------------------------------------- */ +/* Initialize environment, allocate handles */ +/* ----------------------------------------------------------------- */ +sword init_handles(envhp, svchp, errhp, srvhp, authp, init_mode) +OCIEnv **envhp; +OCISvcCtx **svchp; +OCIError **errhp; +OCIServer **srvhp; +OCISession **authp; +ub4 init_mode; +{ + (void) printf("Environment setup ....\n"); + + /* Initialize the OCI Process */ + if (OCIInitialize(init_mode, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + /* Inititialize the OCI Environment */ + if (OCIEnvInit((OCIEnv **) envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + /* Allocate a service handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on svchp\n"); + return OCI_ERROR; + } + + /* Allocate an error handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on errhp\n"); + return OCI_ERROR; + } + + /* Allocate a server handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on srvhp\n"); + return OCI_ERROR; + } + + /* Allocate a authentication handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on authp\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/* ----------------------------------------------------------------- */ +/* Attach to server with a given mode. */ +/* ----------------------------------------------------------------- */ +sword attach_server(mode, srvhp, errhp, svchp) +ub4 mode; +OCIServer *srvhp; +OCIError *errhp; +OCISvcCtx *svchp; +{ + text *cstring = (text *)""; + + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + /* Set the server handle in the service handle */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet() server attribute\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} +/* ----------------------------------------------------------------- */ +/* Logon to the database using given username, password & credentials*/ +/* ----------------------------------------------------------------- */ +sword log_on(authp, errhp, svchp, uid, pwd, credt, mode) +OCISession *authp; +OCIError *errhp; +OCISvcCtx *svchp; +text *uid; +text *pwd; +ub4 credt; +ub4 mode; +{ + /* Set attributes in the authentication handle */ + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *) uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet() userid\n"); + return OCI_ERROR; + } + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *) pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + (void) printf("Logging on as %s ....\n", uid); + + if (OCISessionBegin(svchp, errhp, authp, credt, mode)) + { + (void) printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + (void) printf("%s logged on.\n", uid); + + /* Set the authentication handle in the Service handle */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet() session\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/*---------------------------------------------------------------------*/ +/* Allocate all required bind handles */ +/*---------------------------------------------------------------------*/ + +sword alloc_bind_handle(stmthp, bndhp, nbinds) +OCIStmt *stmthp; +OCIBind *bndhp[]; +int nbinds; +{ + int i; + /* + * This function allocates the specified number of bind handles + * from the given statement handle. + */ + for (i = 0; i < nbinds; i++) + if (OCIHandleAlloc((dvoid *)stmthp, (dvoid **)&bndhp[i], + (ub4)OCI_HTYPE_BIND, (CONST size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() bind handle\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/* ----------------------------------------------------------------- */ +/* Free the specified handles */ +/* ----------------------------------------------------------------- */ +void free_handles(envhp, svchp, srvhp, errhp, authp, stmthp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +OCIStmt *stmthp; +{ + (void) printf("Freeing handles ...\n"); + + if (srvhp) + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + if (authp) + (void) OCIHandleFree((dvoid *) authp, (ub4) OCI_HTYPE_SESSION); + if (stmthp) + (void) OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT); + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV); + + return; +} + +/* ----------------------------------------------------------------- */ +/* Print the error message */ +/* ----------------------------------------------------------------- */ +void report_error(errhp) +OCIError *errhp; +{ + text msgbuf[512]; + sb4 errcode = 0; + + (void) OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("ERROR CODE = %d\n", errcode); + (void) printf("%.*s\n", 512, msgbuf); + return; +} + +/*-------------------------------------------------------------------*/ +/* Logout and detach from the server */ +/*-------------------------------------------------------------------*/ +void logout_detach_server(svchp, srvhp, errhp, authp, userid) +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +text *userid; +{ + if (OCISessionEnd(svchp, errhp, authp, (ub4) 0)) + { + (void) printf("FAILED: OCISessionEnd()\n"); + report_error(errhp); + } + + (void) printf("%s Logged off.\n", userid); + + if (OCIServerDetach(srvhp, errhp, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionEnd()\n"); + report_error(errhp); + } + + (void) printf("Detached from server.\n"); + + return; +} + +/*---------------------------------------------------------------------*/ +/* Finish demo and clean up */ +/*---------------------------------------------------------------------*/ +sword finish_demo(loggedon, envhp, svchp, srvhp, errhp, authp, stmthp, userid) +boolean loggedon; +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +OCIStmt *stmthp; +text *userid; +{ + + if (loggedon) + logout_detach_server(svchp, srvhp, errhp, authp, userid); + + free_handles(envhp, svchp, srvhp, errhp, authp, stmthp); + + return OCI_SUCCESS; +} + +/*===================== END OF UTILITY FUNCTIONS ======================*/ + + + +int main(argc, argv) +int argc; +char *argv[]; +{ + text *username = (text *)"SCOTT"; + text *password = (text *)"tiger"; + + OCIServer *srvhp; + OCISession *authp; + OCIStmt *stmthp = (OCIStmt *) NULL; + OCIBind *bndhp[MAXBINDS]; + int i; + + if (init_handles(&envhp, &svchp, &errhp, &srvhp, &authp, (ub4)OCI_OBJECT)) + { + (void) printf("FAILED: init_handles()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + if (attach_server((ub4) OCI_DEFAULT, srvhp, errhp, svchp)) + { + (void) printf("FAILED: attach_server()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + if (log_on(authp, errhp, svchp, username, password, + (ub4) OCI_CRED_RDBMS, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: log_on()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + logged_on = TRUE; + + if (OCIHandleAlloc((dvoid *)envhp, (dvoid **) &stmthp, + (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: alloc statement handle\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + /* bind handles will be implicitly allocated in the bind calls */ + /* need to initialize them to null prior to first usage in bind calls */ + + for (i = 0; i < MAXBINDS; i++) + bndhp[i] = (OCIBind *) 0; + + + if (demo_insert(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: demo_insert()\n"); + else + (void) printf("PASSED: demo_insert()\n"); + + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); +} + + +/* ----------------------------------------------------------------- */ +sword bind_input(stmthp, bndhp, errhp) +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + if (OCIBindByPos(stmthp, &bndhp[0], errhp, (ub4) 1, + (dvoid *) in_state[0], (sb4) 2, SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[1], errhp, (ub4) 2, + (dvoid *) in_zip[0], (sb4) 10, SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (OCIBindArrayOfStruct(bndhp[0], errhp, 2, 0, 0, 0) + || OCIBindArrayOfStruct(bndhp[1], errhp, 10, 0, 0, 0)) + { + (void) printf("FAILED: OCIBindArrayOfStruct()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +sword bind_output(stmthp, bndhp, errhp) +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + ub4 i; + + if (OCITypeByName(envhp, errhp, svchp, (CONST text *) 0, + (ub4) 0, (CONST text *) "ADDRESS_OBJECT", + (ub4) strlen((CONST char *) "ADDRESS_OBJECT"), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, &addrtdo)) + { + (void) printf("FAILED: OCITypeByName()\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (OCIBindByName(stmthp, &bndhp[2], errhp, + (text *) ":addref", (sb4) strlen((char *) ":addref"), + (dvoid *) 0, (sb4) sizeof(OCIRef *), SQLT_REF, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[3], errhp, + (text *) ":zip", (sb4) strlen((char *) ":zip"), + (dvoid *) 0, (sb4) MAXZIPLEN, SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC)) + { + (void) printf("FAILED: OCIBindByName()\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (OCIBindObject(bndhp[2], errhp, (OCIType *) addrtdo, + (dvoid **) &addrref[0], (ub4 *) 0, (dvoid **) 0, (ub4 *) 0)) + { + (void) printf("FAILED: OCIBindObject()\n"); + report_error(errhp); + return OCI_ERROR; + } + + + for (i = 0; i < MAXCOLS; i++) + pos[i] = i; + + if (OCIBindDynamic(bndhp[2], errhp, (dvoid *) &pos[0], cbf_no_data, + (dvoid *) &pos[0], cbf_get_data) + || OCIBindDynamic(bndhp[3], errhp, (dvoid *) &pos[1], cbf_no_data, + (dvoid *) &pos[1], cbf_get_data)) + { + (void) printf("FAILED: OCIBindDynamic()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* Intbind callback that does not do any data input. */ +/* ----------------------------------------------------------------- */ +sb4 cbf_no_data(ctxp, bindp, iter, index, bufpp, alenpp, piecep, indpp) +dvoid *ctxp; +OCIBind *bindp; +ub4 iter, index; +dvoid **bufpp; +ub4 *alenpp; +ub1 *piecep; +dvoid **indpp; +{ + *bufpp = (dvoid *) 0; + *alenpp = 0; + null_ind = -1; + *indpp = (dvoid *) &null_ind; + *piecep = OCI_ONE_PIECE; + + return OCI_CONTINUE; +} + + + +/* ----------------------------------------------------------------- */ +/* Outbind callback for returning data. */ +/* ----------------------------------------------------------------- */ +sb4 cbf_get_data(ctxp, bindp, iter, index, bufpp, alenp, piecep, + indpp, rcodepp) +dvoid *ctxp; +OCIBind *bindp; +ub4 iter, index; +dvoid **bufpp; +ub4 **alenp; +ub1 *piecep; +dvoid **indpp; +ub2 **rcodepp; +{ + static ub4 rows = 0; + ub4 pos = *((ub4 *)ctxp); + + if (index == 0) + { + (void) OCIAttrGet((CONST dvoid *)bindp, OCI_HTYPE_BIND, (dvoid *)&rows, + (ub4 *) sizeof(ub4), OCI_ATTR_ROWS_RETURNED, errhp); + rowsret[iter] = (ub2)rows; + + if (alloc_buffer(pos, iter, rows)) + return OCI_ERROR; + } + + switch(pos) + { + case 0: + rl[pos][iter][index] = sizeof(OCIRef *); + *bufpp = (dvoid *) (&addrref[iter]); + break; + case 1: + rl[pos][iter][index] = (ub4) MAXZIPLEN; + *bufpp = (dvoid *) (out_zip[iter]+(index * MAXZIPLEN)); + break; + default: + *bufpp = (dvoid *) 0; + *alenp = (ub4 *) 0; + (void) printf("ERROR: invalid position number: %d\n", *((ub4 *)ctxp)); + } + + *piecep = OCI_ONE_PIECE; + + ind[pos][iter][index] = 0; + *indpp = (dvoid *) &ind[pos][iter][index]; + + rc[pos][iter][index] = 0; + *rcodepp = &rc[pos][iter][index]; + + *alenp = &rl[pos][iter][index]; + + return OCI_CONTINUE; +} + + +/* ----------------------------------------------------------------- */ +/* allocate buffers for callback. */ +/* ----------------------------------------------------------------- */ +sword alloc_buffer(pos, iter, rows) +ub4 pos; +ub4 iter; +ub4 rows; +{ + switch(pos) + { + case 0: + break; + case 1: + out_zip[iter] = (text *) malloc(rows * MAXZIPLEN); + break; + default: + (void) printf("ERROR: invalid position number: %d\n", pos); + return OCI_ERROR; + } + + ind[pos][iter] = (short *) malloc(rows * sizeof(short)); + rc[pos][iter] = (ub2 *) malloc(rows * sizeof(ub2)); + rl[pos][iter] = (ub4 *) malloc(rows * sizeof(ub4)); + + return OCI_SUCCESS; +} + + + + +/* ----------------------------------------------------------------- */ +/* demo for INSERT with RETURNING clause. */ +/* ----------------------------------------------------------------- */ +sword demo_insert(svchp, stmthp, bndhp, errhp) +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + int i; + address *addr; + text *sqlstmt = (text *) "INSERT INTO EXTADDR E VALUES (:1, :2) \ + RETURNING REF(E), ZIP INTO :addref, :zip"; + + for (i = 0; i < MAXITER; i++) + { + memset((void *) in_state[i], (int)'A' + i%26, (size_t) 2); + (void) sprintf((char *) in_zip[i], "%d", 91200 + i); + in_zip[i][5] = '\0'; + + if (OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_REF, + (OCIType *) 0, (dvoid *) 0, OCI_DURATION_SESSION, + FALSE, (dvoid **) &addrref[i])) + { + (void) printf("FAILED: OCIObjectNew()\n"); + report_error(errhp); + return OCI_ERROR; + } + } + + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (bind_input(stmthp, bndhp, errhp)) + return OCI_ERROR; + + if (bind_output(stmthp, bndhp, errhp)) + return OCI_ERROR; + + + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) MAXITER, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + + for (i = 0; i < MAXITER; i++) + { + addr = (address *) 0; + + if (addrref[i]) + { + if (OCIObjectPin(envhp, errhp, addrref[i], (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&addr)) + { + (void) printf("FAILED: OCIObjectPin()\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (addr) + (void) printf("address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + else + (void) printf("Pinned address pointer is null\n"); + + if (OCIObjectUnpin(envhp, errhp, (dvoid *) addr)) + { + (void) printf("FAILED: OCIObjectUnPin()\n"); + report_error(errhp); + return OCI_ERROR; + } + } + else + (void) printf("%dth Address REF is NULL\n", i+1); + } + + + for (i = 0; i < MAXITER; i++) + (void) OCIObjectMarkDelete(envhp, errhp, (dvoid *) addrref[i]); + + return OCI_SUCCESS; +} + + +/* end of file cdemodr3.c */ + diff --git a/cdemodr3.h b/cdemodr3.h new file mode 100644 index 0000000..db15694 --- /dev/null +++ b/cdemodr3.h @@ -0,0 +1,108 @@ +/* + * $Header: cdemodr3.h 14-jul-99.12:44:57 mjaeger Exp $ + */ + +/* Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +*/ + +/* NOTE: See 'header_template.doc' in the 'doc' dve under the 'forms' + directory for the header file template that includes instructions. +*/ + +/* + NAME + cdemodr3.h - + + DESCRIPTION + + + RELATED DOCUMENTS + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 10/01/98 - include stdlib.h - bug 714175 + azhao 06/03/97 - Creation + +*/ + +#include +#include +#include +#include + +#define MAXBINDS 5 +#define MAXITER 5 +#define MAXCOLS 2 +#define MAXZIPLEN 10 + +struct address +{ + OCIString *state; + OCIString *zip; +}; + +typedef struct address address; + +struct null_address +{ + sb2 null_address; + sb2 null_state; + sb2 null_zip; +}; + +typedef struct null_address null_address; + + +int main(/*_ int argc, char *argv[] _*/); +sword init_handles(/*_ OCIEnv **envhp, OCISvcCtx **svchp, + OCIError **errhp, OCIServer **svrhp, + OCISession **authp, ub4 mode _*/); + +sword attach_server(/*_ ub4 mode, OCIServer *srvhp, + OCIError *errhp, OCISvcCtx *svchp _*/); +sword log_on(/*_ OCISession *authp, OCIError *errhp, OCISvcCtx *svchp, + text *uid, text *pwd, ub4 credt, ub4 mode _*/); +sword alloc_bind_handle(/*_ OCIStmt *stmthp, OCIBind *bndhp[], int nbinds _*/); + +void free_handles(/*_ OCIEnv *envhp, OCISvcCtx *svchp, OCIServer *srvhp, + OCIError *errhp, OCISession *authp, OCIStmt *stmthp _*/); +void report_error(/*_ OCIError *errhp _*/); +void logout_detach_server(/*_ OCISvcCtx *svchp, OCIServer *srvhp, + OCIError *errhp, OCISession *authp, + text *userid _*/); +sword finish_demo(/*_ boolean loggedon, OCIEnv *envhp, OCISvcCtx *svchp, + OCIServer *srvhp, OCIError *errhp, OCISession *authp, + OCIStmt *stmthp, text *userid _*/); +sword demo_insert(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_input(/*_ OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_output(/*_ OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp _*/); +sb4 cbf_no_data(/*_ dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index, + dvoid **bufpp, ub4 *alenpp, ub1 *piecep, dvoid **indpp _*/); +sb4 cbf_get_data(/*_ dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index, + dvoid **bufpp, ub4 **alenpp, ub1 *piecep, + dvoid **indpp, ub2 **rcodepp _*/); +sword alloc_buffer(/*_ ub4 pos, ub4 iter, ub4 rows _*/); + diff --git a/cdemodr3.sql b/cdemodr3.sql new file mode 100644 index 0000000..535f324 --- /dev/null +++ b/cdemodr3.sql @@ -0,0 +1,34 @@ +rem +rem $Header: cdemodr3.sql 14-jul-99.13:51:06 mjaeger Exp $ +rem +rem cdemodr3.sql +rem +rem Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemodr3.sql - setup for cdemodr3.c +rem +rem DESCRIPTION +rem create type and table used for cdemodr3.c +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem svedala 09/11/98 - a "/" required after create type - bug 717842 +rem azhao 06/03/97 - Created +rem + +connect scott/tiger + +drop table extaddr; +drop type address_object; + +create type address_object as object (state char(2), zip char(10)); +/ + +create table extaddr of address_object; + +quit + diff --git a/cdemodsa.c b/cdemodsa.c new file mode 100644 index 0000000..1225ee4 --- /dev/null +++ b/cdemodsa.c @@ -0,0 +1,796 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodsa.c 10-oct-2006.14:39:59 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemodsa.c - + + DESCRIPTION + + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + stsun 06/18/04 - bug3698329: check null str for strncpy + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + svedala 05/22/98 - modify describe_typeattr + azhao 06/03/97 - fix lint errors + sgollapu 05/30/97 - Creation + +*/ + +/* + * -- cdemodsa.c -- + * An example program which describes the table EMPNML created by running + * the sql script CDEMODSA.SQL as SCOTT/TIGER. The table EMPNML consists of + * two columns, one of which is an ADT PERSON defined as containing a name + * (CHAR(20)), age (NUMBER), and address (an ADT). + * + * When successfully executed, the program will print the user defined type + * PERSON and its attributes, and then the table EMPNML. Note that the + * schema name and type name are printed for user-defined types only. + */ + +#include +#include +#include +#include +#include + +static text *username = (text *) "SCOTT"; /* username */ +static text *password = (text *) "tiger"; /* password */ +static text *tablename = (text *) "EMPNML"; /* tablename */ + +static OCIEnv *envhp = (OCIEnv *)0; +static OCIServer *srvhp = (OCIServer *)0; +static OCIError *errhp = (OCIError *)0; +static OCISvcCtx *svchp = (OCISvcCtx *)0; +static OCIStmt *stmhp = (OCIStmt *)0; +static OCIDescribe *dschp = (OCIDescribe *)0; +static OCISession *authp = (OCISession *)0; + +static void initialize(/*_ void _*/); +static void logon(/*_ void _*/); +static void describe_table(/*_ void _*/); +static void describe_column(/*_ OCIParam *parmp, ub4 parmcnt _*/); +static void describe_type(/*_ OCIParam *parmp _*/); +static void describe_typeattr(/*_ OCIParam *parmp, ub4 num_attr _*/); +static void describe_typecoll(/*_ OCIParam *parmp, sword typecode _*/); +static void describe_typemethodlist(/*_ OCIParam *parmp, ub4 num_meth, + text *comment _*/); +static void describe_typemethod(/*_ OCIParam *parmp, text *comment _*/); +static void describe_typearg(/*_ OCIParam *parmp, ub1 type, ub4 start, + ub4 end _*/); +static void logout(/*_ void _*/); +static void cleanup(/*_ void _*/); +static void checkerr(/*_ OCIError *errhp, sword status _*/); +int main(/*_ int argc, char *argv[] _*/); + +static sb4 status; + +#define NPOS 30 /* max number of columns */ +#define MAXLEN 128 /* max length of column names */ + + +int main(argc, argv) +int argc; +char *argv[]; +{ + initialize (); + logon (); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmhp, + OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)); + describe_table (); + logout (); + cleanup (); +} + +static void initialize () +{ + printf ("\nInitializing the environment..\n"); + (void) OCIInitialize (OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 ); + + (void) OCIEnvInit ((OCIEnv **) &envhp, OCI_DEFAULT, (size_t) 0, + (dvoid **) 0); + + /* error handle */ + (void) OCIHandleAlloc ((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + /* server contexts */ + (void) OCIHandleAlloc ((dvoid *) envhp, (dvoid **) &srvhp, OCI_HTYPE_SERVER, + (size_t) 0, (dvoid **) 0); + + (void) OCIHandleAlloc ((dvoid *) envhp, (dvoid **) &svchp, OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0); + + (void) OCIServerAttach (srvhp, errhp, (text *)"", + strlen(""), 0); + + /* set attribute server context in the service context */ + (void) OCIAttrSet ((dvoid *) svchp, OCI_HTYPE_SVCCTX, (dvoid *)srvhp, + (ub4) 0, OCI_ATTR_SERVER, (OCIError *) errhp); +} + +static void logon () +{ + printf ("Logging on as %s/%s..", username, password); + (void) OCIHandleAlloc ((dvoid *) envhp, (dvoid **)&authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0); + + (void) OCIAttrSet ((dvoid *)authp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)username, (ub4)strlen((char *)username), + OCI_ATTR_USERNAME, errhp); + + (void) OCIAttrSet ((dvoid *)authp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)password, (ub4)strlen((char *)password), + OCI_ATTR_PASSWORD, errhp); + + checkerr (errhp, OCISessionBegin (svchp, errhp, authp, OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)); + printf ("Logged on\n"); + + (void) OCIAttrSet ((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, + (ub4) OCI_ATTR_SESSION, errhp); +} + + +static void describe_table () +{ + sword retval; + OCIParam *parmp, *collst; + ub4 parmcnt; + ub2 numcols; + ub4 objid = 0; + + checkerr (errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + if ((retval = OCIDescribeAny(svchp, errhp, (dvoid *)tablename, + (ub4) strlen((char *) tablename), + OCI_OTYPE_NAME, (ub1)1, + OCI_PTYPE_TABLE, dschp)) != OCI_SUCCESS) + { + if (retval == OCI_NO_DATA) + { + printf("NO DATA: OCIDescribeAny on %s\n", tablename); + } + else /* OCI_ERROR */ + { + printf( "ERROR: OCIDescribeAny on %s\n", tablename); + checkerr(errhp, retval); + return; + } + } + else + { + /* get the parameter descriptor */ + checkerr (errhp, OCIAttrGet((dvoid *)dschp, (ub4)OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, + (OCIError *)errhp)); + + /* Get the attributes of the table */ + checkerr (errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &objid, (ub4 *) 0, + (ub4) OCI_ATTR_OBJID, (OCIError *)errhp)); + /* column list of the table */ + checkerr (errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &collst, (ub4 *) 0, + (ub4) OCI_ATTR_LIST_COLUMNS, (OCIError *)errhp)); + /* number of columns */ + checkerr (errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &numcols, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_COLS, (OCIError *)errhp)); + /* now describe each column */ + describe_column(collst, numcols); + } + /* free the describe handle */ + OCIHandleFree((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE); +} + +static void describe_column(parmp, parmcnt) +OCIParam *parmp; +ub4 parmcnt; +{ + text colname1[NPOS][30], colname2[NPOS][30], colname3[NPOS][30]; + text *namep; + ub4 sizep; + ub2 collen[NPOS]; + ub2 coltyp[NPOS]; + OCIParam *parmdp; + ub4 i, pos; + sword retval; + ub1 precision[NPOS]; + sb1 scale[NPOS]; + + for (pos = 1; pos <= parmcnt; pos++) + { + /* get the parameter descriptor for each column */ + checkerr (errhp, OCIParamGet((dvoid *)parmp, (ub4)OCI_DTYPE_PARAM, errhp, + (dvoid *)&parmdp, (ub4) pos)); + /* column length */ + checkerr (errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &collen[pos-1], (ub4 *) 0, + (ub4) OCI_ATTR_DATA_SIZE, (OCIError *)errhp)); + /* column name */ + checkerr (errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &sizep, + (ub4) OCI_ATTR_NAME, (OCIError *)errhp)); + + if(sizep){ + strncpy((char *)colname1[pos-1], (char *)namep, (size_t) sizep); + } + colname1[pos-1][sizep] = '\0'; + /* schema name */ + checkerr (errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &sizep, + (ub4) OCI_ATTR_SCHEMA_NAME, (OCIError *)errhp)); + + if(sizep){ + strncpy((char *)colname2[pos-1], (char *)namep, (size_t) sizep); + } + colname2[pos-1][sizep] = '\0'; + /* type name */ + checkerr (errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &sizep, + (ub4) OCI_ATTR_TYPE_NAME, (OCIError *)errhp)); + + if(sizep){ + strncpy((char *)colname3[pos-1], (char *)namep, (size_t) sizep); + } + colname3[pos-1][sizep] = '\0'; + /* data type */ + checkerr (errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &coltyp[pos-1], (ub4 *) 0, + (ub4) OCI_ATTR_DATA_TYPE, (OCIError *)errhp)); + /* precision */ + checkerr (errhp, OCIAttrGet ((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &precision[pos-1], (ub4 *) 0, + (ub4) OCI_ATTR_PRECISION, (OCIError *)errhp)); + /* scale */ + checkerr (errhp, OCIAttrGet ((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &scale[pos-1], (ub4 *) 0, + (ub4) OCI_ATTR_SCALE, (OCIError *)errhp)); + + /* if column or attribute is type OBJECT/COLLECTION, describe it by ref */ + if (coltyp[pos-1] == OCI_TYPECODE_OBJECT || + coltyp[pos-1] == OCI_TYPECODE_NAMEDCOLLECTION) + { + OCIDescribe *deshp; + OCIParam *parmhp; + OCIRef *typeref; + + /* get ref to attribute/column type */ + checkerr (errhp, OCIAttrGet ((dvoid *)parmdp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&typeref, (ub4 *)0, + (ub4)OCI_ATTR_REF_TDO, (OCIError *)errhp)); + /* describe it */ + checkerr (errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&deshp, + (ub4)OCI_HTYPE_DESCRIBE, (size_t)0, (dvoid **)0)); + + checkerr (errhp, OCIDescribeAny(svchp, errhp, (dvoid *)typeref, (ub4)0, + OCI_OTYPE_REF, (ub1)1, OCI_PTYPE_TYPE, deshp)); + /* get the parameter descriptor */ + checkerr (errhp, OCIAttrGet((dvoid *)deshp, (ub4)OCI_HTYPE_DESCRIBE, + (dvoid *)&parmhp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, + (OCIError *)errhp)); + /* describe the type */ + describe_type (parmhp); + + /* free describe handle */ + OCIHandleFree((dvoid *) deshp, (ub4) OCI_HTYPE_DESCRIBE); + } + } + + printf ("\n------------------\n"); + printf ("TABLE : %s \n", tablename); + printf ("------------------\n"); + printf ( + "\nColumn Name Schema Length Type Datatype Precision Scale\n"); + printf ( + "_____________________________________________________________________\n"); + for (i = 1; i <= parmcnt; i++) + printf( "%10s%10s%6d%10s%10d%10d%10d\n", colname1[i-1], colname2[i-1], + collen[i-1], colname3[i-1], coltyp[i-1], precision[i-1], scale[i-1]); +} + + +static void describe_type(type_parmp) +OCIParam *type_parmp; +{ + sword retval; + OCITypeCode typecode, + collection_typecode; + text schema_name[MAXLEN], + version_name[MAXLEN], + type_name[MAXLEN]; + text *namep; + ub4 size; /* not used */ + OCIRef *type_ref; /* not used */ + ub2 num_attr, + num_method; + ub1 is_incomplete, + has_table; + OCIParam *list_attr, + *list_method, + *map_method, + *order_method, + *collection_elem; + + printf ("\n\n-----------------\n"); + printf ("USED-DEFINED TYPE\n-----------------\n"); + + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_SCHEMA_NAME, (OCIError *) errhp)); + if(size){ + strncpy((char *)schema_name, (char *)namep, (size_t) size); + } + schema_name[size] = '\0'; + printf ( "Schema: %s\n", schema_name); + + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_NAME, (OCIError *) errhp)); + if(size){ + strncpy ((char *)type_name, (char *)namep, (size_t) size); + } + type_name[size] = '\0'; + printf ( "Name: %s\n", type_name); + + /* get ref of type, although we are not using it here */ + checkerr (errhp, OCIAttrGet((dvoid *)type_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&type_ref, (ub4 *)0, + (ub4)OCI_ATTR_REF_TDO, (OCIError *)errhp)); + + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, + (ub4) OCI_ATTR_TYPECODE, (OCIError *) errhp)); + printf ( "Oracle Typecode: %d\n", typecode); + + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_VERSION, (OCIError *) errhp)); + if(size){ + strncpy ((char *)version_name, (char *)namep, (size_t) size); + } + version_name[size] = '\0'; + printf ( "Version: %s\n", version_name); + + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_incomplete, (ub4 *) 0, + (ub4) OCI_ATTR_IS_INCOMPLETE_TYPE, (OCIError *)errhp)); + printf ( "Is incomplete: %d\n", is_incomplete); + + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &has_table, (ub4 *) 0, + (ub4) OCI_ATTR_HAS_NESTED_TABLE, (OCIError *)errhp)); + printf ( "Has nested table: %d\n", has_table); + + /* describe type attributes if any */ + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &num_attr, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_TYPE_ATTRS, (OCIError *) errhp)); + printf ( "Number of attrs: %d\n", num_attr); + if (num_attr > 0) + { + /* get the list of attributes and pass it on */ + checkerr (errhp, OCIAttrGet((dvoid *)type_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&list_attr, (ub4 *)0, + (ub4)OCI_ATTR_LIST_TYPE_ATTRS, (OCIError *)errhp)); + describe_typeattr(list_attr, num_attr); + } + + /* describe the collection element if this is a collection type */ + if (typecode == OCI_TYPECODE_NAMEDCOLLECTION) + { + checkerr (errhp, OCIAttrGet((dvoid *)type_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&collection_typecode, (ub4 *)0, + (ub4)OCI_ATTR_COLLECTION_TYPECODE, (OCIError *)errhp)); + printf ( "Collection typecode: %d\n", collection_typecode); + + checkerr (errhp, OCIAttrGet((dvoid *)type_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&collection_elem, (ub4 *)0, + (ub4)OCI_ATTR_COLLECTION_ELEMENT, (OCIError *)errhp)); + + describe_typecoll(collection_elem, collection_typecode); + } + + /* describe the MAP method if any */ + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &map_method, (ub4 *) 0, + (ub4) OCI_ATTR_MAP_METHOD, (OCIError *)errhp)); + if (map_method != (dvoid *)0) + describe_typemethod(map_method,(text *)"TYPE MAP METHOD\n---------------"); + + /* describe the ORDER method if any; note that this is mutually exclusive */ + /* with MAP */ + checkerr (errhp, OCIAttrGet((dvoid *)type_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&order_method, (ub4 *)0, + (ub4)OCI_ATTR_ORDER_METHOD, (OCIError *)errhp)); + if (order_method != (dvoid *)0) + describe_typemethod(order_method, + (text *)"TYPE ORDER METHOD\n-----------------"); + + /* describe all methods (including MAP/ORDER) */ + checkerr (errhp, OCIAttrGet((dvoid *)type_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&num_method, (ub4 *)0, + (ub4)OCI_ATTR_NUM_TYPE_METHODS, (OCIError *)errhp)); + printf("Number of methods: %d\n", num_method); + if (num_method > 0) + { + checkerr (errhp, OCIAttrGet((dvoid *)type_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&list_method, (ub4 *)0, + (ub4)OCI_ATTR_LIST_TYPE_METHODS, (OCIError *)errhp)); + + describe_typemethodlist(list_method, num_method, + (text *)"TYPE METHOD\n-----------"); + } +} + +static void describe_typeattr(attrlist_parmp, num_attr) +OCIParam *attrlist_parmp; +ub4 num_attr; +{ + OCIParam *attr_parmp; + sword retval; + text *attr_name, + *schema_name, + *type_name; + ub4 namesize, snamesize, tnamesize; + ub4 size; + ub2 datasize; + OCITypeCode typecode; + ub2 datatype; + ub1 precision; + sb1 scale; + ub4 i, + pos; + + printf( + "\nAttr Name Schema Type Length Typ Datatyp Pre Scal\n"); + printf( + "____________________________________________________________________\n"); + + for (pos = 1; pos <= num_attr; pos++) + { + /* get the attribute's describe handle from the parameter */ + checkerr (errhp, OCIParamGet((dvoid *)attrlist_parmp, (ub4)OCI_DTYPE_PARAM, + errhp, (dvoid *)&attr_parmp, (ub4)pos)); + + /* obtain attribute values for the type's attributes */ + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&attr_name, (ub4 *)&namesize, + (ub4)OCI_ATTR_NAME, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&schema_name, (ub4 *)&snamesize, + (ub4)OCI_ATTR_SCHEMA_NAME, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&type_name, (ub4 *)&tnamesize, + (ub4)OCI_ATTR_TYPE_NAME, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&datasize, (ub4 *)0, + (ub4)OCI_ATTR_DATA_SIZE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&typecode, (ub4 *)0, + (ub4)OCI_ATTR_TYPECODE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&datatype, (ub4 *)0, + (ub4)OCI_ATTR_DATA_TYPE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&precision, (ub4 *)0, + (ub4)OCI_ATTR_PRECISION, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&scale, (ub4 *)0, + (ub4)OCI_ATTR_SCALE, (OCIError *)errhp)); + + /* if typecode == OCI_TYPECODE_OBJECT, you can proceed to describe it + recursively by calling describe_type() with its name; or you can + obtain its OCIRef by using OCI_ATTR_REF_TDO, and then describing the + type by REF */ + + /* print values for the attribute */ + printf("%10.*s%10.*s%16.*s%8d%4d%8d%4d%5d\n", namesize, attr_name, + snamesize, schema_name, tnamesize, type_name, datasize, + typecode, datatype, precision, scale); + } + printf("\n"); +} + + +static void describe_typecoll(collelem_parmp, coll_typecode) +OCIParam *collelem_parmp; +sword coll_typecode; /* OCI_TYPECODE_VARRAY or OCI_TYPECODE_TABLE */ +{ + text *attr_name, + *schema_name, + *type_name; + ub4 size; + ub2 datasize; + ub4 num_elems; + OCITypeCode typecode; + ub2 datatype; + sword retval; + + checkerr (errhp, OCIAttrGet((dvoid *)collelem_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&schema_name, (ub4 *)&size, + (ub4)OCI_ATTR_SCHEMA_NAME, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)collelem_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&type_name, (ub4 *)&size, + (ub4)OCI_ATTR_TYPE_NAME, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)collelem_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&datasize, (ub4 *)0, + (ub4)OCI_ATTR_DATA_SIZE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)collelem_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&typecode, (ub4 *)0, + (ub4)OCI_ATTR_TYPECODE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)collelem_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&datatype, (ub4 *)0, + (ub4)OCI_ATTR_DATA_TYPE, (OCIError *)errhp)); + if (coll_typecode == OCI_TYPECODE_VARRAY) + checkerr (errhp, OCIAttrGet((dvoid *)collelem_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&num_elems, (ub4 *)0, + (ub4)OCI_ATTR_NUM_ELEMS, (OCIError *)errhp)); + else num_elems = 0; + + printf("Schema Type Length Type Datatype Elements\n"); + printf("_________________________________________________________\n"); + + printf("%10s%16s%9d%5d%9d%8d\n", schema_name, type_name, + datasize, typecode, datatype, num_elems); +} + +static void describe_typemethodlist(methodlist_parmp, num_method, comment) +OCIParam *methodlist_parmp; +ub4 num_method; +text *comment; +{ + sword retval; + OCIParam *method_parmp; + ub4 i, pos; + /* traverse the method list */ + for (pos = 1; pos <= num_method; pos++) + { + checkerr (errhp, OCIParamGet((dvoid *)methodlist_parmp, + (ub4)OCI_DTYPE_PARAM, errhp, + (dvoid *)&method_parmp, (ub4)pos)); + describe_typemethod(method_parmp, comment); + } +} + +static void describe_typemethod(method_parmp, comment) +OCIParam *method_parmp; +text *comment; +{ + sword retval; + text *method_name; + ub4 size; + ub2 ovrid; + ub4 num_arg; + ub1 has_result, + is_map, + is_order; + OCITypeEncap encap; + OCIParam *list_arg; + + /* print header */ + printf("\n%s\n", comment); + + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&method_name, (ub4 *)&size, + (ub4)OCI_ATTR_NAME, (OCIError *)errhp)); + printf("Method Name: %s\n", method_name); + + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&ovrid, (ub4 *)0, + (ub4)OCI_ATTR_OVERLOAD_ID, (OCIError *)errhp)); + printf("Overload ID: %d\n", ovrid); + + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&encap, (ub4 *)0, + (ub4)OCI_ATTR_ENCAPSULATION, (OCIError *)errhp)); + printf("Encapsulation: %s\n", + (encap == OCI_TYPEENCAP_PUBLIC) ? "public" : "private"); + + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&is_map, (ub4 *)0, + (ub4)OCI_ATTR_IS_MAP, (OCIError *)errhp)); + printf("Is map: %d\n", is_map); + + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&is_order, (ub4 *)0, + (ub4)OCI_ATTR_IS_ORDER, (OCIError *)errhp)); + printf("Is order: %d\n", is_order); + + /* retrieve the argument list, includes result */ + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&list_arg, (ub4 *)0, + (ub4)OCI_ATTR_LIST_ARGUMENTS, (OCIError *)errhp)); + + /* if this is a function (has results, then describe results */ + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&has_result, (ub4 *)0, + (ub4)OCI_ATTR_HAS_RESULT, (OCIError *)errhp)); + printf("Has result: %d\n", has_result); + if (has_result) + { + describe_typearg(list_arg, OCI_PTYPE_TYPE_RESULT, 0, 1); + } + + /* describe each argument */ + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&num_arg, (ub4 *)0, + (ub4)OCI_ATTR_NUM_ARGS, (OCIError *)errhp)); + printf("Number of args: %d\n", num_arg); + if (num_arg > 0) + { + describe_typearg(list_arg, OCI_PTYPE_TYPE_ARG, 1, num_arg+1); + } +} + +static void describe_typearg (arglist_parmp, type, start, end) +OCIParam *arglist_parmp; +ub1 type; +ub4 start; +ub4 end; +{ + OCIParam *arg_parmp; + sword retval; + text *arg_name, + *schema_name, + *type_name; + ub2 position; + ub2 level; + ub1 has_default; + OCITypeParamMode iomode; + ub4 size; + OCITypeCode typecode; + ub2 datatype; + ub4 i, + pos; + + /* print header */ + printf("Name Pos Type Datatype Lvl Def Iomode SchName TypeName\n"); + printf( + "________________________________________________________________\n"); + + for (pos = start; pos < end; pos++) + { + /* get the attribute's describe handle from the parameter */ + checkerr (errhp, OCIParamGet((dvoid *)arglist_parmp, (ub4)OCI_DTYPE_PARAM, + errhp, (dvoid *)&arg_parmp, (ub4)pos)); + + /* obtain attribute values for the type's attributes */ + /* if this is a result, it has no name, so we give it one */ + if (type == OCI_PTYPE_TYPE_RESULT) + { + arg_name = (text *)"RESULT"; + } + else if (type == OCI_PTYPE_TYPE_ARG) + { + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&arg_name, (ub4 *)&size, + (ub4)OCI_ATTR_NAME, (OCIError *)errhp)); + } + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&position, (ub4 *)0, + (ub4)OCI_ATTR_POSITION, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&typecode, (ub4 *)0, + (ub4)OCI_ATTR_TYPECODE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&datatype, (ub4 *)0, + (ub4)OCI_ATTR_DATA_TYPE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&level, (ub4 *)0, + (ub4)OCI_ATTR_LEVEL, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&has_default, (ub4 *)0, + (ub4)OCI_ATTR_HAS_DEFAULT, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&iomode, (ub4 *)0, + (ub4)OCI_ATTR_IOMODE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&schema_name, (ub4 *)&size, + (ub4)OCI_ATTR_SCHEMA_NAME, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&type_name, (ub4 *)&size, + (ub4)OCI_ATTR_TYPE_NAME, (OCIError *)errhp)); + + /* if typecode == OCI_TYPECODE_OBJECT, you can proceed to describe it + recursively by calling describe_type() with its name; or you can + obtain its OCIRef by using OCI_ATTR_REF_TDO, and then describing the + type by REF */ + + /* print values for the argument */ + printf ("%8s%5d%5d%9d%4d%3c%7d%8s%14s\n", arg_name, position, + typecode, datatype, level, has_default ? 'y' : 'n', + iomode, schema_name, type_name); + } +} + +static void logout() +{ + printf ("\n\nFreeing statement handle..\n"); + OCIHandleFree ((dvoid *) stmhp, (ub4) OCI_HTYPE_STMT); + + printf ("Logging off...\n"); + OCISessionEnd (svchp, errhp, authp, (ub4) 0); +} + +static void cleanup() +{ + printf ("\nFreeing global structures..\n"); + if (errhp) OCIServerDetach (srvhp, errhp, (ub4) OCI_DEFAULT ); + if (srvhp) OCIHandleFree((dvoid *) srvhp, (CONST ub4) OCI_HTYPE_SERVER); + if (svchp) OCIHandleFree((dvoid *) svchp, (CONST ub4) OCI_HTYPE_SVCCTX); + if (errhp) OCIHandleFree((dvoid *) errhp, (CONST ub4) OCI_HTYPE_ERROR); + if (authp) OCIHandleFree((dvoid *) authp, (CONST ub4) OCI_HTYPE_SESSION); +} + + +static void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet ((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + +/* end of file cdemodsa.c */ + diff --git a/cdemodsa.sql b/cdemodsa.sql new file mode 100644 index 0000000..754469f --- /dev/null +++ b/cdemodsa.sql @@ -0,0 +1,48 @@ +rem +rem $Header: cdemodsa.sql 14-jul-99.13:51:36 mjaeger Exp $ +rem +rem cdemodsa.sql +rem +rem Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemodsa.sql - +rem +rem DESCRIPTION +rem +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem svedala 09/11/98 - a "/" required after create type - bug 717842 +rem azhao 06/03/97 - add connect scott/tiger +rem sgollapu 05/30/97 - Created +rem + +connect scott/tiger; + +set echo on; + +drop table customerobj; +drop type address_object; +drop type person; +drop table empnml; +drop table empref; + +create type address_object as object (state char(2), zip char(10)); +/ + +create table customerobj (custno number, addr REF address_object); + +create type person as object(name char(20), age number, + address address_object); +/ + +create table empnml (emp_id number, emp_info person); +create table empref (emp_id number, emp_info REF person); + +commit; + +set echo off; diff --git a/cdemodsc.c b/cdemodsc.c new file mode 100644 index 0000000..2690d72 --- /dev/null +++ b/cdemodsc.c @@ -0,0 +1,870 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodsc.c 14-jul-99.13:10:30 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + NAME + cdemodsc.c + DESCRIPTION + Tests OCIDescribeAny on ADT. + + cdemodsc takes the user name and password and a type name + (created in the database) as command line arguments and + dumps all the information about the type -- + its attribute types, methods, + method parameters, etc. + + NOTES + see routines. + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + echen 06/04/97 - fix the include files + cchau 05/29/97 - creation +*/ + +#ifndef CDEMODSC_ORACLE +#include "cdemodsc.h" +#endif + +/*****************************************************************************/ +static void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + break; + case OCI_NEED_DATA: + break; + case OCI_NO_DATA: + break; + case OCI_ERROR: + (void) OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("Error - %s\n", errbuf); + exit(1); + break; + case OCI_INVALID_HANDLE: + break; + case OCI_STILL_EXECUTING: + break; + case OCI_CONTINUE: + break; + default: + break; + } +} + +/*----------------------------------------------------------------------*/ + +static void chk_methodlst(envhp, errhp, svchp, parmp, count, comment) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +dvoid *parmp; +ub4 count; +const text *comment; +{ + sword retval; + ub4 pos; + dvoid *parmdp; + + for (pos = 1; pos <= count; pos++) + { + checkerr(errhp, OCIParamGet((dvoid *)parmp, (ub4) OCI_DTYPE_PARAM, errhp, + (dvoid *)&parmdp, (ub4) pos)); + chk_method(envhp, errhp, svchp, parmdp, comment); + } +} + +/*----------------------------------------------------------------------*/ + +static void chk_method(envhp, errhp, svchp, parmp, comment) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +dvoid *parmp; +const text *comment; +{ + sword retval; + text method[MAXNAME], + *namep; + ub4 size; + ub4 num_arg; + ub1 has_result, + is_selfish, + is_virtual, + is_inline, + is_constructor, + is_destructor, + is_constant, + is_operator, + is_map, + is_order, + is_rnds, + is_rnps, + is_wnds, + is_wnps; + OCITypeEncap encap; + dvoid *list_arg; + + /* get name of the method */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)method, (char *)namep, (size_t) size); + method[size] = '\0'; + + /* get the number of arguments */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &num_arg, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_ARGS, (OCIError *) errhp)); + + /* encapsulation (public?) */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &encap, (ub4 *) 0, + (ub4) OCI_ATTR_ENCAPSULATION, (OCIError *) errhp)); + + /* has result */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&has_result, (ub4 *)0, + (ub4)OCI_ATTR_HAS_RESULT, (OCIError *) errhp)); + + /* map method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_map, (ub4 *)0, + (ub4)OCI_ATTR_IS_MAP, (OCIError *) errhp)); + + /* order method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_order, (ub4 *)0, + (ub4)OCI_ATTR_IS_ORDER, (OCIError *) errhp)); + + /* selfish method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_selfish, (ub4 *)0, + (ub4)OCI_ATTR_IS_SELFISH, (OCIError *) errhp)); + + /* virtual method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_virtual, (ub4 *)0, + (ub4)OCI_ATTR_IS_VIRTUAL, (OCIError *) errhp)); + + /* inline method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_inline, (ub4 *)0, + (ub4)OCI_ATTR_IS_INLINE, (OCIError *) errhp)); + + /* constant method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_constant, (ub4 *)0, + (ub4)OCI_ATTR_IS_CONSTANT, (OCIError *) errhp)); + + /* operator */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_operator, (ub4 *)0, + (ub4)OCI_ATTR_IS_OPERATOR, (OCIError *) errhp)); + + /* constructor method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_constructor, (ub4 *)0, + (ub4)OCI_ATTR_IS_CONSTRUCTOR, (OCIError *) errhp)); + + /* destructor method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_destructor, (ub4 *)0, + (ub4)OCI_ATTR_IS_DESTRUCTOR, (OCIError *) errhp)); + + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_rnds, (ub4 *)0, + (ub4)OCI_ATTR_IS_RNDS, (OCIError *) errhp)); + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_rnps, (ub4 *)0, + (ub4)OCI_ATTR_IS_RNPS, (OCIError *) errhp)); + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_wnds, (ub4 *)0, + (ub4)OCI_ATTR_IS_WNDS, (OCIError *) errhp)); + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_wnps, (ub4 *)0, + (ub4)OCI_ATTR_IS_WNPS, (OCIError *) errhp)); + + /* get list of arguments */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&list_arg, (ub4 *)0, + (ub4)OCI_ATTR_LIST_ARGUMENTS, (OCIError *) errhp)); + + SPACING; + printf ( "\n%s\n", comment); + SPACING; + printf ( "Name: %s\n", method); + SPACING; + printf ( "Number of args: %d\n", num_arg); + SPACING; + printf ( "Encapsulation: %s\n", + (encap==OCI_TYPEENCAP_PUBLIC) ? "public" : "private"); + SPACING; + printf ( "Has result: %d\n", has_result); + SPACING; + printf ( "Is selfish: %d\n", is_selfish); + SPACING; + printf ( "Is virtual: %d\n", is_virtual); + SPACING; + printf ( "Is inline: %d\n", is_inline); + SPACING; + printf ( "Is constructor: %d\n", is_constructor); + SPACING; + printf ( "Is desctructor: %d\n", is_destructor); + SPACING; + printf ( "Is constant: %d\n", is_constant); + SPACING; + printf ( "Is operator: %d\n", is_operator); + SPACING; + printf ( "Is map: %d\n", is_map); + SPACING; + printf ( "Is order: %d\n", is_order); + SPACING; + printf ( "Is RNDS: %d\n", is_rnds); + SPACING; + printf ( "Is RNPS: %d\n", is_rnps); + SPACING; + printf ( "Is WNPS: %d\n", is_wnps); + printf("\n"); + + if (has_result) + chk_arg(envhp, errhp, svchp, list_arg, OCI_PTYPE_TYPE_RESULT, 0, 1); + if (num_arg > 0) + chk_arg(envhp, errhp, svchp, list_arg, OCI_PTYPE_TYPE_ARG, 1, num_arg + 1); +} + +/*----------------------------------------------------------------------*/ + +static void chk_arglst(envhp, errhp, svchp, parmp) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +dvoid *parmp; +{ + dvoid *arglst; + ub4 numargs; + ub1 ptype; + sword retval; + + /* get list of arguments */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &arglst, (ub4 *) 0, + (ub4) OCI_ATTR_LIST_ARGUMENTS, (OCIError *) errhp)); + + /* get number of parameters */ + checkerr(errhp, OCIAttrGet((dvoid*) arglst, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &numargs, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_PARAMS, (OCIError *) errhp)); + + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &ptype, (ub4 *) 0, + (ub4) OCI_ATTR_PTYPE, (OCIError *) errhp)); + + switch (ptype) + { + case OCI_PTYPE_FUNC: + chk_arg (envhp, errhp, svchp, arglst, OCI_PTYPE_ARG, 0, numargs); + break; + case OCI_PTYPE_PROC: + chk_arg (envhp, errhp, svchp, arglst, OCI_PTYPE_ARG, 1, numargs); + } +} + +/*----------------------------------------------------------------------*/ + +static void chk_arg (envhp, errhp, svchp, parmp, type, start, end) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +dvoid *parmp; +ub1 type; +ub4 start; +ub4 end; +{ + text argname[NPOS][30]; + text *namep; + ub4 sizep; + ub2 collen[NPOS]; + ub2 coldesr[NPOS]; + dvoid *parmdp; + ub4 i, pos; + sword retval; + ub2 level[NPOS]; + ub1 radix[NPOS], def[NPOS]; + ub4 iomode[NPOS]; + ub1 precision[NPOS], scale[NPOS], isnull[NPOS]; + + + for (pos = start; pos < end; pos++) + { + + checkerr(errhp, OCIParamGet((dvoid *)parmp, (ub4) OCI_DTYPE_PARAM, errhp, + (dvoid *)&parmdp, (ub4) pos)); + + /* get data type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &coldesr[pos], (ub4 *) 0, + (ub4) OCI_ATTR_DATA_TYPE, + (OCIError *) errhp)); + + /* method's result has no name */ + iomode[pos] = 0; + def[pos] = 0; + sizep = 0; + if (type != OCI_PTYPE_TYPE_RESULT) + { + /* has default */ + checkerr(errhp, OCIAttrGet((dvoid *)parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&def[pos], (ub4 *)0, + (ub4)OCI_ATTR_HAS_DEFAULT, (OCIError *) errhp)); + + /* get iomode */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &iomode[pos], (ub4 *) 0, + (ub4) OCI_ATTR_IOMODE, (OCIError *) errhp)); + + /* get argument name */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &sizep, + (ub4) OCI_ATTR_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)argname[pos], (char *)namep, (size_t) sizep); + } + argname[pos][sizep] = '\0'; + + /* the following are not for type arguments and results */ + precision[pos] = 0; + scale[pos] = 0; + collen[pos] = 0; + level[pos] = 0; + radix[pos] = 0; + isnull[pos] = FALSE; + if (type != OCI_PTYPE_TYPE_ARG && type != OCI_PTYPE_TYPE_RESULT) + { + /* get the data size */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &collen[pos], (ub4 *) 0, + (ub4) OCI_ATTR_DATA_SIZE, (OCIError *) errhp)); + + /* get the precision of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &precision, (ub4 *) 0, + (ub4) OCI_ATTR_PRECISION, (OCIError *) errhp)); + + /* get the scale of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &scale, (ub4 *) 0, + (ub4) OCI_ATTR_SCALE, (OCIError *) errhp)); + + /* get the level of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &level[pos], (ub4 *) 0, + (ub4) OCI_ATTR_LEVEL, (OCIError *) errhp)); + + /* get the radix of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &radix[pos], (ub4 *) 0, + (ub4) OCI_ATTR_RADIX, (OCIError *) errhp)); + + /* is null */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &isnull, (ub4 *) 0, + (ub4) OCI_ATTR_IS_NULL, (OCIError *) errhp)); + + /* should get error 24328 */ + if (OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &isnull, (ub4 *) 0, + (ub4) OCI_ATTR_INDEX_ONLY, (OCIError *) errhp) + != OCI_ERROR) + printf("ERROR: should get error here\n"); + } + } + + SPACING; + (void) printf("Argument Name Length Datatype Level Radix Default Iomode" + " Prec Scl Null\n"); + SPACING; + (void) printf("___________________________________________________" + "______________________\n"); + for (i = start; i < end; i++) + { + SPACING; + (void) printf( "%15s%6d%8d%6d%6d %c%6d%9d%4d%4d\n", argname[i], + collen[i], coldesr[i], level[i], radix[i], + (def[i])?'y':'n', iomode[i], precision[i], scale[i], + isnull[i]); + } + printf("\n"); + +} + +static void chk_collection (envhp, errhp, svchp, parmp, is_array) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +dvoid *parmp; +sword is_array; +{ + text schema[MAXNAME], + type[MAXNAME], + *namep; + ub4 size; + ub2 len; + ub4 num_elems; + OCITypeCode typecode; + sword retval; + + /* get the data size */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &len, (ub4 *) 0, + (ub4) OCI_ATTR_DATA_SIZE, (OCIError *) errhp)); + + /* get the name of the collection */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_TYPE_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)type, (char *)namep, (size_t) size); + type[size] = '\0'; + + /* get the name of the schema */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_SCHEMA_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)schema, (char *)namep, (size_t) size); + schema[size] = '\0'; + + /* get the data type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, (ub4) OCI_ATTR_DATA_TYPE, + (OCIError *) errhp)); + + num_elems = 0; + if (is_array) + /* get the number of elements */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &num_elems, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_ELEMS, (OCIError *) errhp)); + + SPACING; + (void) + printf ( "Schema Type Length Datatype Elements\n"); + SPACING; + (void) + printf ( "____________________________________________________\n"); + SPACING; + (void) printf( "%10s%16s%6d%11d%9d\n", schema, type, len, typecode, + num_elems); + printf("\n"); +} + +/*----------------------------------------------------------------------*/ + +static void chk_column(envhp, errhp, svchp, parmp, parmcnt) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +dvoid *parmp; +ub4 parmcnt; +{ + text colname1[NPOS][30], colname2[NPOS][30], colname3[NPOS][30]; + text *namep; + ub4 sizep; + ub2 collen[NPOS]; + ub2 coldesr[NPOS]; + dvoid *parmdp; + ub4 i, pos; + sword retval; + + /* loop through all the attributes in the type and get all information */ + for (pos = 1; pos <= parmcnt; pos++) + { + /* get the parameter list for each attribute */ + checkerr(errhp, OCIParamGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, errhp, + (dvoid *)&parmdp, (ub4) pos)); + + /* size of the attribute (non ADT or REF) objects */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &collen[pos-1], (ub4 *) 0, + (ub4) OCI_ATTR_DATA_SIZE, (OCIError *) errhp)); + + /* name of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &sizep, + (ub4) OCI_ATTR_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)colname1[pos-1], (char *)namep, (size_t) sizep); + colname1[pos-1][sizep] = '\0'; + + /* get the schema name */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &sizep, + (ub4) OCI_ATTR_SCHEMA_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)colname2[pos-1], (char *)namep, (size_t) sizep); + colname2[pos-1][sizep] = '\0'; + + /* name of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &sizep, + (ub4) OCI_ATTR_TYPE_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)colname3[pos-1], (char *)namep, (size_t) sizep); + colname3[pos-1][sizep] = '\0'; + + /* get data type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &coldesr[pos-1], (ub4 *) 0, + (ub4) OCI_ATTR_DATA_TYPE, + (OCIError *) errhp)); + + if (coldesr[pos-1] == SQLT_NTY || coldesr[pos-1] == SQLT_REF) + { + /* call tst_desc_type here if the type is ADT or REF */ + tab += 5; + SPACING; + printf("!!!!ATTRIBUTE IS A TYPE OR REF!!!!\n"); + SPACING; + printf("ATTRIBUTE NAME IS %s\n", colname3[pos-1]); + SPACING; + printf("ATTRIBUTE TYPE IS %d\n", coldesr[pos-1]); + tst_desc_type(envhp, errhp, svchp, colname3[pos-1]); + tab -= 5; + printf("\n"); + } + + } + + SPACING; + (void) + printf ( "Column Name Schema Type Length Datatype\n"); + SPACING; + (void) + printf ( "__________________________________________________________\n"); + for (i = 1; i <= parmcnt; i++) + { + SPACING; + (void) printf( "%15s%10s%16s%6d%8d\n", colname1[i-1], colname2[i-1], + colname3[i-1], collen[i-1], coldesr[i-1] ); + } + printf("\n"); +} + +/*----------------------------------------------------------------------*/ + +static void tst_desc_type(envhp, errhp, svchp, objname) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +text *objname; +{ + OCIDescribe *dschp = (OCIDescribe *) 0; + sword retval; + OCITypeCode typecode, + collection_typecode; + text schema[MAXNAME], + version[MAXNAME], + *namep, + *type_name; + ub4 size, + text_len; + OCIRef *type_ref; + ub2 num_attr, + num_method; + ub1 is_incomplete, + is_system, + is_predefined, + is_transient, + is_sysgen, + has_table, + has_lob, + has_file; + dvoid *list_attr, + *list_method, + *map_method, + *order_method, + *collection_dschp, + *some_object; + OCIParam *parmp; + ub1 objtype; + + /* must allocate describe handle first for OCIDescribeAny */ + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + /* call OCIDescribeAny and passing in the type name */ + checkerr(errhp, OCIDescribeAny(svchp, errhp, (text *)objname, + (ub4) strlen((char *)objname), OCI_OTYPE_NAME, (ub1)1, + (ub1) OCI_PTYPE_TYPE, dschp)); + + /* get the parameter list for the requested type */ + checkerr(errhp, OCIAttrGet((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, errhp)); + + /* get the schema name for the requested type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp,(ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_SCHEMA_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)schema, (char *)namep, (size_t) size); + schema[size] = '\0'; + + /* get the type code for the requested type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, + (ub4) OCI_ATTR_TYPECODE, (OCIError *) errhp)); + + /* get other information for collection type */ + if (typecode == OCI_TYPECODE_NAMEDCOLLECTION) + { + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&collection_typecode, (ub4 *)0, + (ub4)OCI_ATTR_COLLECTION_TYPECODE, (OCIError *)errhp)); + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&collection_dschp, (ub4 *)0, + (ub4)OCI_ATTR_COLLECTION_ELEMENT, (OCIError *)errhp)); + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&collection_dschp, (ub4 *)0, + (ub4)OCI_ATTR_COLLECTION_ELEMENT, (OCIError *)errhp)); + } + + /* get the ref to the type descriptor */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &type_ref, (ub4 *) 0, + (ub4) OCI_ATTR_REF_TDO, (OCIError *) errhp)); + + /* get the type version */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_VERSION, (OCIError *) errhp)); + + (void) strncpy((char *)version, (char *)namep, (size_t) size); + version[size] = '\0'; + + /* incomplete type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_incomplete, (ub4 *) 0, + (ub4) OCI_ATTR_IS_INCOMPLETE_TYPE, (OCIError *) errhp)); + + /* system type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_system, (ub4 *) 0, + (ub4) OCI_ATTR_IS_SYSTEM_TYPE, (OCIError *) errhp)); + + /* predefined type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_predefined, (ub4 *) 0, + (ub4) OCI_ATTR_IS_PREDEFINED_TYPE, (OCIError *) errhp)); + + /* transient type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_transient, (ub4 *) 0, + (ub4) OCI_ATTR_IS_TRANSIENT_TYPE, (OCIError *) errhp)); + + /* system generated type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_sysgen, (ub4 *) 0, + (ub4) OCI_ATTR_IS_SYSTEM_GENERATED_TYPE, (OCIError*) errhp)); + + /* has nested table */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &has_table, (ub4 *) 0, + (ub4) OCI_ATTR_HAS_NESTED_TABLE, (OCIError *) errhp)); + + /* has lob */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &has_lob, (ub4 *) 0, + (ub4) OCI_ATTR_HAS_LOB, (OCIError *) errhp)); + + /* has file */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &has_file, (ub4 *) 0, + (ub4) OCI_ATTR_HAS_FILE, (OCIError *) errhp)); + + /* get the list of attributes */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&list_attr, (ub4 *)0, + (ub4)OCI_ATTR_LIST_TYPE_ATTRS, (OCIError *)errhp)); + + /* number of attributes */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &num_attr, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_TYPE_ATTRS, (OCIError *) errhp)); + + /* get method list */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&list_method, (ub4 *)0, + (ub4)OCI_ATTR_LIST_TYPE_METHODS, (OCIError *)errhp)); + + /* get number of methods */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &num_method, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_TYPE_METHODS, (OCIError *) errhp)); + + /* get map method list */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &map_method, (ub4 *) 0, + (ub4) OCI_ATTR_MAP_METHOD, (OCIError *) errhp)); + + /* get order method list*/ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &order_method, (ub4 *) 0, + (ub4) OCI_ATTR_ORDER_METHOD, (OCIError *) errhp)); + + SPACING; + printf ( "TYPE : Attributes : \n"); + SPACING; + printf ( "Schema: %s\n", schema); + SPACING; + printf ( "Typecode: %d\n", typecode); + if (typecode == OCI_TYPECODE_NAMEDCOLLECTION) + { + SPACING; + printf ( "Collection typecode: %d\n", collection_typecode); + } + SPACING; + printf ( "Version: %s\n", version); + SPACING; + printf ( "Number of attrs: %d\n", num_attr); + SPACING; + printf ( "Number of methods: %d\n", num_method); + SPACING; + printf ( "Is incomplete: %d\n", is_incomplete); + SPACING; + printf ( "Is system: %d\n", is_system); + SPACING; + printf ( "Is predefined: %d\n", is_predefined); + SPACING; + printf ( "Is sys-gen: %d\n", is_sysgen); + SPACING; + printf ( "Is transient: %d\n", is_transient); + SPACING; + printf ( "Has nested table: %d\n", has_table); + SPACING; + printf ( "Has LOB: %d\n", has_lob); + SPACING; + printf ( "Has file: %d\n", has_file); + printf("\n"); + + if (num_attr > 0) + chk_column(envhp, errhp, svchp, list_attr, num_attr); + else if (typecode == OCI_TYPECODE_NAMEDCOLLECTION) + chk_collection(envhp, errhp, svchp, collection_dschp, + collection_typecode == OCI_TYPECODE_VARRAY); + if (map_method != (dvoid *)0) + chk_method(envhp, errhp, svchp, map_method, + "TYPE MAP METHOD\n---------------"); + if (order_method != (dvoid *)0) + chk_method(envhp, errhp, svchp, order_method, + "TYPE ORDER METHOD\n-----------------"); + if (num_method > 0) + chk_methodlst(envhp, errhp, svchp, list_method, num_method, + "TYPE METHOD\n-----------"); +} + + +/*****************************************************************************/ +int main(int argc, char *argv[]) +{ + OCIEnv *envhp = (OCIEnv *) 0; + OCIServer *srvhp = (OCIServer *) 0; + OCIError *errhp = (OCIError *) 0; + OCISvcCtx *svchp = (OCISvcCtx *) 0; + OCISession *usrhp = (OCISession *) 0; + dvoid *tmp; + int i; + + tab = 0; + + if (argc < 4) + { + (void) printf( + "Usage -- cdemort \n"); + return (0); + } + + (void) OCIInitialize((ub4) OCI_THREADED | OCI_OBJECT, + (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)()) 0, (void (*)()) 0 ); + + (void) OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &envhp, + (ub4) OCI_HTYPE_ENV, + 52, (dvoid **) &tmp); + + (void) OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp); + + checkerr(errhp, OCIServerAttach( srvhp, errhp, (text *) "", + (sb4) strlen(""), (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp)); + + checkerr(errhp, OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp)); + + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, + (ub4)OCI_HTYPE_SESSION, 0, (dvoid **)0)); + + checkerr(errhp, OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)argv[1], (ub4)strlen(argv[1]), + (ub4)OCI_ATTR_USERNAME, errhp)); + + checkerr(errhp, OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)argv[2], (ub4)strlen(argv[2]), + (ub4)OCI_ATTR_PASSWORD, errhp)); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, + OCI_CRED_RDBMS, OCI_DEFAULT)); + + checkerr(errhp, OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, + (ub4)OCI_ATTR_SESSION, errhp)); + + /* dump an adt with all the types */ + SPACING; + (void) printf("%s\n", argv[3]); + tst_desc_type(envhp, errhp, svchp, argv[3]); + printf("\n"); + + checkerr(errhp, OCISessionEnd (svchp, errhp, usrhp, OCI_DEFAULT)); + + (void) OCIServerDetach( srvhp, errhp, (ub4) OCI_DEFAULT ); + + checkerr(errhp, OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX)); + checkerr(errhp, OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR)); + checkerr(errhp, OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER)); + + return (0); +} + + +/* end of file cdemodsc.c */ + diff --git a/cdemodsc.h b/cdemodsc.h new file mode 100644 index 0000000..e9b3b48 --- /dev/null +++ b/cdemodsc.h @@ -0,0 +1,109 @@ +/* + * $Header: cdemodsc.h 23-jun-2004.17:12:05 aliu Exp $ + */ + +/* Copyright (c) 1997, 2004, Oracle. All rights reserved. +*/ + +/* NOTE: See 'header_template.doc' in the 'doc' dve under the 'forms' + directory for the header file template that includes instructions. +*/ + +/* + NAME + cdemodsc.h - header file for cdemodsc.c + + DESCRIPTION + This file will contain the header information for the cdemodsc.c + + RELATED DOCUMENTS + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + aliu 06/23/04 - fix lrg 1712708 - include header files + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + echen 06/04/97 - fix the include files + cchau 05/29/97 - Creation. +*/ + +/*----------------------------------------------------------------------*/ +#ifndef CDEMODSC +#define CDEMODSC + +#ifndef STDIO +#include +#endif + +#ifndef STDLIB +#include +#endif + +#ifndef STRING +#include +#endif + +#ifndef OCI_ORACLE +#include +#endif + +/*----------------------------------------------------------------------*/ +/* +** #define +*/ + +#define MAXNAME 30 +#define MAXOBJLEN 60 +#define MAXOBJS 7 +#define NPOS 40 +#define SPACING for (glindex = 0; glindex < tab; glindex++)\ + printf(" ") + +/*----------------------------------------------------------------------*/ +/* +** Prototypes for functions in cdemodsc.c +*/ +static void chk_column(/*_ OCIEnv *envhp, OCIError *errhp, + OCISvcCtx *svchp, dvoid *dschp, ub4 parmcnt _*/); +static void chk_method(/*_ OCIEnv *envhp, OCIError *errhp, + OCISvcCtx *svchp, dvoid *dschp, const text *comment _*/); +static void chk_methodlst(/*_ OCIEnv *envhp, OCIError *errhp, + OCISvcCtx *svchp, dvoid *dschp, ub4 count, const text *comment _*/); +static void chk_arglst(/*_ OCIEnv *envhp, OCIError *errhp, + OCISvcCtx *svchp, dvoid *dschp _*/); +static void chk_arg(/*_ OCIEnv *envhp, OCIError *errhp, OCISvcCtx *svchp, + dvoid *dschp, ub1 type, ub4 start, ub4 end _*/); +static void chk_collection (/*_ OCIEnv *envhp, OCIError *errhp, + OCISvcCtx *svchp, dvoid *dschp, sword is_array _*/); +static void tst_desc_type(/*_ OCIEnv *envhp, OCIError *errhp, + OCISvcCtx *svchp, text *objname _*/); +static void checkerr(/*_ OCIError *errhp, sword status _*/); + +/* Prototype for main function */ +int main(/*_ int argc, char *argv[] _*/); +int tab; +int glindex; + +#endif /* CDEMODSC */ + diff --git a/cdemodt.c b/cdemodt.c new file mode 100644 index 0000000..5972237 --- /dev/null +++ b/cdemodt.c @@ -0,0 +1,1225 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodt.c 10-oct-2006.14:39:59 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemodt.c - Datetime/Interval type demo program in OCI + + DESCRIPTION - Demonstrate insertion and selection of timestamp, timestamp + with time zone, timestamp with local time zone, interval year + to month, and interval day to seconds via Bind and Define with + SQL statements. + Demonstrate IN/OUT bind with PL/SQL procedure. + Demonstrate how time zone names work and daylight saving features + using OCIDateTimeConvert() on different values of timestamp with + time zone region. + Demonstrate how daylight saving works with time zone names when + time changes from daylight saving time to standard time or vice + verse using OCIDateTimeIntervalAdd(). + + Note: Before running this program, ensure that the database is started + up with compatible=9.0.0.0.0 and a table CDEMODT_FOO or a procedure + CDEMODT_INS_SEL does not exist in the SCOTT/TIGER sample account. + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + aliu 06/27/01 - Change table and procedure names to be free of conflict with other tests. + aliu 06/12/01 - Fix porting bug 1827600. + aliu 04/24/01 - Merged aliu_dt_demo_oci + aliu 04/24/01 - Modify variable names and main prototype. + aliu 04/23/01 - Update lint warnings. + aliu 04/12/00 - Creation + +*/ + +#ifndef CDEMOXML +#define CDEMOXML + +/*------------------------------------------------------------------------ + * Include Files + */ + +#ifndef STDIO +#include +#endif + +#ifndef STDLIB +#include +#endif + +#ifndef STRING +#include +#endif + +#ifndef OCI_ORACLE +#include +#endif + +/*----------------- End of including files -----------------*/ + +/*--------------------- Public Constants and Variables ----------------------*/ + +/* constants */ +#define MAXDATELEN 64 +#define COLNUM 6 + +/* database login information */ +static OraText *user=(OraText *)"SCOTT"; +static OraText *password=(OraText *)"tiger"; + +/* OCI Handles and Variables */ +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCISvcCtx *svchp; +static OCIError *errhp; +static OCISession *authp; +static OCIBind *bndhp[COLNUM] = { (OCIBind *)0, (OCIBind *)0, (OCIBind *)0, + (OCIBind *)0, (OCIBind *)0, (OCIBind *)0 }; +static OCIDefine *defhp[COLNUM] = { (OCIDefine *)0, (OCIDefine *)0, (OCIDefine *)0, + (OCIDefine *)0, (OCIDefine *)0, (OCIDefine *)0 }; +static OCIStmt *stmthp = (OCIStmt *) 0; + +/* Misellaneous */ +static boolean ret = FALSE; +static boolean tab_exists = FALSE; +static boolean proc_exists = FALSE; +static ub2 sqlt[COLNUM] = {SQLT_TIMESTAMP, SQLT_TIMESTAMP_TZ, SQLT_TIMESTAMP_LTZ, + SQLT_INTERVAL_YM, SQLT_INTERVAL_DS, SQLT_INT}; +static ub4 ocit[COLNUM-1] = { OCI_DTYPE_TIMESTAMP, OCI_DTYPE_TIMESTAMP_TZ, + OCI_DTYPE_TIMESTAMP_LTZ, OCI_DTYPE_INTERVAL_YM, + OCI_DTYPE_INTERVAL_DS }; + +/*----------------- End of Constants and Variables -----------------*/ + +/*--------------------- Functions Declaration --------------------*/ + +int main(/*_ int argc, char *argv[] _*/); +static sb4 add_interval(/* OraText *dt, OraText *interval, OraText *fmt, ub4 type1, ub4 type2 _*/); +static sb4 alloc_desc(/*_ OCIDateTime *dvar[], OCIInterval *ivar[], sword size1, sword size2 _*/); +static void chk_err(/*_ OCIError *errhp, boolean ec, sb2 linenum, OraText *comment _*/); +static void cleanup(/*_ void _*/); +static sb4 connect_server(/*_ OraText *cstring _*/); +static sb4 conv_dt(/*_ OraText *str1, ub4 type1, ub4 type2, OraText *fmt1, + OraText *fmt2, OraText *name1, OraText *name2 _*/); +static void disconnect_server(/*_ void _*/); +static sb4 exe_insert(/*_ OraText *insstmt, OraText *strdate[COLNUM-1], + OraText *fmtdate[3], OCIDateTime *dvar[], OCIInterval *ivar[], size_t rownum_*/); +static sb4 exe_sql(/*_ OraText *stmt _*/); +static sb4 free_desc(/*_ OCIDateTime *dvar[], OCIInterval *ivar[], sword size1, sword size2 _*/); +static sb4 init_env_handle(/*_ void _*/); +static sb4 init_sql(/*_ void _*/); +static sb4 insert_dt(/*_ size_t rownum _*/); +static sb4 io_proc(/*_ _*/); +static sb4 select_dt(/*_ size_t rownum _*/); +static sb4 set_sdtz(); +static sb4 tzds_1(); +static sb4 tzds_2(); + +/*--------------------- End of Functions Declaration --------------------*/ + +#endif + + +/*---------------------------Main function -----------------------------*/ +int main(argc, argv) +int argc; +char *argv[]; +{ + OraText cstring[50]; + size_t rownum = 1; + + memset((void *)cstring, '\0', 50); + + if (argc > 1 && strncmp((char *) "remote", (char *)argv[1], 6) == 0) + { + strcpy((char *)cstring, "inst1_alias"); + } + + /* Initialize the environment and allocate handles */ + if (init_env_handle()) + { + printf("FAILED: init_env_handle()!\n"); + return OCI_ERROR; + } + + /* Log on to the server and begin a session */ + if (connect_server(cstring)) + { + printf("FAILED: connect_server()!\n"); + cleanup(); + return OCI_ERROR; + } + + /* Initialize the demo table and PL/SQL procedure */ + if (init_sql()) + { + printf("FAILED: init_sql()\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* Set the session datetime zone */ + if (set_sdtz()) + { + printf("FAILED: set_sdtz()\n"); + disconnect_server(); + return OCI_ERROR; + } + + rownum = 1; + /* Insertion via SQL statement */ + if (insert_dt(rownum)) + { + printf("FAILED: insert_dt()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* Selection via SQL statement */ + if (select_dt(rownum)) + { + printf("FAILED: select_dt()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* An example on IN/OUT BIND in PL/SQL procedure */ + if (io_proc()) + { + printf("FAILED: io_proc()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* An example on time zone name and daylight saving using OCIDateTimeConvert() */ + if (tzds_1()) + { + printf("FAILED: tzds_1()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* An example on time zone name and daylight saving using OCIDateTimeIntervalAdd() */ + if (tzds_2()) + { + printf("FAILED: tzds_2()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* Detach from a server and clean up the environment */ + disconnect_server(); + + return OCI_SUCCESS; +} + + +/*---------------------------Subfunctions -----------------------------*/ + +/*--------------------------------------------------------*/ +/* Add an interval to a datetime */ +/*--------------------------------------------------------*/ +sb4 add_interval(dt, interval, fmt, type1, type2) +OraText *dt, *interval, *fmt; +ub4 type1, type2; +{ + OCIDateTime *var1, *result; + OCIInterval *var2; + OraText *str, *fmt2; + ub4 buflen; + + /* Initialize the output string */ + str = (OraText *)malloc(MAXDATELEN); + memset ((void *) str, '\0', MAXDATELEN); + fmt2 = (OraText *)malloc(MAXDATELEN); + memset ((void *) fmt2, '\0', MAXDATELEN); + + /* Allocate descriptors */ + if (ret = OCIDescriptorAlloc((dvoid *)envhp,(dvoid **)&var1, type1, + 0, (dvoid **) 0) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDescriptorAlloc"); + return OCI_ERROR; + } + if (ret = OCIDescriptorAlloc((dvoid *)envhp,(dvoid **)&result, type1, + 0, (dvoid **) 0) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDescriptorAlloc"); + return OCI_ERROR; + } + if (ret = OCIDescriptorAlloc((dvoid *)envhp,(dvoid **)&var2, type2, + 0,(dvoid **)0) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDescriptorAlloc"); + return OCI_ERROR; + } + + /* Change to datetime type format */ + if (ret = OCIDateTimeFromText((dvoid *)authp,errhp,(CONST OraText *)dt, + (ub4) strlen((char *)dt), (CONST OraText *)fmt, + (ub1) strlen((char *)fmt),(CONST OraText *)0,0, var1) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDateTimeFromText"); + return OCI_ERROR; + } + /* Change to interval type format */ + if ((ret = OCIIntervalFromText((dvoid *)authp, errhp,(CONST OraText *)interval, + (ub4) strlen((char *)interval), + (OCIInterval *)var2)) != OCI_SUCCESS) { + chk_err(errhp, ret, __LINE__,(OraText *)"OCIIntervalFromText"); + return OCI_ERROR; + } + + /* Add the interval to datetime */ + if (ret = OCIDateTimeIntervalAdd(envhp, errhp, var1, var2, result) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDateTimeIntervalAdd"); + return OCI_ERROR; + } + + buflen = MAXDATELEN; + + /* Change the result to text format */ + strcpy((char *)fmt2,"DD-MON-RR HH.MI.SSXFF AM TZR TZD"); + if (ret = OCIDateTimeToText((dvoid *)authp,errhp,(CONST OCIDateTime *)result, + (CONST OraText *)fmt2,(ub1)strlen((char *)fmt2),(ub1) 2, + (CONST OraText *) NULL, + (ub4)0, (ub4 *) &buflen, (OraText *) str) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDateTimeToText"); + return OCI_ERROR; + } + + printf("( %s ) + ( %s ) --->\n\t%s\n\n", dt, interval, str); + + /* Free the descriptors */ + if (var1) { + OCIDescriptorFree((dvoid *) var1, (ub4) type1); + } + if (result) { + OCIDescriptorFree((dvoid *) result, (ub4) type1); + } + if (var2) { + OCIDescriptorFree((dvoid *) var2, (ub4) type2); + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* Allocate descriptors */ +/*--------------------------------------------------------*/ +sb4 alloc_desc(dvar, ivar, size1, size2) +OCIDateTime *dvar[]; +OCIInterval *ivar[]; +sword size1, size2; +{ + sword i; + + /* allocate datetime and interval descriptors */ + for (i=0; i %s:\n", name1, name2); + printf("\t%s ---> %s\n\n", str1, str2); + + /* Free the descriptors */ + if (var1) { + OCIDescriptorFree((dvoid *) var1, (ub4) type1); + } + if (var2) { + OCIDescriptorFree((dvoid *) var2, (ub4) type2); + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* End the session, detach server and free environmental handles. */ +/*--------------------------------------------------------*/ +void disconnect_server() +{ + printf("\n\nLogged off and detached from server.\n"); + + /* Drop the demo table and procedure if any */ + if (tab_exists) + exe_sql((OraText *)"drop table cdemodt_foo"); + if (proc_exists) + exe_sql((OraText *)"drop procedure cdemodt_ins_sel"); + + /* End a session */ + if (ret = OCISessionEnd((OCISvcCtx *)svchp, (OCIError *)errhp, + (OCISession *)authp, (ub4) OCI_DEFAULT)) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCISessionEnd"); + cleanup(); + return; + } + + /* Detach from the server */ + if (ret = OCIServerDetach((OCIServer *)srvhp, (OCIError *)errhp, + (ub4)OCI_DEFAULT)) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIServerDetach"); + cleanup(); + return; + } + + /* Free the handles */ + if (stmthp) { + OCIHandleFree((dvoid *)stmthp, (ub4) OCI_HTYPE_STMT); + } + if (authp) { + OCIHandleFree((dvoid *)authp, (ub4) OCI_HTYPE_SESSION); + } + if (svchp) { + OCIHandleFree((dvoid *)svchp, (ub4) OCI_HTYPE_SVCCTX); + } + if (srvhp) { + OCIHandleFree((dvoid *)srvhp, (ub4) OCI_HTYPE_SERVER); + } + if (errhp) { + OCIHandleFree((dvoid *)errhp, (ub4) OCI_HTYPE_ERROR); + } + if (envhp) { + OCIHandleFree((dvoid *)envhp, (ub4) OCI_HTYPE_ENV); + } + + return; +} + + +/*--------------------------------------------------------*/ +/* Execute the insertion */ +/*--------------------------------------------------------*/ +sb4 exe_insert(insstmt, strdate, fmtdate, dvar, ivar, rownum) +OraText *insstmt, *strdate[COLNUM-1], *fmtdate[3]; +OCIDateTime *dvar[3]; +OCIInterval *ivar[2]; +size_t rownum; +{ + sword i; + size_t colc = rownum; + + /* Converts the text strings to the datetime types in the table */ + for (i=0; i<3; i++) { + if (ret = OCIDateTimeFromText(authp,errhp,(CONST OraText *)strdate[i], + (ub4) strlen((char *)strdate[i]),(CONST OraText *) fmtdate[i], + (ub1) strlen((char *)fmtdate[i]),(OraText *) NULL,(ub4) 0,dvar[i])) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDateFromText"); + return OCI_ERROR; + } + } + + /* Converts the text strings to the interval types in the table */ + for (i=0; i<2; i++) { + if ((ret = OCIIntervalFromText((dvoid *)authp, errhp,(CONST OraText *) + strdate[i+3], (ub4) strlen((char *)strdate[i+3]), + (OCIInterval *)ivar[i])) != OCI_SUCCESS) { + chk_err(errhp, ret, __LINE__,(OraText *)"OCIIntervalFromText"); + return OCI_ERROR; + } + } + + /* Preparation of statment handle for the SQL statement */ + if ((ret = OCIStmtPrepare(stmthp, errhp, insstmt, (ub4)strlen((char *)insstmt), OCI_NTV_SYNTAX, + OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtPrepare"); + return OCI_ERROR; + } + + /* Binds the input variable */ + for (i=0; i<3; i++) { + if ((ret = OCIBindByPos(stmthp,&bndhp[i],errhp,i+1,(dvoid *)&dvar[i], + (sb4) sizeof(OCIDateTime *), sqlt[i], (dvoid *)0, + (ub2 *) 0,(ub2 *) 0,(ub4) 0,(ub4 *)0,OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIBindByPos"); + return OCI_ERROR; + } + } + for (i=0; i<2; i++) { + if ((ret = OCIBindByPos(stmthp,&bndhp[i+3],errhp,i+4,(dvoid *)&ivar[i], + (sb4) sizeof(OCIInterval *), sqlt[i+3], (dvoid *)0, + (ub2 *) 0,(ub2 *) 0,(ub4) 0,(ub4 *)0,OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIBindByPos"); + return OCI_ERROR; + } + } + if ((ret = OCIBindByPos(stmthp,&bndhp[5],errhp,6,(dvoid *)&colc, + (sb4) sizeof(colc), sqlt[5], (dvoid *)0, + (ub2 *) 0,(ub2 *) 0,(ub4) 0,(ub4 *)0,OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIBindByPos"); + return OCI_ERROR; + } + + /* Executing the SQL statement */ + if ((ret = OCIStmtExecute(svchp, stmthp, errhp, 1, 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtExecute"); + return OCI_ERROR; + } + + printf("Values inserted\n\n"); + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* Execute a sql statement */ +/*--------------------------------------------------------*/ +sb4 exe_sql(stmt) +OraText *stmt; +{ + /* prepare statement */ + if (ret = OCIStmtPrepare(stmthp, errhp, stmt, (ub4) strlen((char *) stmt), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtPrepare"); + return OCI_ERROR; + } + /* execute statement */ + if (ret = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtExecute"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* Free the descriptors */ +/*--------------------------------------------------------*/ +sb4 free_desc(dvar, ivar, size1, size2) +OCIDateTime *dvar[]; +OCIInterval *ivar[]; +sword size1, size2; +{ + sword i; + + /* Free the descriptors */ + for (i=0; iInsertion via SQL statement\n\n"); + /* execute the insertion */ + if (exe_insert(insstmt, strdate, fmtdate, dvar, ivar, rownum)) { + printf("FAILED: exe_insert()!\n"); + return OCI_ERROR; + } + + /* Free the descriptors */ + if (free_desc(dvar, ivar, 3, 2)) { + printf("FAILED: free_desc()!\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* Insert/Select via In/Out Bind */ +/*--------------------------------------------------------*/ +sb4 io_proc() +{ + sword i; + size_t rownum = 1; + OCIDateTime *dvar[3]; + OCIInterval *ivar[2]; + ub4 str_size[COLNUM-1]; + size_t resultlen; + OraText *strdate[COLNUM-1]; + OraText *fmtdate[3]; + OraText *sqlstmt = (OraText *)"BEGIN CDEMODT_INS_SEL(:1, :2, :3, :4, :5, :6); END; "; + + /* Initialize strings */ + for (i=0; iInsertion and Selection via PL/SQL procedure\n\n"); + + strcpy((char *)strdate[0],"1999-12-01 01:30:10"); + strcpy((char *)strdate[1],"1999-12-01 01:30:10 US/Pacific PST"); + strcpy((char *)strdate[2],"1999-12-01 01:30:10"); + strcpy((char *)strdate[3],"02-03"); + strcpy((char *)strdate[4],"2 03:03:03.09"); + strcpy((char *)fmtdate[0],"YYYY-MM-DD HH24:MI:SS"); + strcpy((char *)fmtdate[1],"YYYY-MM-DD HH24:MI:SS TZR TZD"); + strcpy((char *)fmtdate[2],"YYYY-MM-DD HH24:MI:SS"); + + /* allocate datetime and interval descriptors */ + if (alloc_desc(dvar, ivar, 3, 2)) { + printf("FAILED: alloc_desc()!\n"); + return OCI_ERROR; + } + + /* execute the statement */ + if (exe_insert(sqlstmt, strdate, fmtdate, dvar, ivar, rownum)) { + printf("FAILED: exe_insert()!\n"); + return OCI_ERROR; + } + + /* Convert to text format */ + printf("Values selected:\n"); + for (i=0; i<3; i++) { + str_size[i] = MAXDATELEN; + if ((ret = OCIDateTimeToText(authp, errhp, dvar[i], (OraText*)fmtdate[i], + (ub1) strlen((char *)fmtdate[i]), (ub1) 2, (OraText*)0, 0, + &str_size[i], (OraText*)strdate[i])) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDateTimeToText"); + return OCI_ERROR; + } + printf("Column %d: %s\n", i+1, strdate[i]); + } + for (i=0; i<2; i++) { + str_size[i+3] = MAXDATELEN; + if ((ret = OCIIntervalToText(envhp, errhp, ivar[i], (ub1) 3, (ub1)2, + strdate[i+3],str_size[i+3],(size_t *)&resultlen)) != 0) { + chk_err(errhp, ret, __LINE__,(OraText *)"Error in OCIIntervalToText"); + return OCI_ERROR; + } + printf("Column %d: %s\n", i+4, strdate[i+3]); + } + printf("Column 6: %d\n\n", rownum); + + /* Free the descriptors */ + if (free_desc(dvar, ivar, 3, 2)) { + printf("FAILED: free_desc()!\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* Select datetime/interval values from the table */ +/*--------------------------------------------------------*/ +sb4 select_dt(rownum) +size_t rownum; +{ + sword i, var6; + size_t colc = rownum; + OraText *strdate[COLNUM-1]; + OraText *fmtdate[3]; + ub4 str_size[COLNUM-1]; + size_t resultlen; + OCIDateTime *dvar[3]; + OCIInterval *ivar[2]; + OraText *selstmt = (OraText *) "SELECT * FROM CDEMODT_FOO WHERE int = :1"; + + /* Initialize strings */ + for (i=0; iSelection via SQL statement\n\n"); + /* Preparation of statment handle for the SQL statement */ + if ((ret = OCIStmtPrepare(stmthp, errhp, selstmt, (ub4)strlen((char *)selstmt), OCI_NTV_SYNTAX, + OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtPrepare"); + return OCI_ERROR; + } + + /* associate variable colc with bind placeholder in the SQL statement */ + if ((ret = OCIBindByPos(stmthp, &bndhp[0], errhp, 1, &colc, sizeof(colc), + SQLT_INT,(void *)0, (ub2 *)0,(ub2 *)0, 0, (ub4 *)0, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIBindByPos"); + return OCI_ERROR; + } + + /* Defining the positions for the variables */ + for (i=0; i<3; i++) { + if ((ret = OCIDefineByPos(stmthp, &defhp[i], errhp, i+1, &dvar[i], sizeof(dvar[i]), + sqlt[i], (void *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDefineByPos"); + return OCI_ERROR; + } + } + for (i=0; i<2; i++) { + if ((ret = OCIDefineByPos(stmthp, &defhp[i+3], errhp, i+4, &ivar[i], sizeof(ivar[i]), + sqlt[i+3], (void *)0,(ub2 *)0, (ub2 *)0, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDefineByPos"); + return OCI_ERROR; + } + } + if ((ret = OCIDefineByPos(stmthp, &defhp[5], errhp, 6, &var6, sizeof(var6), + sqlt[5], (void *)0, (ub2 *)0,(ub2 *)0, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDefineByPos"); + return OCI_ERROR; + } + + /* Executing the SQL statement */ + if ((ret = OCIStmtExecute(svchp, stmthp, errhp, 1, 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtExecute"); + return OCI_ERROR; + } + + /* Convert to text format */ + printf("Values selected:\n"); + for (i=0; i<3; i++) { + str_size[i] = MAXDATELEN; + if ((ret = OCIDateTimeToText(authp, errhp, dvar[i], (OraText*)fmtdate[i], + (ub1) strlen((char *)fmtdate[i]), (ub1) 2, (OraText*)0,(size_t)0, + &str_size[i], (OraText*)strdate[i])) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDateTimeToText"); + return OCI_ERROR; + } + printf("Column %d: %s\n", i+1, strdate[i]); + } + for (i=0; i<2; i++) { + str_size[i+3] = MAXDATELEN; + if ((ret = OCIIntervalToText(envhp, errhp, ivar[i], (ub1) 3, (ub1)2, + strdate[i+3],str_size[i+3],(size_t *)&resultlen)) != 0) { + chk_err(errhp, ret, __LINE__, (OraText *)"Error in OCIIntervalToText"); + return OCI_ERROR; + } + printf("Column %d: %s\n", i+4, strdate[i+3]); + } + printf("Column 6: %d\n\n", var6); + + /* Free the descriptors */ + if (free_desc(dvar, ivar, 3, 2)) { + printf("FAILED: free_desc()!\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* Set session datetime zone */ +/*--------------------------------------------------------*/ +sb4 set_sdtz() +{ + OraText *altstmt=(OraText *)"ALTER SESSION SET TIME_ZONE='US/Central'"; + OraText *selstmt=(OraText *)"SELECT SESSIONTIMEZONE FROM DUAL"; + OraText *str; + + /* Initialize strings */ + str = (OraText *)malloc(MAXDATELEN); + memset ((void *) str, '\0', MAXDATELEN); + + /* Alter session time zone */ + if (exe_sql(altstmt)) { + printf("FAILED: exe_sql()!\n"); + return OCI_ERROR; + } + + /* Preparation of statment handle for the select SQL statement */ + if ((ret = OCIStmtPrepare(stmthp, errhp, selstmt, (ub4) strlen((char *)selstmt), + OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtPrepare"); + return OCI_ERROR; + } + + /* Defining the position for the variable */ + if ((ret = OCIDefineByPos(stmthp, &defhp[0], errhp, 1, str, MAXDATELEN, + SQLT_STR, (void *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDefineByPos"); + return OCI_ERROR; + } + + /* Executing the SQL statement */ + if ((ret = OCIStmtExecute(svchp, stmthp, errhp, 1, 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtExecute"); + return OCI_ERROR; + } + + printf("The session time zone is set to %s\n\n", str); + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* An example on time zone name and daylight saving using OCIDateTimeConvert */ +/*--------------------------------------------------------*/ +sb4 tzds_1() +{ + ub4 type1, type2; + OraText *str1, *fmt1, *fmt2, *name1, *name2; + + /* Initialize strings */ + str1 = (OraText *)malloc(MAXDATELEN); + memset ((void *) str1, '\0', MAXDATELEN); + fmt1 = (OraText *)malloc(MAXDATELEN); + memset ((void *) fmt1, '\0', MAXDATELEN); + fmt2 = (OraText *)malloc(MAXDATELEN); + memset ((void *) fmt2, '\0', MAXDATELEN); + name1 = (OraText *)malloc(MAXDATELEN); + memset ((void *) name1, '\0', MAXDATELEN); + name2 = (OraText *)malloc(MAXDATELEN); + memset ((void *) name2, '\0', MAXDATELEN); + + printf("-->Conversion of datetime types\n\n"); + /* Convert from timestamp with time zone region to timestamp with time zone offset */ + /* The same time zone name will return different time zone offsets for standard time and daylight saving time */ + /* daylight saving time, expected time zone offset is -07:00 */ + type1 = OCI_DTYPE_TIMESTAMP_TZ; + type2 = OCI_DTYPE_TIMESTAMP_TZ; + strcpy((char *)str1,"1999-10-01 01:30:10 US/Pacific"); + strcpy((char *)fmt1,"YYYY-MM-DD HH:MI:SS TZR"); + strcpy((char *)fmt2,"YYYY-MM-DD HH:MI:SS TZH:TZM"); + strcpy((char *)name1, "TIMESTAMP WITH TIME ZONE REGION"); + strcpy((char *)name2, "TIMESTAMP WITH TIME ZONE OFFSET"); + if (conv_dt(str1, type1, type2, fmt1, fmt2, name1, name2)) { + printf("FAILED: conv_dt()!\n"); + return OCI_ERROR; + } + + /* standard time, expected time zone offset is -08:00 */ + strcpy((char *)str1,"1999-11-01 01:30:10 US/Pacific"); + if (conv_dt(str1, type1, type2, fmt1, fmt2, name1, name2)) { + printf("FAILED: conv_dt()!\n"); + return OCI_ERROR; + } + + /* Convert from timestamp with time zone region to timestamp with local time zone, + the session time zone was set to US/Central at the begining of the program */ + /* daylight saving time */ + type1 = OCI_DTYPE_TIMESTAMP_TZ; + type2 = OCI_DTYPE_TIMESTAMP_LTZ; + strcpy((char *)str1,"1999-10-31 01:30:10 US/Pacific PDT"); + strcpy((char *)fmt1,"YYYY-MM-DD HH24:MI:SS TZR TZD"); + strcpy((char *)fmt2,"YYYY-MM-DD HH24:MI:SS"); + strcpy((char *)name1, "TIMESTAMP WITH TIME ZONE REGION"); + strcpy((char *)name2, "TIMESTAMP WITH LOCAL TIME ZONE"); + if (conv_dt(str1, type1, type2, fmt1, fmt2, name1, name2)) { + printf("FAILED: conv_dt()!\n"); + return OCI_ERROR; + } + + /* standard time */ + strcpy((char *)str1,"1999-10-31 01:30:10 US/Pacific PST"); + if (conv_dt(str1, type1, type2, fmt1, fmt2, name1, name2)) { + printf("FAILED: conv_dt()!\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* An example on time zone name and daylight saving using OCIDateTimeIntervalAdd */ +/*--------------------------------------------------------*/ +sb4 tzds_2() +{ + ub4 type1, type2; + OraText *dt, *interval, *fmt; + + /* Initialize strings */ + dt = (OraText *)malloc(MAXDATELEN); + memset ((void *) dt, '\0', MAXDATELEN); + interval = (OraText *)malloc(MAXDATELEN); + memset ((void *) interval, '\0', MAXDATELEN); + fmt = (OraText *)malloc(MAXDATELEN); + memset ((void *) fmt, '\0', MAXDATELEN); + + printf("-->Addition of timestamp with time zone and interval day to seconds\n\n"); + /* The following two cases show that daylight saving is automatically + reflected with a time zone name */ + type1 = OCI_DTYPE_TIMESTAMP_TZ; + type2 = OCI_DTYPE_INTERVAL_DS; + strcpy((char *)interval,"0 08:00:00.00"); + strcpy((char *)fmt,"YYYY-MM-DD HH24:MI:SS TZR"); + + /* Standard time + an interval = daylight saving time */ + strcpy((char *)dt,"2000-4-1 23:24:54 AMERICA/LOS_ANGELES"); + if (add_interval(dt, interval, fmt, type1, type2)) { + printf("FAILED: add_interval()!\n"); + return OCI_ERROR; + } + + /* Daylight saving time + an interval = standard time */ + strcpy((char *)dt,"2000-10-28 22:00:00 AMERICA/LOS_ANGELES"); + if (add_interval(dt, interval, fmt, type1, type2)) { + printf("FAILED: add_interval()!\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* end of file cdemodt.c */ diff --git a/cdemoext.c b/cdemoext.c new file mode 100644 index 0000000..1dff2f4 --- /dev/null +++ b/cdemoext.c @@ -0,0 +1,310 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoext.c 14-jul-99.13:10:58 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 1999,, 2000 Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemoext.c - C Demo for ociEXTract + + DESCRIPTION + This file demonstrates an example of using the OCIExtract package + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + tsaulys 01/05/00 - #(1078628) do not use strlist + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + nramakri 01/16/98 - add demos for OCINUM and List support + nramakri 12/17/97 - Creation + +*/ + +#include +#include +#include +#include + +#define NUMKEYS 9 /* Number of parameter keys */ + +/* Default values and ranges for various parameter keys */ +static const sb4 dflt_intval = 1234; +static const ub1 dflt_boolval = TRUE; + +static const sb4 intrange[] = {1234, 5678}; +static const text *strlst[] = {(const text *)"abcd", + (const text *)"efghi", + (const text *)"ijlkmn", + (const text *)"mnopqrs", + (const text *)"tuvwxyz", + (const text *)0 + }; + +/* strings containing parameters to be parsed */ +static text *par_str[] = {(text *)"param2=hello param3=30", + (text *)"Param4=hi Param5=5555 Param6=tuvwxyz", + (text *)"param1=45 param7=f param9=3.1415" + }; + +/* file containing parameters to be parsed */ +static text *par_file = (text *)"cdemoext.dat"; + +/* behavior flags to use while parsing parameter string */ +static const ub4 par_str_flags[] = {0, + OCI_EXTRACT_CASE_SENSITIVE, + OCI_EXTRACT_APPEND_VALUES + }; + +/* behavior flags to use while parsing parameter file */ +static const ub4 par_file_flags = OCI_EXTRACT_APPEND_VALUES; + +static sword checkerr(/*_ OCIError *errhp, sword status _*/); +int main(/*_ void _*/); + +int main() +{ + OCIEnv *envhp; + OCIError *errhp; + sword status; + sb4 outi; + ub1 outb; + text outs[100]; + OCINumber outn; + uword scount; + uword numkeys; + text *keyname; + ub1 keytype; + uword keynumvals; + dvoid **keyvalues; + double dnum; + + /* Set up OCI */ + (void) OCIInitialize((ub4)OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t))0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *))0 ); + + (void) OCIEnvInit((OCIEnv **)&envhp, OCI_DEFAULT, (size_t)0, (dvoid **)0); + + (void) OCIHandleAlloc((dvoid *)envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, + (size_t)0, (dvoid **)0); + + /* Initialize OCI extraction package */ + if (checkerr(errhp, OCIExtractInit(envhp, errhp)) != OCI_SUCCESS) + goto exit0; + + /* Set definitions for parameters to be extracted */ + if (checkerr(errhp, OCIExtractSetNumKeys(envhp, errhp, NUMKEYS+1)) + != OCI_SUCCESS) + goto exit0; + + /* Reset parameter space, cancels previous setting */ + (void) checkerr(errhp, OCIExtractReset(envhp, errhp)); + + if (checkerr(errhp, OCIExtractSetNumKeys(envhp, errhp, NUMKEYS)) + != OCI_SUCCESS) + goto exit0; + + /* 1: integer parameter, with no default value */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param1", + (ub1)OCI_EXTRACT_TYPE_INTEGER, + (ub4)OCI_EXTRACT_MULTIPLE, + (dvoid *)0, + (sb4 *)0, + (CONST text *CONST *)0)); + + /* 2: string parameter, with no default value */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param2", + (ub1)OCI_EXTRACT_TYPE_STRING, + (ub4)0, + (dvoid *)0, + (sb4 *)0, + (CONST text *CONST *)0)); + + /* 3: integer parameter, with a default value */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param3", + (ub1)OCI_EXTRACT_TYPE_INTEGER, + (ub4)0, + (dvoid *)&dflt_intval, + (sb4 *)0, + (CONST text *CONST *)0)); + + /* 4: string parameter, with a default value */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param4", + (ub1)OCI_EXTRACT_TYPE_STRING, + (ub4)0, + (dvoid *)"abcd", + (sb4 *)0, + (CONST text *CONST *)0)); + + /* 5: integer parameter, with no default value, and allowable range */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param5", + (ub1)OCI_EXTRACT_TYPE_INTEGER, + (ub4)0, + (dvoid *)0, + (sb4 *)intrange, + (CONST text *CONST *)0)); + + /* 6: string parameter, with a default value, and allowable list */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param6", + (ub1)OCI_EXTRACT_TYPE_STRING, + (ub4)0, + (dvoid *)"efghi", + (sb4 *)0, + (CONST text *CONST *)strlst)); + + /* 7: boolean parameter, with no default value */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param7", + (ub1)OCI_EXTRACT_TYPE_BOOLEAN, + (ub4)OCI_EXTRACT_MULTIPLE, + (dvoid *)0, + (sb4 *)0, + (CONST text *CONST *)0)); + + /* 8: boolean parameter, with a default value */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param8", + (ub1)OCI_EXTRACT_TYPE_BOOLEAN, + (ub4)0, + (dvoid *)&dflt_boolval, + (sb4 *)0, + (CONST text *CONST *)0)); + + /* 9: ocinum parameter with no default value */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param9", + OCI_EXTRACT_TYPE_OCINUM, + OCI_EXTRACT_MULTIPLE, + (CONST dvoid *)0, + (CONST sb4 *)0, + (CONST text *CONST *)0)); + + /* Extract parameters from a file */ + (void) checkerr(errhp, OCIExtractFromFile(envhp, errhp, + par_file_flags, par_file)); + + /* Extract parameters from strings */ + for (scount = 0; scount < 3; scount++) + (void) checkerr(errhp, OCIExtractFromStr(envhp, errhp, + par_str_flags[scount], + par_str[scount])); + + /* Output some parameters */ + if (checkerr(errhp, OCIExtractToInt(envhp, errhp, (text *)"Param1", + 0, &outi)) == OCI_SUCCESS) + printf("Param1 is %d\n", outi); + + if (checkerr(errhp, OCIExtractToStr(envhp, errhp, (text *)"Param6", + 0, outs, 100)) == OCI_SUCCESS) + printf("Param6 is %s\n", outs); + + if (checkerr(errhp, OCIExtractToBool(envhp, errhp, (text *)"Param8", + 0, &outb)) == OCI_SUCCESS) + printf("Param8 is %s\n", (outb == TRUE)?"true":"false"); + + if (checkerr(errhp, OCIExtractToList(envhp, errhp, &numkeys)) + == OCI_SUCCESS) + { + /* Extract some key */ + (void) checkerr(errhp, OCIExtractFromList(envhp, errhp, 1, + &keyname, &keytype, + &keynumvals, &keyvalues)); + + /* Print details about the extracted key */ + printf("The key extracted was \'%s\'\n", keyname); + printf("%s contains %d ", keyname, keynumvals); + switch(keytype) + { + case OCI_EXTRACT_TYPE_INTEGER: + printf("integer values which are:\n"); + for (scount=0; scount < keynumvals; scount++) + printf("%d\n", *(sb4 *)keyvalues[scount]); + break; + case OCI_EXTRACT_TYPE_BOOLEAN: + printf("boolean values which are:\n"); + for (scount=0; scount < keynumvals; scount++) + printf("%s\n", (*(ub1 *)keyvalues[scount]==TRUE)?"true":"false"); + break; + case OCI_EXTRACT_TYPE_STRING: + printf("string values which are:\n"); + for (scount=0; scount < keynumvals; scount++) + printf("%s\n", (text *)keyvalues[scount]); + break; + case OCI_EXTRACT_TYPE_OCINUM: + printf("OCINumber values which are:\n"); + for (scount=0; scount < keynumvals; scount++) + { + (void) checkerr(errhp, + OCINumberToReal(errhp, + (CONST OCINumber *)keyvalues[scount], + (uword)sizeof(dnum), (dvoid *)&dnum)); + (void) printf("%11.4f\n", dnum); + } + break; + default: + printf("unknown values\n"); + break; + } + } + + /* Terminate OCI extraction package */ + (void) checkerr(errhp, OCIExtractTerm(envhp, errhp)); + + exit0: + if (errhp) + (void) OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR); + + return 0; +} + +static sword checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + default: + break; + } + return status; +} + +/* end of file cdemoext.c */ + diff --git a/cdemoext.dat b/cdemoext.dat new file mode 100644 index 0000000..ecb57a3 --- /dev/null +++ b/cdemoext.dat @@ -0,0 +1,11 @@ +# +# parameter file +# +param1=25 +param2=world +param3=145 +param4=hi +param5=5555 +param6=efghi +param7=true +param9=-63378.4542 .2096 diff --git a/cdemofil.c b/cdemofil.c new file mode 100644 index 0000000..95ec3a0 --- /dev/null +++ b/cdemofil.c @@ -0,0 +1,242 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemofil.c 27-jul-2004.08:40:29 jchai Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 2004, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemofil.c - C Demo for ociFILe + + DESCRIPTION + This file demonstrates an example of using the OCIFile package + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + jchai 07/27/04 - + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + nramakri 12/17/97 - Creation + +*/ + +#include +#include +#include + +#ifndef OCI_ORACLE +#include +#endif + +static sword checkerr(/*_ OCIError *errhp, sword status _*/); +int main(/*_ int argc, char *argv[] _*/); + +int main(argc, argv) +int argc; +char *argv[]; +{ + OCIEnv *envhp; + OCIError *errhp; + + OCIFileObject *of1o, *of2o; + OraText *f1name, *f1path, *f2name, *f2path; + OraText buf1[500], buf2[50], buf3[500], buf4[500]; + ub4 bytes1, bytes2, i; + ubig_ora f1len, f2len; + ub1 flag; /* boolean */ + + f1name = (OraText *)"test_file1.dat"; + f1path = (OraText *)NULL; + + f2name = (OraText *)"test_file2.dat"; + f2path = (OraText *)NULL; + + + (void) OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 ); + + (void) OCIEnvInit( (OCIEnv **) &envhp, OCI_DEFAULT, (size_t) 0, + (dvoid **) 0 ); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + /* Initialize OCIFile */ + if (checkerr(errhp, OCIFileInit(envhp, errhp)) != OCI_SUCCESS) + goto exit0; + else + printf("OCIFile initialized successfully\n"); + + + /* Create the file and open it for read & write: file1 */ + if (checkerr(errhp, OCIFileOpen(envhp, errhp, &of1o, f1name, f1path, + OCI_FILE_READ_WRITE, OCI_FILE_CREATE, + OCI_FILE_TEXT)) != OCI_SUCCESS) + goto exit0; + else + printf("File %s opened successfully\n", f1name); + + /* fill buf4 with data to be written */ + for (i=0; i<500; i++) + buf4[i] = 'a'+i%26; + + /* write buf2 */ + if (checkerr(errhp, OCIFileWrite(envhp, errhp, of1o, (void *)buf4, + 500, &bytes1)) + == OCI_SUCCESS) + { + printf("No of bytes written to file %s is %d\n", f1name, bytes1); + } + + /* flush the buffers */ + checkerr(errhp, OCIFileFlush(envhp, errhp, of1o)); + + /* Print out the length of file1 */ + if (checkerr(errhp, OCIFileGetLength(envhp, errhp, f1name, f1path, &f1len)) + == OCI_SUCCESS) + { + printf("The length of the file %s is %d\n",f1name, f1len); + } + + /* Seek to the beginning of the file */ + if (checkerr(errhp, OCIFileSeek(envhp, errhp, of1o, OCI_FILE_SEEK_BEGINNING, + 0, OCI_FILE_FORWARD)) != OCI_SUCCESS) + goto exit0; + + /* Read upto 400 bytes from test_file1.txt */ + if (checkerr(errhp, OCIFileRead(envhp, errhp, of1o, (void *)buf1, + 400, &bytes1)) == OCI_SUCCESS) + { + printf("No of bytes read from file %s is %d\n", f1name, bytes1); + } + + flag = FALSE; + + /* Check whether file2 exists */ + checkerr(errhp, OCIFileExists(envhp, errhp, f2name, f2path, &flag)); + + if (flag == FALSE) + { + /* File doesn't exist, Open for write in exclusive mode */ + /* skip printf, causes dif in tkpgoci2.tsc */ + /* printf("File %s does not exist\n", f2name); */ + if (checkerr(errhp, OCIFileOpen(envhp, errhp, &of2o, f2name, f2path, + OCI_FILE_READ_WRITE, OCI_FILE_EXCL, + OCI_FILE_TEXT)) != OCI_SUCCESS) + goto exit0; + else + printf("File %s opened successfully\n", f2name); + } + else /* File exists, open in truncate mode */ + { + /* skip printf, causes dif in tkpgoci2.tsc */ + /*printf("File %s exists \n", f2name); */ + if (checkerr(errhp, OCIFileOpen(envhp, errhp, &of2o, f2name, f2path, + OCI_FILE_READ_WRITE, OCI_FILE_TRUNCATE, + OCI_FILE_TEXT)) != OCI_SUCCESS) + goto exit0; + else + printf("File %s opened successfully\n", f2name); + } + + /* write from buf1 */ + if (checkerr(errhp, OCIFileWrite(envhp, errhp, of2o, buf1, bytes1, &bytes2)) + == OCI_SUCCESS) + { + printf("No of bytes written to file %s is %d\n", f2name, bytes2); + } + + /* Seek to the end of the file */ + if (checkerr(errhp, OCIFileSeek(envhp, errhp, of2o, OCI_FILE_SEEK_END, 0, + OCI_FILE_FORWARD)) != OCI_SUCCESS) + goto exit0; + + strcpy((char *)buf2, "This is the end of this file!"); + + /* write buf2 */ + if (checkerr(errhp, OCIFileWrite(envhp, errhp, of2o, (void *)buf2, + strlen((CONST char *)buf2), &bytes2)) + == OCI_SUCCESS) + printf("No of bytes written to file %s is %d\n", f2name, bytes2); + + /* flush the buffers */ + checkerr(errhp, OCIFileFlush(envhp, errhp, of2o)); + + /* Print out the length of the file */ + if (checkerr(errhp, OCIFileGetLength(envhp, errhp, f2name, f2path, &f2len)) + == OCI_SUCCESS) + printf("The length of file %s is %d\n", f2name, f2len); + + /* Seek to the beginning of file2 */ + if (checkerr(errhp, OCIFileSeek(envhp, errhp, of2o, OCI_FILE_SEEK_BEGINNING, + 0, OCI_FILE_FORWARD)) != OCI_SUCCESS) + goto exit0; + + /* Read all the data from test_file2.txt */ + if (checkerr(errhp, OCIFileRead(envhp, errhp, of2o, (void *)buf3, + f2len, &bytes1)) == OCI_SUCCESS) + printf("No of bytes read from file %s is %d\n", f2name, bytes1); + + /* append buf2 contents to buf1 */ + memcpy(buf1+400, buf2, bytes2); + + /* compare buf1 & buf3 */ + if (memcmp(buf1, buf3, bytes1) == 0) + printf("Reads & Writes are successful\n"); + else + printf("Error in data read/written\n"); + + /* close the files and terminate OCIFile */ + checkerr(errhp, OCIFileClose(envhp, errhp, of2o)); + checkerr(errhp, OCIFileClose(envhp, errhp, of1o)); + checkerr(errhp, OCIFileTerm(envhp, errhp)); + + exit0: + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + + return 0; +} + +sword checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + OraText errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (OraText *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + default: + break; + } + return status; +} + +/* end of file cdemofil.c */ + diff --git a/cdemofo.c b/cdemofo.c new file mode 100644 index 0000000..dfc326b --- /dev/null +++ b/cdemofo.c @@ -0,0 +1,398 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemofo.c 16-jul-2003.09:08:43 srseshad Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 2003, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemofo.c - C demo program for OCI callbacks for application failover + + DESCRIPTION + This is an example program to demonstrate the registration + and operation of OCI application failover callbacks. + + PUBLIC FUNCTION(S) + main - main entry point + + PRIVATE FUNCTION(S) + checkerr - check errors + cleanup - cleanup resources + register_callback - register failover callback + callback_fn - callback function + + + RETURNS + EX_SUCESS on success + EX_FAILURE on failure + + NOTES + This is just a demo program for the failover callbacks. A complete + failover example would require someway of simulating the failure of the + connection and switching to a new instance + + + MODIFIED (MM/DD/YY) + srseshad 07/16/03 - remove direct ref to ocikp.h and ociap.h + porangas 10/08/02 - Fix for bug#2540468 + slari 05/15/02 - Change to fix core dumep during cleanup at demo exit.. + emendez 09/13/00 - fix top 5 olint errors + mrhodes 01/25/00 - make sleep call nt compatible + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + slari 10/14/98 - remove OCI_FO_TXNAL + slari 10/13/98 - demo program for oci application failover callbacks + slari 10/13/98 - Creation + +*/ + + +/* for WINDOWS compatibility of 'sleep' call */ +#if defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32) +#include +#define sleep(x) Sleep(1000*(x)) +#endif + + +#include +#include +#include +#include + +#define EX_SUCCESS 0 +#define EX_FAILURE -1 +#define FAILOVER_S "Application Failover Context" + +static text *username = (text *) "SCOTT"; +static text *password = (text *) "TIGER"; +static text *dbname = (text *) "inst1"; + + /* Define SQL statements to be used in program. */ +static text *sel1 = (text *) "SELECT empno FROM emp order by empno"; + +static OCIEnv *envhp = NULL; +static OCIServer *srvhp = NULL; +static OCIError *errhp = NULL; +static OCISvcCtx *svchp = NULL; +static OCIStmt *stmthp = NULL; +static OCIDefine *defnp = (OCIDefine *) 0; + +static OCIBind *bnd1p = (OCIBind *) 0; + +static sb4 checkerr(/*_ OCIError *errhp, sword status _*/); +static void cleanup(/*_ void _*/); + +static sb4 register_callback(); +static sb4 callback_fn(); + +int main(/*_ int argc, char *argv[] _*/); +static sword status; + + + +int main(argc, argv) +int argc; +char *argv[]; +{ + OCIFocbkStruct failover; + int exitCode = EX_FAILURE; + + sword i=0, empno=0, count=0, totcount=0; + + OCISession *authp = (OCISession *) 0; + + + if (checkerr(NULL, OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0))) + goto terminate; + + if (checkerr(NULL, OCIEnvInit((OCIEnv **) &envhp, OCI_DEFAULT, (size_t) 0, + (dvoid **) 0))) + goto terminate; + + if (checkerr(envhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + OCI_HTYPE_ERROR, (size_t) 0, (dvoid **)0))) + goto terminate; + + /* server contexts */ + if (checkerr(envhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + OCI_HTYPE_SERVER, (size_t) 0, + (dvoid **) 0))) + goto terminate; + + if (checkerr(envhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + OCI_HTYPE_SVCCTX, (size_t) 0, + (dvoid **) 0))) + goto terminate; + + if (checkerr(errhp, OCIServerAttach(srvhp, errhp, (text *)dbname, + strlen((char *)dbname), 0))) + goto terminate; + + /* set attribute server context in the service context */ + if (checkerr(errhp, OCIAttrSet((dvoid *) svchp, OCI_HTYPE_SVCCTX, + (dvoid *)srvhp, (ub4) 0, OCI_ATTR_SERVER, + (OCIError *) errhp))) + goto terminate; + + if (checkerr(envhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **)&authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, + (dvoid **) 0))) + goto terminate; + + if (checkerr(errhp, OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) username, (ub4) strlen((char *)username), + (ub4) OCI_ATTR_USERNAME, errhp))) + goto terminate; + + if (checkerr(errhp, OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *)password), + (ub4) OCI_ATTR_PASSWORD, errhp))) + goto terminate; + + if (checkerr(errhp, OCISessionBegin(svchp, errhp, authp, OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT))) + goto terminate; + + if (checkerr(errhp, OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, + (ub4) OCI_ATTR_SESSION, errhp))) + goto terminate; + + /* registers the OCI application failover callbacks */ + if (register_callback(srvhp, errhp,&failover)) + goto terminate; + + if (checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0))) + goto terminate; + + /* process SQL statement */ + if (checkerr(errhp, OCIStmtPrepare(stmthp, errhp, sel1, + (ub4) strlen((char *) sel1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT))) + goto terminate; + + if (checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, 1, + (dvoid *) &empno, + (sword) sizeof(sword), SQLT_INT, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, OCI_DEFAULT))) + goto terminate; + + status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT); + for(;;) + { + if (status != 0) + { + if (status == OCI_NO_DATA) + break; + else + { + checkerr(errhp, status); + goto terminate; + } + } + printf("empno: %d\n", empno); + /* execute and fetch */ + status=OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) 0, (ub4) 0); + } + + exitCode = EX_SUCCESS; + + terminate: + + if (exitCode == EX_SUCCESS) + printf("No errors.\n"); + else + printf("Failed due to errors.\n"); + + cleanup(); + return exitCode; +} + /* application failoever callback function */ +sb4 callback_fn(svchp, envhp, fo_ctx, fo_type, fo_event ) +dvoid * svchp; +dvoid * envhp; +dvoid *fo_ctx; +ub4 fo_type; +ub4 fo_event; +{ + switch (fo_event) + { + case OCI_FO_BEGIN: + { + printf(" Failing Over ... Please stand by \n"); + printf(" Failover type was found to be %s \n", + ((fo_type==OCI_FO_NONE) ? "NONE" + :(fo_type==OCI_FO_SESSION) ? "SESSION" + :(fo_type==OCI_FO_SELECT) ? "SELECT" + : "UNKNOWN!")); + printf(" Failover Context is :%s\n", + (fo_ctx?(char *)fo_ctx:"NULL POINTER!")); + break; + } + + case OCI_FO_ABORT: + { + printf(" Failover aborted. Failover will not take place.\n"); + break; + } + + case OCI_FO_END: + { + printf(" Failover ended ...resuming services\n"); + break; + } + + case OCI_FO_REAUTH: + { + printf(" Failed over user. Resuming services\n"); + + /* Application can check the OCI_ATTR_SESSION attribute of + the service handle to find out the user being + re-authenticated. + + After this, the application can replay any ALTER SESSION + commands associated with this session. These must have + been saved by the application in the fo_ctx + */ + break; + } + + + case OCI_FO_ERROR: + { + printf(" Failover error gotten. Sleeping...\n"); + sleep(3); + return OCI_FO_RETRY; + break; + } + + default: + { + printf("Bad Failover Event: %d.\n", fo_event); + break; + } + } + return 0; +} + + + + /* callback function registration */ +sb4 register_callback(srvhp, errhp,failover) +dvoid *srvhp; /* the server handle */ +OCIError *errhp; /* the error handle */ +OCIFocbkStruct *failover; +{ + + if (!(failover->fo_ctx = + (dvoid *)malloc(strlen(FAILOVER_S) + 1))) + { + (void) printf("Error - could not allocate failover context\n"); + return EX_FAILURE; + } + + /* initialize the context. */ + strcpy((char *)failover->fo_ctx, FAILOVER_S); + failover->callback_function = &callback_fn; + /* do the registration */ + if (checkerr(errhp, OCIAttrSet(srvhp, (ub4) OCI_HTYPE_SERVER, + (dvoid *) failover, (ub4) 0, + (ub4) OCI_ATTR_FOCBK, errhp))) + { + printf("Failed to set failover attribute\n"); + return EX_FAILURE; + } + + return EX_SUCCESS; +} + + + /* error handler */ +sb4 checkerr(ehndlp, status) +OCIError *ehndlp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + return EX_SUCCESS; + + case OCI_SUCCESS_WITH_INFO: + printf("Error - OCI_SUCCESS_WITH_INFO\n"); + return EX_SUCCESS; + + case OCI_NEED_DATA: + printf("Error - OCI_NEED_DATA\n"); + return EX_SUCCESS; + + case OCI_NO_DATA: + printf("Error - OCI_NODATA\n"); + return EX_SUCCESS; + + case OCI_ERROR: + if (ehndlp) + { + OCIErrorGet((dvoid *)ehndlp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + printf("Error - %.*s\n", 512, errbuf); + } + else + printf("Error - OCI_ERROR\n"); + return EX_FAILURE; + + case OCI_INVALID_HANDLE: + printf("Error - OCI_INVALID_HANDLE\n"); + return EX_FAILURE; + + case OCI_STILL_EXECUTING: + printf("Error - OCI_STILL_EXECUTE\n"); + return EX_SUCCESS; + + case OCI_CONTINUE: + printf("Error - OCI_CONTINUE\n"); + return EX_SUCCESS; + + default: + printf("Error - Unknown error\n"); + return EX_FAILURE; + } +} + + + /* cleanup resources */ +void cleanup() +{ + if (stmthp) + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + + if (errhp && srvhp) + (void) OCIServerDetach( srvhp, errhp, OCI_DEFAULT ); + + if (srvhp) + checkerr(errhp, OCIHandleFree((dvoid *) srvhp, OCI_HTYPE_SERVER)); + + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, OCI_HTYPE_SVCCTX); + + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, OCI_HTYPE_ENV); + return; +} + + + +/* end of file cdemofo.c */ + diff --git a/cdemofor.c b/cdemofor.c new file mode 100644 index 0000000..97efe32 --- /dev/null +++ b/cdemofor.c @@ -0,0 +1,143 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemofor.c 14-jul-99.13:12:32 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemofor.c - C Demo for ociFORmat + + DESCRIPTION + This file demonstrates an example of using the OCIFormat package. + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ewaugh 05/06/98 - OCIString renamed to OCIFormat. + nramakri 12/17/97 - Creation + +*/ + +#include +#include +#include +#include + +#define BUFLEN 100 +#define FORMATLEN 100 + +struct +{ + text buffer[BUFLEN]; + sbig_ora bytesWritten; + text formatString[FORMATLEN]; + text style[3]; +} MyDate[2]; + +sword checkerr(/*_ OCIError *errhp, sword status _*/); +int main (/*_ int argc, char *argv[] _*/); + +int main(argc, argv) +int argc; +char *argv[]; +{ + OCIEnv *envhp; + OCIError *errhp; + + ub1 month = 12; + ub1 day = 31; + ub1 year = 97; + + uword i; + + strcpy((char *)MyDate[0].formatString, "%(2)02u/%(1)02u/%(3)02u"); + strcpy((char *)MyDate[0].style, "US"); + strcpy((char *)MyDate[1].formatString, "%(1)02u/%(2)02u/%(3)02u"); + strcpy((char *)MyDate[1].style, "NZ"); + + (void) OCIInitialize(OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t))0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *))0); + + (void) OCIEnvInit((OCIEnv **)&envhp, OCI_DEFAULT, (size_t)0, (dvoid **)0); + + (void) OCIHandleAlloc((dvoid *)envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, + (size_t)0, (dvoid **)0); + + if (checkerr(errhp, OCIFormatInit(envhp, errhp)) != OCI_SUCCESS) + { + goto error; + } + + for (i = 0 ; i < 2 ; i++) + { + if (checkerr(errhp, OCIFormatString(envhp, errhp, MyDate[i].buffer, + BUFLEN, &MyDate[i].bytesWritten, + (CONST text *)MyDate[i].formatString, + OCIFormatUb1(day), + OCIFormatUb1(month), + OCIFormatUb1(year), + OCIFormatEnd)) == OCI_SUCCESS) + { + (void) printf("New Year's eve in %s style is %s\n", + (char *)MyDate[i].style, (char *)MyDate[i].buffer); + } + } + + (void) checkerr(errhp, OCIFormatTerm(envhp, errhp)); + +error: + if (errhp) + { + (void) OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR); + } + + return 0; +} + +sword checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4)1, (text *)NULL, + &errcode, + errbuf, (ub4)sizeof(errbuf), + OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", (int)512, (char *)errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + default: + break; + } + + return status; +} + +/* end of file cdemofor.c */ + diff --git a/cdemoin1.c b/cdemoin1.c new file mode 100644 index 0000000..d7a6db7 --- /dev/null +++ b/cdemoin1.c @@ -0,0 +1,761 @@ +/* Copyright (c) 1996, 2001, Oracle Corporation. All rights reserved. */ + +/* + + NAME + cdemoin1 - Demo program which modifies an inherited type in a table and + displays a record from the table. + + DESCRIPTION + This program pins an inherited instance in the object cache and displays + the attributes in it. It also updates a record of a table. + + NOTES + dependent files : + cdemoin1.h - Header file + cdemoin1.sql - SQL script to be run before execution + cdemoin1.tsc - test script (optional) + + Program Notes : + + MODIFIED (MM/DD/YY) + pzwu 05/18/01 - Fix bug1786565 + jchai 04/29/01 - change schema + rdwajan 08/22/00 - Creation +*/ + +#define NUMREC 3 +#include "cdemoin1.h" + +static OCIError *errhp = (OCIError *)0; +static OCIEnv *envhp = (OCIEnv *)0; +static OCIServer *svrhp = (OCIServer *)0; +static OCISession *sesnhp = (OCISession *)0; +static OCISvcCtx *svchp = (OCISvcCtx *)0; +static OCIStmt *stmthp = (OCIStmt *)0; + +static OCIRef *workadd[NUMREC]; /* Array of REFs for workadd to be populated */ +static text *database =(text *)""; +static text *username =(text *)"scott"; +static text *password =(text *)"tiger"; + +static text *selectSql = (text *) + "SELECT REF(a) FROM i_manager_tab a WHERE VALUE(a) IS OF (ONLY i_manager)"; + +static text *updateSql = (text *) + "SELECT REF(a) FROM i_manager_tab a WHERE VALUE(a) IS OF (ONLY i_manager) FOR UPDATE"; + +static text *insertSql = (text *) + "INSERT INTO i_people_tab VALUES (:v1)"; + +static text *selRef = (text *) + "SELECT REF(a) FROM i_residence_tab a"; + +int main(/*void*/); +/* Free the allocated handles */ +static void cleanup (void); + +/* Function to modify a record of an inherited object table */ +static void modifyFunction(); + +/* Function to select the ref of an inherited object */ +static void selectFunction (); + +/* Function to insert an instance of the subtype into a supertype table */ +static void insertFunction(); + +/* Function to display the attributes of the object */ +static void display (i_manager *sub_obj); + +/* Function to get an array of REFs */ +static void getRef(); + +static sword status = 0; + +int main (void) +{ + printf + ("cdemoin1 - Demonstrating select, insert and update on a subtype table\n"); + /* Initializing the environment in the Object mode*/ + + OCIEnvCreate((OCIEnv **) &envhp, OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0, (size_t) 0, (dvoid **) 0 ); + + OCIHandleAlloc (envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, (size_t)0, + (dvoid **)0); + + OCIHandleAlloc(envhp, (dvoid **)&svrhp, OCI_HTYPE_SERVER, (size_t)0, + (dvoid **)0); + + status = OCIServerAttach(svrhp, errhp, (text *)database, + (sb4)strlen((char *)database), OCI_DEFAULT); + + if (status != OCI_SUCCESS) + { + printf("OCIServerAttach failed \n"); + } + else + printf("OCIServerAttach - Success \n"); + + OCIHandleAlloc(envhp, (dvoid **)&svchp, OCI_HTYPE_SVCCTX, (size_t)0, + (dvoid **)0); + OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, (dvoid *)svrhp, (ub4)0, OCI_ATTR_SERVER, + errhp); + + OCIHandleAlloc(envhp, (dvoid **)&sesnhp, OCI_HTYPE_SESSION, (size_t)0, + (dvoid **)0); + + OCIAttrSet(sesnhp, OCI_HTYPE_SESSION, (dvoid *)username, + (ub4)strlen((char *)username), OCI_ATTR_USERNAME, errhp); + + OCIAttrSet(sesnhp, OCI_HTYPE_SESSION, (dvoid*)password, + (ub4)strlen((char *)password), OCI_ATTR_PASSWORD, errhp); + + printf("Connecting as %s/%s@%s\n",username,password,database); + + status = OCISessionBegin(svchp, errhp, sesnhp, OCI_CRED_RDBMS, OCI_DEFAULT); + if (status != OCI_SUCCESS) + { + printf("Connection failed \n"); + } + else + printf("Connection - Success \n"); + + OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, sesnhp, (ub4)0, OCI_ATTR_SESSION, errhp); + + /* Calling function to get an array of REFs to populate the varray */ + getRef(); + + /* Function to insert an instance of the subtype into a supertype table */ + insertFunction(); + + /* Function to modify the data of an inherited object */ + modifyFunction(); + + /* Function to display data from the table */ + selectFunction(); + + /* Free the allocated handles */ + cleanup(); + + printf("cdemoin1 - Done\n"); + return 1; +} /* End of main() */ + +/* Function to insert an instance of the subtype into a supertype table */ +static void insertFunction() +{ + OCIBind *bindhp = (OCIBind *)0; + i_residence elem; + i_residence *elemptr = &elem; + i_manager *sub_obj = (i_manager *)0; + i_manager_ind ind; + OCIType *i_manager_tdo = (OCIType *)0; + + ub4 subSize = 0; + ub4 sizeUB4 = sizeof (ub4); + sb4 size = 0; + text *name = (text*)"JENNY"; + ub4 name_len =(ub4)( strlen( (char * ) name)); + ub4 ssn = 303; /* Data for ssn */ + ub4 addr_hno = 33; /*Data for hno of addr */ + text *addr_street = (text *)"T33"; /*Data for street of addr */ + ub4 addr_streetLen = (ub4)(strlen( (char *)addr_street)); + ub4 altadrs_hno = 333; /*data for hno of altadrs */ + text *altadrs_street = (text *)"T333"; /*Data for street of altadrs */ + ub4 altadrs_streetLen = (ub4)(strlen( (char *)altadrs_street)); + ub4 empno = 3333; /* data for empno */ + + sb4 index1 = 0; /* Index for the starting point of the scan */ + sb4 index2 = 0; /* Index of the next existing element */ + boolean eoc = TRUE; /* For getting the status for the availability of + the next index */ + ub4 count = 0; /* Loop counter */ + + memset(&ind, 0, sizeof(ind)); + memset(elemptr, 0, sizeof(elem)); + OCIHandleAlloc (envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + if ((status = OCIStmtPrepare (stmthp, errhp, (text *)insertSql, + (ub4)strlen((char *)insertSql),OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIStmtPrepare - Fail\n"); + } + + if ((status = OCIBindByName(stmthp, &bindhp, errhp, (text *)":v1", + (sb4) -1, (dvoid *)0, (sb4)0, SQLT_NTY, (dvoid *)0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIBindByName - Failure \n"); + } + + if ((status = OCITypeByName (envhp, errhp, svchp, (CONST text *)0, (ub4)0, + (CONST text *)"I_MANAGER", (ub4)strlen ((char *)"I_MANAGER"), + (CONST text *)0, (ub4)0, OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, + &i_manager_tdo)) != OCI_SUCCESS) + { + printf ("OCITypeByName - Fail\n"); + } + + if (( status = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_OBJECT, + (OCIType *)i_manager_tdo, (dvoid *)0, OCI_DURATION_SESSION, TRUE, + (dvoid **) &sub_obj)) != OCI_SUCCESS) + { + printf ("OCIObjectNew - Failure\n"); + } + OCINumberFromInt (errhp, (dvoid *)&ssn, sizeof(ssn), OCI_NUMBER_UNSIGNED, + &(sub_obj->_super.ssn)); + OCINumberFromInt (errhp, (dvoid *)&empno, sizeof(empno), OCI_NUMBER_UNSIGNED, + &(sub_obj->empno)); + + OCINumberFromInt (errhp, (dvoid *)&addr_hno, sizeof(addr_hno),OCI_NUMBER_UNSIGNED, + &(sub_obj->_super.addr.hno)); + + OCIStringAssignText (envhp, errhp, (text *)name, (ub2)name_len, + &(sub_obj->_super.name)); + OCIStringAssignText (envhp, errhp, (text *)addr_street, (ub2)addr_streetLen, + &(sub_obj->_super.addr.street)); + for (count = 0; count < NUMREC; ++count) + { + OCIStringAssignText (envhp, errhp, (text *)altadrs_street, (ub2)altadrs_streetLen, + &(elemptr->street)); + OCINumberFromInt (errhp, (dvoid *)&altadrs_hno, sizeof(altadrs_hno), + OCI_NUMBER_UNSIGNED, &(elemptr->hno)); + if (( status = OCICollAppend (envhp, errhp, (dvoid *)elemptr, (dvoid *)&ind, + (OCIColl *)sub_obj->_super.altadrs)) != OCI_SUCCESS) + { + printf ("OCICollAppend - Fail\n"); + } + altadrs_hno ++; + } + for (count = 0; count < NUMREC; ++count) + { + if (( status = OCICollAppend (envhp, errhp, (dvoid *)workadd[count], + (dvoid *)&ind, (OCIColl *)sub_obj->workadd)) != OCI_SUCCESS) + { + printf ("OCICollAppend - Fail\n"); + } + } + OCITableSize(envhp, errhp,(CONST OCITable*) (sub_obj->_super.altadrs), &size); + OCITableSize(envhp, errhp,(CONST OCITable*) (sub_obj->workadd), &size); + + if (OCIBindObject(bindhp, errhp, i_manager_tdo, + (dvoid **) &sub_obj, (ub4 *)0, (dvoid **)&ind , (ub4 *) 0) != OCI_SUCCESS) + { + printf("OCIBindObject - Failure \n"); + } + + printf ("\nExecuting the statement:%s\n", insertSql); + if (OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_COMMIT_ON_SUCCESS ) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure \n"); + } + else + printf("OCIStmtExecute - Success\n"); + + OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT); +}/* End on insertFunction() */ + +/* Function to modify the data of an inherited object */ +static void modifyFunction () +{ + OCIDefine *defhp = (OCIDefine *)0; + OCIRef *sub_ref = (OCIRef *)0; + i_residence elem; + i_residence *elemptr = (i_residence *)0; + i_manager *sub_obj = (i_manager *)0; + ub4 subSize = 0; + ub4 sizeUB4 = sizeof (ub4); + OCIType *mtype = (OCIType *)0; + + text *name = (text*)"JENNY"; + ub4 name_len=(ub4)strlen( (char * ) name); + ub4 ssn = 808; /* Data for ssn */ + ub4 addr_hno = 800; /*Data for hno of addr */ + text *addr_street = (text *)"Laurel Road"; /*Data for street of addr */ + ub4 addr_streetLen = (ub4)strlen( (char *)addr_street); + ub4 altadrs_hno = 800; /*data for hno of altadrs */ + text *altadrs_street = (text *)"Shoreline Street"; /*Data for street of altadrs */ + ub4 altadrs_streetLen = (ub4)strlen( (char *)altadrs_street); + ub4 empno = 8888; /* data for empno */ + + sb4 index1 = 0; /* Index for the starting point of the scan */ + sb4 index2 = 0; /* Index of the next existing element */ + boolean eoc = TRUE; /* For getting the status for the availability of + the next index */ + ub4 count = 0; /* Loop counter */ + OCIHandleAlloc (envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + if ((status = OCIStmtPrepare (stmthp, errhp, (text *)updateSql, + (ub4)strlen((char *)updateSql),OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIStmtPrepare - Fail\n"); + } + + if (( status = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_REF, + (OCIType *)0, (dvoid *)0, OCI_DURATION_DEFAULT, FALSE, + (dvoid **) &sub_ref)) != OCI_SUCCESS) + { + printf ("OCIObjectNew - Failure\n"); + } + + if ((status = OCIDefineByPos(stmthp, &defhp, errhp, (ub4) 1, + (dvoid *) 0, (sb4) 0, SQLT_REF, (dvoid *) 0, + (ub2 *)0, (ub2 *)0, (ub4) OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIDefineByPos - Failure \n"); + } + + if ((status = OCIDefineObject(defhp, errhp, (OCIType *)0, + (dvoid **)&sub_ref, (ub4 *)&subSize, (dvoid **) 0, (ub4 *) 0)) + != OCI_SUCCESS) + { + printf ("OCIDefineObject - Failure \n"); + } + + printf ("\nExecuting the statement:%s\n", updateSql); + if (OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_COMMIT_ON_SUCCESS ) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure \n"); + } + else + { + printf("OCIStmtExecute - Success\n"); + if ((status = OCIObjectPin(envhp, errhp, sub_ref, (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **) &sub_obj)) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + } + else + { + printf ("\nDisplaying the original data from the employee table \n"); + display (sub_obj); + printf ("\nModifying the data present in the object\n"); + if ((status = OCIObjectMarkUpdate (envhp, errhp, (dvoid *)sub_obj)) + != OCI_SUCCESS) + { + printf ("OCIObjectMarkUpdate - Fail\n"); + } + else + { + printf ("OCIObjectMarkUpdate - Success\n"); + } + OCINumberFromInt (errhp, (dvoid *)&ssn, sizeof(ssn), OCI_NUMBER_UNSIGNED, + &(sub_obj->_super.ssn)); + OCINumberFromInt (errhp, (dvoid *)&empno, sizeof(empno), + OCI_NUMBER_UNSIGNED, &(sub_obj->empno)); + OCINumberFromInt (errhp, (dvoid *)&addr_hno, sizeof(addr_hno), + OCI_NUMBER_UNSIGNED, &(sub_obj->_super.addr.hno)); + OCIStringAssignText (envhp, errhp, (text *)name, (ub2)name_len, + &(sub_obj->_super.name)); + OCIStringAssignText (envhp, errhp, (text *)addr_street, (ub2)addr_streetLen, + &(sub_obj->_super.addr.street)); + OCITableFirst(envhp, errhp, (CONST OCITable*)sub_obj->_super.altadrs, + &index1); + OCICollGetElem(envhp, errhp, (OCIColl *)sub_obj->_super.altadrs, + index1, (boolean *)&eoc, (dvoid **)&elemptr, (dvoid **)0); + OCINumberFromInt (errhp, (dvoid *)&altadrs_hno, sizeof(altadrs_hno), + OCI_NUMBER_UNSIGNED, &(elemptr->hno)); + OCIStringAssignText (envhp, errhp, (text *)altadrs_street, (ub2)altadrs_streetLen, + &(elemptr->street)); + for (count = 0; count < NUMREC-1; ++count) + { + altadrs_hno += count; + OCITableNext(envhp, errhp, index1, + (CONST OCITable*) sub_obj->_super.altadrs, &index2, &eoc); + OCICollGetElem(envhp, errhp, (OCIColl *)sub_obj->_super.altadrs, + index2, (boolean *)&eoc, (dvoid **)&elemptr, (dvoid **)0); + OCINumberFromInt (errhp, (dvoid *)&altadrs_hno, sizeof(altadrs_hno), + OCI_NUMBER_UNSIGNED, &(elemptr->hno)); + OCIStringAssignText (envhp, errhp, (text *)altadrs_street, (ub2)altadrs_streetLen, + &(elemptr->street)); + index1 = index2; + } + index1 = 0; + index2 = 0; + + OCITableFirst(envhp, errhp, (CONST OCITable*)sub_obj->workadd, &index1); + OCICollAssignElem (envhp, errhp, index1, (dvoid *)workadd[count], + (dvoid *)0, (OCIColl *)sub_obj->workadd); + for (count = 0; count < NUMREC; ++count) + { + OCITableNext(envhp, errhp, index1,(CONST OCITable*) sub_obj->workadd, + &index2, &eoc); + OCICollAssignElem (envhp, errhp, index1, (dvoid *)workadd[count], + (dvoid *)0, (OCIColl *)sub_obj->workadd); + index1 = index2; + } + + if ((status = OCIObjectFlush(envhp, errhp, sub_obj)) != OCI_SUCCESS) + { + printf ("OCIObjectFlush - Fail\n"); + } + else + { + printf ("OCIObjectFlush - Success\n"); + } + printf ("Refreshing the object\n"); + if ((status = OCIObjectRefresh(envhp, errhp, (dvoid *)sub_obj)) + != OCI_SUCCESS) + { + printf ("OCIObjectRefresh - Fail\n"); + } + else + { + printf ("OCIObjectRefresh - Success\n"); + } + printf ("\nDisplaying the data in the employee table after the refresh\n"); + display (sub_obj); + + printf ("\nModifying the data present in the object once again\n"); + ssn = 606; /* Data for ssn */ + addr_hno = 200; /*Data for hno of addr */ + addr_street = (text *)"Main Street"; /*Data for street of addr */ + addr_streetLen = (ub4)strlen( (char *)addr_street); + altadrs_hno = 600; /*data for hno of altadrs */ + altadrs_street = (text *)"Shell Blvd";/*Data for street of altadrs*/ + altadrs_streetLen = (ub4)strlen( (char *)altadrs_street); + empno = 6666; /* data for empno */ + + if ((status = OCIObjectMarkUpdate (envhp, errhp, (dvoid *)sub_obj)) + != OCI_SUCCESS) + { + printf ("OCIObjectMarkUpdate - Fail\n"); + } + else + { + printf ("OCIObjectMarkUpdate - Success\n"); + } + index1 = 0; + index2 = 0; + OCINumberFromInt (errhp, (dvoid *)&ssn, sizeof(ssn), OCI_NUMBER_UNSIGNED, + &(sub_obj->_super.ssn)); + OCINumberFromInt (errhp, (dvoid *)&empno, sizeof(empno), OCI_NUMBER_UNSIGNED, + &(sub_obj->empno)); + OCINumberFromInt (errhp, (dvoid *)&addr_hno, sizeof(addr_hno), + OCI_NUMBER_UNSIGNED, &(sub_obj->_super.addr.hno)); + OCIStringAssignText (envhp, errhp, (text *)addr_street, + (ub2)addr_streetLen, &(sub_obj->_super.addr.street)); + OCITableFirst(envhp, errhp,(CONST OCITable*)sub_obj->_super.altadrs, + &index1); + OCICollGetElem(envhp, errhp, (OCIColl *)sub_obj->_super.altadrs, + index1, (boolean *)&eoc, (dvoid **)&elemptr, (dvoid **)0); + OCINumberFromInt (errhp, (dvoid *)&altadrs_hno, sizeof(altadrs_hno), + OCI_NUMBER_UNSIGNED, &(elemptr->hno)); + OCIStringAssignText (envhp, errhp, (text *)altadrs_street, (ub2)altadrs_streetLen, + &(elemptr->street)); + for (count = 0; count < NUMREC-1; ++count) + { + altadrs_hno += count; + OCITableNext(envhp, errhp, index1,(CONST OCITable*) sub_obj->_super.altadrs, &index2, + &eoc); + OCICollGetElem(envhp, errhp, (OCIColl *)sub_obj->_super.altadrs, + index2, (boolean *)&eoc, (dvoid **)&elemptr, (dvoid **)0); + OCINumberFromInt (errhp, (dvoid *)&altadrs_hno, sizeof(altadrs_hno), + OCI_NUMBER_UNSIGNED, &(elemptr->hno)); + OCIStringAssignText (envhp, errhp, (text *)altadrs_street, (ub2)altadrs_streetLen, + &(elemptr->street)); + index1 = index2; + } + index1 = 0; + index2 = 0; + + OCITableFirst(envhp, errhp, (CONST OCITable*)sub_obj->workadd, &index1); + OCICollAssignElem (envhp, errhp, index1, (dvoid *)workadd[count], + (dvoid *)0, (OCIColl *)sub_obj->workadd); + for (count = 0; count < NUMREC; ++count) + { + OCITableNext(envhp, errhp, index1, (CONST OCITable*)sub_obj->workadd, + &index2, &eoc); + OCICollAssignElem (envhp, errhp, index1, (dvoid *)workadd[count], + (dvoid *)0, (OCIColl *)sub_obj->workadd); + index1 = index2; + } + if ((status = OCICacheFlush (envhp, errhp, svchp, NULL, NULL, &sub_ref)) + != OCI_SUCCESS) + { + printf ("OCICacheFlush - Fail\n"); + } + else + { + printf ("OCICacheFlush - Success\n"); + } + } + + if ((status = OCITransCommit (svchp, errhp, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCITransCommit - Fail\n"); + } + else + printf ("OCITransCommit - Success\n"); + } + OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT); + +} /* end of modifyFunction() */ + +/* Function to display data from the table */ +static void selectFunction () +{ + OCIDefine *defhp = (OCIDefine *)0; + OCIRef *sub_ref = (OCIRef *)0; + i_manager *sub_obj = (i_manager *)0; + ub4 subSize = 0; + ub4 sizeUB4 = sizeof (ub4); + OCIType *mtype = (OCIType *)0; + + OCIHandleAlloc (envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + if ((status = OCIStmtPrepare (stmthp, errhp, (text *)selectSql, + (ub4)strlen((char *)selectSql),OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIStmtPrepare - Fail\n"); + } + + if (( status = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_REF, + (OCIType *)0, (dvoid *)0, OCI_DURATION_DEFAULT, FALSE, + (dvoid **) &sub_ref)) != OCI_SUCCESS) + { + printf ("OCIObjectNew - Failure\n"); + } + + if ((status = OCIDefineByPos(stmthp, &defhp, errhp, (ub4) 1, + (dvoid *) 0, (sb4) 0, SQLT_REF, (dvoid *) 0, + (ub2 *)0, (ub2 *)0, (ub4) OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIDefineByPos - Failure \n"); + } + + if ((status = OCIDefineObject(defhp, errhp, (OCIType *) 0, + (dvoid **)&sub_ref, (ub4 *)&subSize, (dvoid **) 0, (ub4 *) 0)) + != OCI_SUCCESS) + { + printf ("OCIDefineObject - Failure \n"); + } + + printf ("\nExecuting the statement:%s\n", selectSql); + if (OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT ) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure \n"); + } + else + { + printf("OCIStmtExecute - Success\n"); + if ((status = OCIObjectPin(envhp, errhp, sub_ref, (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **) &sub_obj)) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + } + else + { + printf ("\nDisplaying the contents of the object\n"); + display (sub_obj); + } + } +} /* end of selectFunction() */ + +/* Function to display the attributes of the object */ +static void display (i_manager *sub_obj) +{ + ub4 sizeUB4 = sizeof (ub4); + ub4 ssn = 0; /* Variable to fetch ssn */ + ub4 addr_hno = 0; /*Variable to fetch hno of addr */ + text *name; /*Variable to fetch name */ + ub4 name_len = 0; + text *addr_street; /*Variable to fetch street of addr */ + ub4 addr_streetLen = 0; + ub4 altadrs_hno = 0; /*Variable to fetch hno of altadrs */ + text *altadrs_street; /*Variable to fetch street of altadrs */ + ub4 altadrs_streetLen = 0; + ub4 empno = 0; /* Variable to fetch empno */ + ub4 workadd_hno = 0; /*Variable to fetch hno of workadd */ + text *workadd_street; /*Variable to fetch street of workadd */ + ub4 workadd_streetLen = 0; + + sb4 size = 111; + sb4 index1 = 0; /* Index for the starting point of the scan */ + sb4 index2 = 0; /* Index of the next existing element */ + boolean eoc = TRUE; /* For getting the status for the availability of + the next index */ + ub4 count = 0; + i_residence *elem = (i_residence *)0; /* To get the element from the + nested table */ + i_residence_ref *elemref = (i_residence_ref *)0; + i_residence *objptr = (i_residence *)0; + + name = OCIStringPtr(envhp, sub_obj->_super.name); + name_len = OCIStringSize (envhp, sub_obj->_super.name); + printf("name is : %.*s\n", name_len, name); + OCINumberToInt (errhp, &(sub_obj->_super.ssn), sizeof(ub4), + OCI_NUMBER_UNSIGNED, (dvoid *)&ssn); + printf("SSN: %d\n", ssn); + OCINumberToInt (errhp, &(sub_obj->_super.addr.hno), sizeof(ub4), + OCI_NUMBER_UNSIGNED, (dvoid *)&addr_hno); + addr_street = OCIStringPtr(envhp, sub_obj->_super.addr.street); + addr_streetLen = OCIStringSize (envhp, sub_obj->_super.addr.street); + printf("Primary address: %d %.*s\n", addr_hno,addr_streetLen, addr_street); + + OCITableSize(envhp, errhp, (CONST OCITable*)(sub_obj->_super.altadrs), &size); + OCITableFirst(envhp, errhp,(CONST OCITable*)sub_obj->_super.altadrs, &index1); + status = OCICollGetElem(envhp, errhp, (OCIColl *)sub_obj->_super.altadrs, + index1, (boolean *)&eoc, (dvoid **)&elem, (dvoid **)0); + OCINumberToInt (errhp, &(elem->hno), sizeof(ub4), + OCI_NUMBER_UNSIGNED, (dvoid *)&altadrs_hno); + altadrs_street = OCIStringPtr(envhp, elem->street); + altadrs_streetLen = OCIStringSize (envhp, elem->street); + printf("Other addresses:\n"); + printf(" %d %.*s\n", altadrs_hno, altadrs_streetLen, + altadrs_street); + for (count = 1; count < size; count++) + { + OCITableNext(envhp, errhp, index1, + (CONST OCITable*)sub_obj->_super.altadrs, &index2, &eoc); + OCICollGetElem(envhp, errhp,(OCIColl *)sub_obj->_super.altadrs, index2, + (boolean *)&eoc, (dvoid **)&elem, (dvoid **)0); + OCINumberToInt (errhp, &(elem->hno), sizeof(ub4), OCI_NUMBER_UNSIGNED, + (dvoid *)&altadrs_hno); + altadrs_street = OCIStringPtr(envhp, elem->street); + altadrs_streetLen = OCIStringSize (envhp, elem->street); + printf(" %d %.*s\n", altadrs_hno, altadrs_streetLen, + altadrs_street); + index1 = index2; + } + + OCINumberToInt (errhp, &(sub_obj->empno), sizeof(ub4), + OCI_NUMBER_UNSIGNED, (dvoid *)&empno); + printf("EMPNO: %d\n", empno); + + index1 = 1; + eoc = TRUE; + OCITableSize(envhp, errhp, (CONST OCITable*) sub_obj->workadd, &size); + OCITableFirst(envhp, errhp,(CONST OCITable*) sub_obj->workadd, &index1); + status = OCICollGetElem(envhp, errhp, (OCIColl *)(sub_obj->workadd), + index1, (boolean *)&eoc, (dvoid **)&elemref, (dvoid **)0); + if (status != OCI_SUCCESS) + { + printf("OCICollGetElem - Failure \n"); + } + elemref = *( OCIRef **)elemref; + + if ((status = OCIObjectPin(envhp, errhp, elemref, + (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **) &objptr)) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + } + + OCINumberToInt (errhp, &(objptr->hno), sizeof(ub4), OCI_NUMBER_UNSIGNED, + (dvoid *)&workadd_hno); + + workadd_street = OCIStringPtr(envhp, objptr->street); + workadd_streetLen = OCIStringSize (envhp, objptr->street); + printf("Work Addresses:\n"); + printf(" %d %.*s\n", workadd_hno,workadd_streetLen, + workadd_street); + for (count = 1; count < size; count++) + { + OCITableNext(envhp, errhp, index1, + (CONST OCITable*)sub_obj->workadd, &index2, &eoc); + status = OCICollGetElem(envhp, errhp, (OCIColl *)(sub_obj->workadd), + index2, (boolean *)&eoc, (dvoid **)&elemref, (dvoid **)0); + if (status != OCI_SUCCESS) + { + printf("OCICollGetElem - Failure \n"); + } + elemref = *( OCIRef **)elemref; + + if ((status = OCIObjectPin(envhp, errhp, elemref, + (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **) &objptr)) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + } + OCINumberToInt (errhp, &(objptr->hno), sizeof(ub4), OCI_NUMBER_UNSIGNED, + (dvoid *)&workadd_hno); + + workadd_street = OCIStringPtr(envhp, objptr->street); + workadd_streetLen = OCIStringSize (envhp, objptr->street); + printf(" %d %.*s\n", workadd_hno,workadd_streetLen, + workadd_street); + index1 = index2; + } +} /* end of display ((i_manager *) */ + +/* Function to get an array of REFs to populate the varray of REFs*/ +static void getRef() +{ + OCIDefine *defhp = (OCIDefine *) 0; /* For the REF column */ + i_residence *sub_obj[NUMREC]; + ub4 subsize[NUMREC]; + ub4 pos = 0; + ub4 arraySize = NUMREC; + + OCIHandleAlloc(envhp, (dvoid **) &stmthp, OCI_HTYPE_STMT, (size_t) 0, + ((dvoid **) 0)); + + if((status = OCIStmtPrepare(stmthp, errhp, (text *) selRef, + (ub4) strlen((char *) selRef), OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf("OciStmtPrepare - Failure\n"); + } + + if((status = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_REF, + (OCIType *) 0, (dvoid *) 0, OCI_DURATION_DEFAULT, FALSE, + (dvoid **) workadd)) != OCI_SUCCESS) + { + printf("OCIObjectNew - Failure\n"); + } + + if((status = OCIDefineByPos(stmthp, &defhp, errhp, (ub4) 1, (dvoid *) 0, + (sb4) 0, SQLT_REF, (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT )) + != OCI_SUCCESS) + { + printf("OCIDefineByPos - Failure\n"); + } + + if((status = OCIDefineObject(defhp, errhp, (OCIType *) 0, (dvoid **) workadd, + subsize, (dvoid **) 0, (ub4 *) 0)) != OCI_SUCCESS) + { + printf("OCIDefineObject - failure\n"); + } + + if((status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) NUMREC, (ub4) 0, + (OCISnapshot *) 0, (OCISnapshot *) 0, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure\n"); + } + else + { + if((status = OCIObjectArrayPin(envhp, errhp, workadd, (ub4) arraySize, + (OCIComplexObject **) 0, 0, OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **) sub_obj, (ub4 *) &pos)) != OCI_SUCCESS) + { + printf("OCIObjectArrayPin - Failure\n"); + } + } + OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT); +} /* End of getRef() */ + +/* Freeing the allocated handles */ +static void cleanup () +{ + OCISessionEnd (svchp, errhp, sesnhp, OCI_DEFAULT ); + OCIHandleFree((dvoid *) sesnhp, OCI_HTYPE_SESSION); + OCIServerDetach(svrhp, errhp, OCI_DEFAULT ); + OCIHandleFree((dvoid *) svrhp, OCI_HTYPE_SERVER); + OCIHandleFree((dvoid *) svchp, OCI_HTYPE_SVCCTX); + OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + return; +}/* End of cleanup() */ + + diff --git a/cdemoin1.h b/cdemoin1.h new file mode 100644 index 0000000..edde208 --- /dev/null +++ b/cdemoin1.h @@ -0,0 +1,85 @@ +/* Copyright (c) Oracle Corporation 1995. All Rights Reserved. */ + +/* + NAME + i_residence - Demo program which modifies an inherited type in a table and + displays a record from the table. + + DESCRIPTION + This program pins an inherited instance in the object cache and displays + the attributes in it. It also updates a record of a table. + + RELATED DOCUMENTS + + + NOTES + MODIFIED + rdwajan 08/11/00 Created +*/ +#include +#include + +#ifndef CDEMOIN1_ORACLE +# define CDEMOIN1_ORACLE + +#ifndef OCI_ORACLE +# include +#endif + +typedef OCIRef i_manager_ref; +typedef OCIArray i_residence_arr; +typedef OCIRef i_people_ref; +typedef OCIRef i_residence_ref; +typedef OCITable i_residence_nest; + +struct i_residence +{ + OCINumber hno; + OCIString * street; +}; +typedef struct i_residence i_residence; + +struct i_residence_ind +{ + OCIInd _atomic; + OCIInd hno; + OCIInd street; +}; +typedef struct i_residence_ind i_residence_ind; + +struct i_people +{ + OCIString * name; + OCINumber ssn; + struct i_residence addr; + i_residence_nest * altadrs; +}; +typedef struct i_people i_people; + +struct i_people_ind +{ + OCIInd _atomic; + OCIInd name; + OCIInd ssn; + struct i_residence_ind addr; + OCIInd altadrs; +}; +typedef struct i_people_ind i_people_ind; + +struct i_manager +{ + i_people _super; + OCINumber empno; + i_residence_arr * workadd; +}; +typedef struct i_manager i_manager; + +struct i_manager_ind +{ + i_people _super; + OCIInd empno; + OCIInd workadd; +}; +typedef struct i_manager_ind i_manager_ind; + +#endif diff --git a/cdemoin1.sql b/cdemoin1.sql new file mode 100644 index 0000000..536f084 --- /dev/null +++ b/cdemoin1.sql @@ -0,0 +1,66 @@ +/* Copyright (c) Oracle Corporation 1995. All Rights Reserved. */ + +/* + NAME + cdemoin1 - Demo program which modifies an inherited type in a table and + displays a record from the table. + + DESCRIPTION + This program pins an inherited instance in the object cache and displays + the attributes in it. It also updates a record of a table. + + MODIFIED + rdwajan 08/29/00 Created + +*/ + +SET SERVEROUTPUT ON +CONNECT scott/tiger; + +DROP TABLE i_manager_tab; +DROP TABLE i_people_tab; +DROP TABLE i_residence_tab; +DROP TYPE i_manager; +DROP TYPE i_people; +DROP TYPE i_residence_nest; +DROP TYPE i_residence_arr; +DROP TYPE i_residence; + +CREATE TYPE i_residence AS OBJECT +( hno NUMBER, street VARCHAR2(50) ) +/ + +CREATE TYPE i_residence_arr AS VARRAY(3) OF REF i_residence; +/ +CREATE TYPE i_residence_nest AS TABLE OF i_residence; +/ + +CREATE TYPE i_people AS OBJECT +(name VARCHAR2(10), ssn NUMBER, addr i_residence, atladrs i_residence_nest) NOT FINAL; +/ + +CREATE TYPE i_manager UNDER i_people +( empno NUMBER, workadd i_residence_arr) ; +/ + +CREATE TABLE i_residence_tab OF i_residence; + +INSERT INTO i_residence_tab values (100, 'Oracle Parkway'); +INSERT INTO i_residence_tab values (200, 'Oracle Parkway'); +INSERT INTO i_residence_tab values (300, 'Oracle Parkway'); + +CREATE TABLE i_people_tab OF i_people +NESTED TABLE atladrs STORE AS i_people_nt_tab1; + +CREATE TABLE i_manager_tab OF i_manager +NESTED TABLE atladrs STORE AS i_manager_nt_tab2; + +INSERT INTO i_manager_tab VALUES (i_manager('ROOPA',101, +i_residence (1000, 'Silver Blvd'), +i_residence_nest (i_residence (201, 'Willow Road'), i_residence (505, 'Springfield St')), +45001, +i_residence_arr ((SELECT REF(a) FROM i_residence_tab a WHERE a.hno = 100), +(SELECT REF(a) FROM i_residence_tab a WHERE a.hno = 200), +(SELECT REF(a) FROM i_residence_tab a WHERE a.hno = 300))) ); + +COMMIT; diff --git a/cdemoin2.c b/cdemoin2.c new file mode 100644 index 0000000..4f5da53 --- /dev/null +++ b/cdemoin2.c @@ -0,0 +1,488 @@ +/* Copyright (c) Oracle Corporation 1996, 1997, 1998. All Rights Reserved. */ + +/* + + NAME + cdemoin2 - Demo program to perform attribute substitutability. + + DESCRIPTION + This program demonstrates attribute substitutability, wherein a column + which is of REF to a supertype is substituted with a REF to a subtype. + All the data from the table are then displayed. + + + NOTES + dependent files : + cdemoin2.h - Header file + cdemoin2.sql - SQL script to be run before execution + cdemoin2.tsc - test script (optional) + + Program Notes : + + MODIFIED (MM/DD/YY) + rdwajan 08/25/00 - Creation +*/ + +#include "cdemoin2.h" + +static OCIError *errhp = (OCIError *)0; +static OCIEnv *envhp = (OCIEnv *)0; +static OCIServer *svrhp = (OCIServer *)0; +static OCISession *sesnhp = (OCISession *)0; +static OCISvcCtx *svchp = (OCISvcCtx *)0; +static OCIStmt *stmthp = (OCIStmt *)0; + +static text *database =(text *)""; +static text *username =(text *)"scott"; +static text *password =(text *)"tiger"; + +static text *updateSql1 = (text *) + "UPDATE cdemoin2_person_tab SET vacation_home = :v1 WHERE ssn = 999"; + +static text *updateSql2 = (text *) + "UPDATE cdemoin2_person_tab SET first_home = :v1 WHERE ssn = 999"; + +static text *getRefSql1 = (text *) + "SELECT REF(a) FROM cdemoin2_address_tab a WHERE a.hno = 300"; + +static text *getRefSql2 = (text *) + "SELECT REF(a) FROM cdemoin2_sec_address_tab a WHERE a.hno = 100"; + +static text *displaySql = (text *) +"SELECT vacation_home, first_home FROM cdemoin2_person_tab"; +/* where deref(vacation_home) is of (cdemoin2_sec_address, cdemoin2_address)";*/ + +/* Free the allocated handles */ +static void cleanup (void); + +/* Check for errors */ +void checkerr (OCIError *errhp, sword status); + +/* Function to display the records before updation*/ +static void displayFunction1(); + +/* Function to display the records after updation*/ +static void displayFunction2(); + +/* Function to modify the REF column to show substitutability */ +static void updateFunction(text *getRefSql, text *updateSql); + +sword status = 0; + +int main (void) +{ + printf("cdemoin2 - Demo program to perform attribute substitutability\n"); + /* Initializing the environment in the Object mode*/ + OCIEnvCreate (&envhp, OCI_OBJECT, (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)()) 0, (dvoid (*)()) 0, 0, (dvoid *)0); + + OCIHandleAlloc (envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, (size_t)0, + (dvoid **)0); + + OCIHandleAlloc(envhp, (dvoid **)&svrhp, OCI_HTYPE_SERVER, (size_t)0, + (dvoid **)0); + + status = OCIServerAttach(svrhp, errhp, (text *)database, + (sb4)strlen((char *)database), OCI_DEFAULT); + + if (status != OCI_SUCCESS) + { + printf("OCIServerAttach failed \n"); + checkerr(errhp, status); + } + else + printf("OCIServerAttach - Success \n"); + + OCIHandleAlloc(envhp, (dvoid **)&svchp, OCI_HTYPE_SVCCTX, (size_t)0, + (dvoid **)0); + OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, (dvoid *)svrhp, (ub4)0, OCI_ATTR_SERVER, + errhp); + + OCIHandleAlloc(envhp, (dvoid **)&sesnhp, OCI_HTYPE_SESSION, (size_t)0, + (dvoid **)0); + + OCIAttrSet(sesnhp, OCI_HTYPE_SESSION, (dvoid *)username, + (ub4)strlen((char *)username), OCI_ATTR_USERNAME, errhp); + + OCIAttrSet(sesnhp, OCI_HTYPE_SESSION, (dvoid*)password, + (ub4)strlen((char *)password), OCI_ATTR_PASSWORD, errhp); + + printf("Connecting as %s/%s@%s\n",username,password,database); + + status = OCISessionBegin(svchp, errhp, sesnhp, OCI_CRED_RDBMS, OCI_DEFAULT); + if (status != OCI_SUCCESS) + { + printf("Connection failed \n"); + checkerr(errhp, status); + } + else + printf("Connection - Success \n"); + + OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, sesnhp, (ub4)0, OCI_ATTR_SESSION, errhp); + + /* Function to display records before updation*/ + printf ("Displaying records before updation\n"); + displayFunction1(); + + /* Substituting a REF of a subtype with a REF of a supertype */ + updateFunction(getRefSql1, updateSql1); + + /* Substituting a REF of a supertype with a REF of a subtype */ + updateFunction(getRefSql2, updateSql2); + + /* Function to display records after updation*/ + printf ("Displaying records after updation\n"); + displayFunction2(); + + /* Free the allocated handles */ + cleanup(); + + printf("cdemoin2 - Done\n"); +} /* End of main() */ + +/* Function to display the contents of the table before updation*/ +static void displayFunction1 () +{ + OCIDefine *def1hp = (OCIDefine *)0; /* For vacation_home */ + OCIDefine *def2hp = (OCIDefine *)0; /* For first_home */ + OCIRef *s_ref = (OCIRef *)0; + OCIRef *ref = (OCIRef *)0; + cdemoin2_sec_address *s_obj = (cdemoin2_sec_address *)0; + cdemoin2_address *obj = (cdemoin2_address *)0; + ub4 subSize = 0; + sb4 size = 0; + + ub4 hno = 0; /* Variable to fetch hno */ + ub4 sizeUB4 = sizeof (ub4); + text *street; /* Variable to fetch street */ + ub4 streetLength = 0; + text *city; /* Variable to fetch city */ + ub4 cityLength = 0; + text *state; /* Variable to fetch state */ + ub4 stateLength = 0; + + OCIHandleAlloc (envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + if ((status = OCIStmtPrepare (stmthp, errhp, (text *)displaySql, + (ub4)strlen(displaySql), OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIStmtPrepare - Fail\n"); + checkerr (errhp, status); + } + + if (status = OCIDefineByPos(stmthp, &def1hp, errhp, (ub4)1, (dvoid *)0, + (ub4)0, SQLT_REF, (dvoid *)0, (ub2 *)0, (ub2 *)0, + OCI_DEFAULT) != OCI_SUCCESS) + { + printf("OCIDefineByPos - Failure \n"); + checkerr(errhp, status); + } + + if (status = OCIDefineByPos(stmthp, &def2hp, errhp, (ub4)2, (dvoid *)0, + (ub4)0, SQLT_REF, (dvoid *)0, (ub2 *)0, (ub2 *)0, + OCI_DEFAULT) != OCI_SUCCESS) + { + printf("OCIDefineByPos - Failure \n"); + checkerr(errhp, status); + } + + if (status = OCIDefineObject(def1hp, errhp, (OCIType *)NULL, + (dvoid **)&s_ref, (ub4 *)0, (dvoid **)0, (ub4)0) != OCI_SUCCESS) + { + printf("OCIDefineObject - Failure \n"); + checkerr(errhp, status); + } + + if (status = OCIDefineObject(def2hp, errhp, (OCIType *)NULL, + (dvoid **)&ref, (ub4 *)0, (dvoid **)0, (ub4)0) != OCI_SUCCESS) + { + printf("OCIDefineObject - Failure \n"); + checkerr(errhp, status); + } + + printf ("Executing the statement:%s\n", displaySql); + if (status = OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT ) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure \n"); + checkerr (errhp, status); + } + else + { + printf("OCIStmtExecute - Success\n"); + if (status = OCIObjectPin(envhp, errhp, ref, + (OCIComplexObject *)0, OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&obj) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + checkerr(errhp, status); + } + if (status = OCIObjectPin(envhp, errhp, s_ref, + (OCIComplexObject *)0, OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&s_obj) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + checkerr(errhp, status); + } + printf ("Col2 data\n"); + OCINumberToInt (errhp, &(s_obj->_super.hno), sizeUB4, + OCI_NUMBER_UNSIGNED, (dvoid *)&hno); + printf("HNO: %d\n", hno); + street = OCIStringPtr(envhp, s_obj->_super.street); + streetLength = OCIStringSize (envhp, s_obj->_super.street); + printf("STREET: %.*s\n", streetLength, street); + city = OCIStringPtr(envhp, s_obj->city); + cityLength = OCIStringSize (envhp, s_obj->city); + printf("CITY: %.*s\n", cityLength, city); + state = OCIStringPtr(envhp, s_obj->state); + stateLength = OCIStringSize (envhp, s_obj->state); + printf("STATE: %.*s\n", stateLength, state); + printf ("Col3 data\n"); + OCINumberToInt (errhp, &(obj->hno), sizeUB4, + OCI_NUMBER_UNSIGNED, (dvoid *)&hno); + printf("HNO: %d\n", hno); + street = OCIStringPtr(envhp, obj->street); + streetLength = OCIStringSize (envhp, obj->street); + printf("STREET: %.*s\n", streetLength, street); + } + OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT); +} /* end of displayFunction1() */ + +/* Function to display the contents of the table after updation*/ +static void displayFunction2 () +{ + OCIDefine *def1hp = (OCIDefine *)0; /* For vacation_home */ + OCIDefine *def2hp = (OCIDefine *)0; /* For first_home */ + OCIRef *s_ref = (OCIRef *)0; + OCIRef *ref = (OCIRef *)0; + cdemoin2_sec_address *s_obj = (cdemoin2_sec_address *)0; + cdemoin2_address *obj = (cdemoin2_address *)0; + ub4 subSize = 0; + sb4 size = 0; + + ub4 hno = 0; /* Variable to fetch hno */ + ub4 sizeUB4 = sizeof (ub4); + text *street; /* Variable to fetch street */ + ub4 streetLength = 0; + text *city; /* Variable to fetch city */ + ub4 cityLength = 0; + text *state; /* Variable to fetch state */ + ub4 stateLength = 0; + + OCIHandleAlloc (envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + if ((status = OCIStmtPrepare (stmthp, errhp, (text *)displaySql, + (ub4)strlen(displaySql), OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIStmtPrepare - Fail\n"); + checkerr (errhp, status); + } + + if (status = OCIDefineByPos(stmthp, &def1hp, errhp, (ub4)1, (dvoid *)0, + (ub4)0, SQLT_REF, (dvoid *)0, (ub2 *)0, (ub2 *)0, + OCI_DEFAULT) != OCI_SUCCESS) + { + printf("OCIDefineByPos - Failure \n"); + checkerr(errhp, status); + } + + if (status = OCIDefineByPos(stmthp, &def2hp, errhp, (ub4)2, (dvoid *)0, + (ub4)0, SQLT_REF, (dvoid *)0, (ub2 *)0, (ub2 *)0, + OCI_DEFAULT) != OCI_SUCCESS) + { + printf("OCIDefineByPos - Failure \n"); + checkerr(errhp, status); + } + + if (status = OCIDefineObject(def1hp, errhp, (OCIType *)NULL, + (dvoid **)&ref, (ub4 *)0, (dvoid **)0, (ub4)0) != OCI_SUCCESS) + { + printf("OCIDefineObject - Failure \n"); + checkerr(errhp, status); + } + + if (status = OCIDefineObject(def2hp, errhp, (OCIType *)NULL, + (dvoid **)&s_ref, (ub4 *)0, (dvoid **)0, (ub4)0) != OCI_SUCCESS) + { + printf("OCIDefineObject - Failure \n"); + checkerr(errhp, status); + } + + printf ("Executing the statement:%s\n", displaySql); + if (status = OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT ) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure \n"); + checkerr (errhp, status); + } + else + { + printf("OCIStmtExecute - Success\n"); + if (status = OCIObjectPin(envhp, errhp, ref, + (OCIComplexObject *)0, OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&obj) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + checkerr(errhp, status); + } + if (status = OCIObjectPin(envhp, errhp, s_ref, + (OCIComplexObject *)0, OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&s_obj) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + checkerr(errhp, status); + } + printf ("Col2 data\n"); + OCINumberToInt (errhp, &(obj->hno), sizeUB4, + OCI_NUMBER_UNSIGNED, (dvoid *)&hno); + printf("HNO: %d\n", hno); + street = OCIStringPtr(envhp, obj->street); + streetLength = OCIStringSize (envhp, obj->street); + printf("STREET: %.*s\n", streetLength, street); + printf ("Col3 data\n"); + OCINumberToInt (errhp, &(s_obj->_super.hno), sizeUB4, + OCI_NUMBER_UNSIGNED, (dvoid *)&hno); + printf("HNO: %d\n", hno); + street = OCIStringPtr(envhp, s_obj->_super.street); + streetLength = OCIStringSize (envhp, s_obj->_super.street); + printf("STREET: %.*s\n", streetLength, street); + city = OCIStringPtr(envhp, s_obj->city); + cityLength = OCIStringSize (envhp, s_obj->city); + printf("CITY: %.*s\n", cityLength, city); + state = OCIStringPtr(envhp, s_obj->state); + stateLength = OCIStringSize (envhp, s_obj->state); + printf("STATE: %.*s\n", stateLength, state); + } + OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT); +} /* end of displayFunction2() */ + +static void updateFunction(text *getRefSql, text *updateSql) +{ + OCIRef *ref = (OCIRef *)0; + OCIDefine *defhp = (OCIDefine *)0; + ub4 subSize = 0; + OCIBind *bindhp = (OCIBind *)0; + sb4 sizeRef = sizeof (OCIRef *); + OCIHandleAlloc (envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + if ((status = OCIStmtPrepare (stmthp, errhp, (text *)getRefSql, + (ub4)strlen(getRefSql), OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIStmtPrepare - Fail\n"); + checkerr (errhp, status); + } + if (( status = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_REF, + (OCIType *)0, (dvoid *)0, OCI_DURATION_DEFAULT, FALSE, + (dvoid **) &ref)) != OCI_SUCCESS) + { + printf ("OCIObjectNew - Failure\n"); + checkerr (errhp, status); + } + + if ((status = OCIDefineByPos(stmthp, &defhp, errhp, (ub4) 1, (dvoid *) 0, + (sb4) 0, SQLT_REF, (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIDefineByPos - Failure \n"); + checkerr (errhp, status); + } + + if ((status = OCIDefineObject(defhp, errhp, (OCIType *) 0, + (dvoid **) &ref, &subSize, (dvoid **) 0, (ub4 *) 0)) != OCI_SUCCESS) + { + printf ("OCIDefineObject - Failure \n"); + checkerr (errhp, status); + } + if (status = OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT ) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure \n"); + checkerr (errhp, status); + } + else + { + if ((status = OCIStmtPrepare (stmthp, errhp, (text *)updateSql, + (ub4)strlen(updateSql), OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIStmtPrepare - Fail\n"); + checkerr (errhp, status); + } + + if ((status = OCIBindByPos(stmthp, &bindhp, errhp, (ub4) 1, (dvoid *) 0, + sizeRef, SQLT_REF, (dvoid *) 0, (ub2 *)0, (ub2 *)0, (ub4)0, + (ub4 *)0, (ub4) OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIBindByPos - Failure \n"); + checkerr (errhp, status); + } + + if (status = OCIBindObject(bindhp, errhp, (OCIType *)0, (dvoid **) &ref, + (ub4 *) &subSize, (dvoid **)0 , (ub4 *) 0) != OCI_SUCCESS) + { + printf("OCIBindObject - Failure \n"); + checkerr(errhp, status); + } + printf ("Executing the statement:%s\n", updateSql); + if (status = OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT ) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure \n"); + checkerr (errhp, status); + } + else + { + printf("OCIStmtExecute - Success\n"); + } + } + OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT); +} /* end of updateFunction(text *, text *) */ + +/* Freeing the allocated handles */ +static void cleanup () +{ + OCISessionEnd (svchp, errhp, sesnhp, OCI_DEFAULT ); + OCIHandleFree((dvoid *) sesnhp, OCI_HTYPE_SESSION); + OCIServerDetach(svrhp, errhp, OCI_DEFAULT ); + OCIHandleFree((dvoid *) svrhp, OCI_HTYPE_SERVER); + OCIHandleFree((dvoid *) svchp, OCI_HTYPE_SVCCTX); + OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + return; +}/* End of cleanup() */ + +/* check for the errors */ +void checkerr (OCIError *err, sword status) +{ + text errbuf[514]; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS : + break; + case OCI_SUCCESS_WITH_INFO : + OCIErrorGet (err, 1, (text *)0, + (sb4 *)&errcode, errbuf, 514, + OCI_HTYPE_ERROR); + printf ("Warning %d : %.*s\n", errcode, 514, errbuf); + break; + case OCI_NO_DATA : + printf ("*** No Data Found *** \n"); + break; + case OCI_INVALID_HANDLE : + printf ("*** Invalid Handle *** \n"); + exit (-5); + case OCI_ERROR : + OCIErrorGet (err, 1, (text *)0, + (sb4 *)&errcode, errbuf, 514, + OCI_HTYPE_ERROR); + printf ("ERROR %d : %.*s\n", errcode, 514, errbuf); + break; + default : + printf ("*** Unknown Status *** \n"); + break; + } +} + diff --git a/cdemoin2.h b/cdemoin2.h new file mode 100644 index 0000000..a9ddcac --- /dev/null +++ b/cdemoin2.h @@ -0,0 +1,63 @@ +/* Copyright (c) Oracle Corporation 1995. All Rights Reserved. */ + +/* + NAME + cdemoin2 - Demo program to perform attribute substitutability. + + DESCRIPTION + This program demonstrates attribute substitutability, wherein a column + which is of REF to a supertype is substituted with a REF to a subtype. + All the data from the table are then displayed. + + NOTES + dependent files : + cdemoin2.c - Source file. + cdemoin2.sql - SQL File to be run before execution of the test. + cdemoin2.tsc - Optional, test script file. + + MODIFIED + rdwajan 08/11/00 Created +*/ + +#ifndef CDEMOIN2_ORACLE +# define CDEMOIN2_ORACLE + +#ifndef OCI_ORACLE +# include +#endif + +typedef OCIRef cdemoin2_sec_address_ref; +typedef OCIRef cdemoin2_address_ref; + +struct cdemoin2_address +{ + OCINumber hno; + OCIString * street; +}; +typedef struct cdemoin2_address cdemoin2_address; + +struct cdemoin2_address_ind +{ + OCIInd _atomic; + OCIInd hno; + OCIInd street; +}; +typedef struct cdemoin2_address_ind cdemoin2_address_ind; + +struct cdemoin2_sec_address +{ + cdemoin2_address _super; + OCIString * city; + OCIString * state; +}; +typedef struct cdemoin2_sec_address cdemoin2_sec_address; + +struct cdemoin2_sec_address_ind +{ + cdemoin2_address _super; + OCIInd city; + OCIInd state; +}; +typedef struct cdemoin2_sec_address_ind cdemoin2_sec_address_ind; + +#endif diff --git a/cdemoin2.sql b/cdemoin2.sql new file mode 100644 index 0000000..6498dc9 --- /dev/null +++ b/cdemoin2.sql @@ -0,0 +1,52 @@ +/* Copyright (c) Oracle Corporation 1995. All Rights Reserved. */ + +/* + NAME + cdemoin2 - Demo program to perform attribute substitutability. + + DESCRIPTION + This program demonstrates attribute substitutability, wherein a column + which is of REF to a supertype is substituted with a REF to a subtype. + All the data from the table are then displayed. + + MODIFIED + rdwajan 08/03/00 Created + +*/ +CONNECT scott/tiger; +DROP TABLE cdemoin2_person_tab; +DROP TABLE cdemoin2_address_tab; +DROP TABLE cdemoin2_sec_address_tab; +DROP TYPE cdemoin2_sec_address; +DROP TYPE cdemoin2_address; + +CREATE TYPE cdemoin2_address AS OBJECT +( hno NUMBER, street VARCHAR2(20) ) NOT FINAL; +/ + +CREATE TYPE cdemoin2_sec_address UNDER cdemoin2_address +( city VARCHAR2(20), state CHAR(20) ); +/ +show errors; +CREATE TABLE cdemoin2_sec_address_tab OF cdemoin2_sec_address; +INSERT INTO cdemoin2_sec_address_tab values +(cdemoin2_sec_address(100, 'MAIN STREET', 'NEW YORK', 'NY')); +INSERT INTO cdemoin2_sec_address_tab values +(cdemoin2_sec_address(200, 'BROADWAY BLVD', 'CHICAGO', 'IL')); + +CREATE TABLE cdemoin2_address_tab OF cdemoin2_address; +INSERT INTO cdemoin2_address_tab values (cdemoin2_address(300, 'SHORE RD')); +INSERT INTO cdemoin2_address_tab values (cdemoin2_address(400, 'ESCONDIDO RD')); + +CREATE TABLE cdemoin2_person_tab +( ssn NUMBER, + vacation_home REF cdemoin2_sec_address, + first_home REF cdemoin2_address +); + +INSERT INTO cdemoin2_person_tab (ssn, vacation_home, first_home) VALUES +(999, (SELECT REF(a) FROM cdemoin2_sec_address_tab a WHERE a.hno = 100), +(SELECT REF(a) FROM cdemoin2_address_tab a WHERE a.hno = 300)); + +COMMIT; + diff --git a/cdemoin3.c b/cdemoin3.c new file mode 100644 index 0000000..b7f58a2 --- /dev/null +++ b/cdemoin3.c @@ -0,0 +1,675 @@ +/* Copyright (c) 1996, 2001, Oracle Corporation. All rights reserved. */ + +/* + + NAME + cdemoin3 - Demo program to describe an object, inherited types, object + table and subtable. + + DESCRIPTION + The program describes an object, an inherited object, methods of an + object, object table and a subtable and prints out the new type level + attributes, the new method level attributes and the new table level + attributes. + + NOTES + dependent files : + cdemoin3.h - Header file + cdemoin3.sql - SQL script to be run before execution + cdemoin3.tsc - test script (optional) + + Program Notes : + + MODIFIED (MM/DD/YY) + rdwajan 08/07/00 - Creation +*/ + +#include "cdemoin3.h" + +static OCIError *errhp = (OCIError *)0; +static OCIEnv *envhp = (OCIEnv *)0; +static OCIServer *svrhp = (OCIServer *)0; +static OCISession *sesnhp = (OCISession *)0; +static OCISvcCtx *svchp = (OCISvcCtx *)0; +static OCIStmt *stmthp = (OCIStmt *)0; + +static text *database =(text *)""; +static text *username =(text *)"scott"; +static text *password =(text *)"tiger"; + +/* Free the allocated handles */ +static void cleanup (void); + +/* Check for errors */ +void checkerr (OCIError *errhp, sword status); + +/* describe a given object */ +void describe_obj ( OCIEnv *envhp, OCISvcCtx *svchp, OCIStmt *stmthp, +OCIError *errhp, text *obj); + +/* describe an object table */ +void describe_tab ( OCIEnv *envhp, OCISvcCtx *svchp, OCIStmt *stmthp, +OCIError *errhp, text *table); + +/* Function to describe the methods of an object */ +void desc_obj_meth (OCIParam *parmhp); + +/* print the type of the enumerated type */ +void printtypename (ub2 type, text *name, ub2 typeSize, ub2 typenameSize); + +sword status = 0; + +int main (void) +{ + printf("cdemoin3 - Demo program for describing objects \n"); + /* Initializing the environment in the Object mode*/ + OCIEnvCreate (&envhp, OCI_OBJECT, (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)()) 0, (dvoid (*)()) 0, 0, (dvoid *)0); + + OCIHandleAlloc (envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, (size_t)0, + (dvoid **)0); + + OCIHandleAlloc(envhp, (dvoid **)&svrhp, OCI_HTYPE_SERVER, (size_t)0, + (dvoid **)0); + + status = OCIServerAttach(svrhp, errhp, (text *)database, + (sb4)strlen((char *)database), OCI_DEFAULT); + + if (status != OCI_SUCCESS) + { + printf("OCIServerAttach failed \n"); + checkerr(errhp, status); + } + else + printf("OCIServerAttach - Success \n"); + + OCIHandleAlloc(envhp, (dvoid **)&svchp, OCI_HTYPE_SVCCTX, (size_t)0, + (dvoid **)0); + OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, (dvoid *)svrhp, (ub4)0, OCI_ATTR_SERVER, + errhp); + + OCIHandleAlloc(envhp, (dvoid **)&sesnhp, OCI_HTYPE_SESSION, (size_t)0, + (dvoid **)0); + + OCIAttrSet(sesnhp, OCI_HTYPE_SESSION, (dvoid *)username, + (ub4)strlen((char *)username), OCI_ATTR_USERNAME, errhp); + + OCIAttrSet(sesnhp, OCI_HTYPE_SESSION, (dvoid*)password, + (ub4)strlen((char *)password), OCI_ATTR_PASSWORD, errhp); + + printf("Connecting as %s/%s@%s\n",username,password,database); + + status = OCISessionBegin(svchp, errhp, sesnhp, OCI_CRED_RDBMS, OCI_DEFAULT); + if (status != OCI_SUCCESS) + { + printf("Connection failed \n"); + checkerr(errhp, status); + } + else + printf("Connection - Success \n"); + + OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, sesnhp, (ub4)0, OCI_ATTR_SESSION, errhp); + + /* describing the object I_PERSON */ + describe_obj (envhp, svchp, stmthp, errhp, (text *)"I_PERSON"); + + /* describing the object I_STUDENT */ + describe_obj (envhp, svchp, stmthp, errhp, (text *)"I_STUDENT"); + + /* describing the object I_EMPLOYEE */ + describe_obj (envhp, svchp, stmthp, errhp, (text *)"I_EMPLOYEE"); + + /* describing the table I_PERSON_TAB */ + describe_tab ( envhp, svchp, stmthp, errhp, (text*)"I_PERSON_TAB"); + + /* describing the table I_STUDENT_TAB */ + describe_tab ( envhp, svchp, stmthp, errhp, (text*)"I_STUDENT_TAB"); + + /* describing the table I_EMPLOYEE_TAB */ + describe_tab ( envhp, svchp, stmthp, errhp, (text*)"I_EMPLOYEE_TAB"); + + /* describing the table I_PEOPLE_TAB1 */ + describe_tab ( envhp, svchp, stmthp, errhp, (text*)"I_PEOPLE_TAB1"); + + /* describing the table I_PEOPLE_TAB2 */ + describe_tab ( envhp, svchp, stmthp, errhp, (text*)"I_PEOPLE_TAB2"); + + /* describing the storage table of nested table I_PEOPLE_TAB3_NT_TAB */ + describe_tab ( envhp, svchp, stmthp, errhp, (text*)"I_PEOPLE_TAB3_NT_TAB"); + + /* describing the table I_PEOPLE_TAB3 */ + describe_tab ( envhp, svchp, stmthp, errhp, (text*)"I_PEOPLE_TAB3"); + + /* Free the allocated handles */ + cleanup(); + + printf("cdemoin3 - Done\n"); +} /* End of main() */ + +/* describing an object */ +void describe_obj ( OCIEnv *envhp, OCISvcCtx *svchp, OCIStmt *stmthp, +OCIError *errhp, text *obj ) +{ + ub4 objlen = strlen((char *)obj); + OCIParam *parmhp = (OCIParam *)0; /* parameter handle */ + OCIParam *attrlshp = (OCIParam *)0; /* list of attributes */ + OCIParam *attrhp = (OCIParam *)0; /* attributes handle */ + OCIDescribe *deschp = (OCIDescribe *)0; + + ub4 in = 0; /* counter in the loop */ + ub2 numattr = 0; /* To store the number of attributes */ + + ub2 type = 0; /* To get the type of the attribute */ + text *typename; /* To get the typename of the attribute */ + ub2 typeSize = 0; /* To get column size */ + ub4 typenameSize = 0; + ub4 ntynameSize = 0; + text *ntyname = (text *)0; /* To get the typename of the attribute if the + type is SQLT_NTY */ + ub4 sizeSuper = 0; /* To get the size of the Supertype */ + ub4 sizeSchm = 0; /* To get the size of the Supertype schema */ + + ub1 isFinal = 0; /* To check if type is final */ + ub1 isInst = 0; /* To check if type is instantiable */ + ub1 isSubtype = 0; /* To check if type is a subtype */ + ub1 isInhattr = 0; /* To check if attribute is inherited */ + ub4 local_attr = 0; /* To get the number of local attributes */ + ub4 local_meth = 0; /* To get the number of local methods */ + text *superType; /* To get the name of the supertype */ + text *superSchema; /* To get the name of the schema of the supertype */ + + printf ("Describing object %s \n", obj); + + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&deschp, + (ub4)OCI_HTYPE_DESCRIBE, (size_t)0, (dvoid **)0); + + /* get the describe handle for the object */ + if ((status = OCIDescribeAny(svchp, errhp, (dvoid *)obj, objlen, + OCI_OTYPE_NAME, 0, OCI_PTYPE_TYPE, deschp)) != OCI_SUCCESS ) + { + printf ("Describe - Fail\n"); + checkerr (errhp, status); + } + else + printf ("Describe - Success \n"); + + /* get the parameter handle */ + if ((status = OCIAttrGet(deschp, OCI_HTYPE_DESCRIBE, &parmhp, 0, + OCI_ATTR_PARAM, errhp)) != OCI_SUCCESS) + { + printf ("Getting parameter Handle - Fail \n"); + checkerr (errhp, status); + } + + /* get the number of attributes in the object */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &numattr, 0, + OCI_ATTR_NUM_TYPE_ATTRS, errhp)) != OCI_SUCCESS) + { + printf ("Getting the number of attributes - Fail \n"); + checkerr (errhp, status); + } + printf ("Number of attributes = %d \n", numattr); + + /* get whether the type is final*/ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &isFinal, 0, + OCI_ATTR_IS_FINAL_TYPE, errhp)) != OCI_SUCCESS) + { + printf ("Getting whether type is final - Fail \n"); + checkerr (errhp, status); + } + if (isFinal) + printf ("Type is Final\n"); + else + printf ("Type is not Final\n"); + + /* get whether the type is instantiable*/ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &isInst, 0, + OCI_ATTR_IS_INSTANTIABLE_TYPE, errhp)) != OCI_SUCCESS) + { + printf ("Getting whether type is instantiable - Fail \n"); + checkerr (errhp, status); + } + if (isInst) + printf ("Type is instantiable\n"); + else + printf ("Type is not instantiable\n"); + + /* get whether the type is subtype*/ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &isSubtype, 0, + OCI_ATTR_IS_SUBTYPE, errhp)) != OCI_SUCCESS) + { + printf ("Getting whether type is a subtype - Fail \n"); + checkerr (errhp, status); + } + if (isSubtype) + printf ("Type is a subtype\n"); + else + printf ("Type is not a subtype\n"); + + if (isSubtype) + { + /* get the name of the schema of the supertype */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, (dvoid *)&superSchema, + (dvoid *)&sizeSchm, OCI_ATTR_SUPERTYPE_SCHEMA_NAME, errhp)) + != OCI_SUCCESS) + { + printf ("Getting the name of the schema of supertype - Fail \n"); + checkerr (errhp, status); + } + printf ("Name of schema of supertype: %.*s\n", sizeSchm, superSchema); + + /* get the name of the supertype */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, (dvoid *)&superType, + (dvoid *)&sizeSuper, OCI_ATTR_SUPERTYPE_NAME, errhp)) != OCI_SUCCESS) + { + printf ("Getting the name of the supertype - Fail \n"); + checkerr (errhp, status); + } + printf ("Name of supertype: %.*s\n", sizeSuper, superType); + } + + /* get handle for parameter list */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &attrlshp, 0, + OCI_ATTR_LIST_TYPE_ATTRS, errhp)) != OCI_SUCCESS) + { + printf ("Getting attributes list Handle - Fail \n"); + checkerr (errhp, status); + } + + for (in = 1; in <= numattr; ++in) + { + if (status = OCIParamGet (attrlshp, OCI_DTYPE_PARAM, errhp, + (dvoid **)&attrhp, in) != OCI_SUCCESS) + { + printf ("Getting parameter Handle for the attr - Failed \n"); + checkerr (errhp, status); + } + + if (status = OCIAttrGet ((dvoid *)attrhp, OCI_DTYPE_PARAM, &type, + 0, OCI_ATTR_DATA_TYPE, errhp) != OCI_SUCCESS) + { + printf ("Getting column type - Failed \n"); + checkerr (errhp, status); + } + + if (status = OCIAttrGet ((dvoid *)attrhp, OCI_DTYPE_PARAM, + &typeSize, 0, OCI_ATTR_DATA_SIZE, errhp) != OCI_SUCCESS) + { + printf ("Getting column size - Failed \n"); + checkerr (errhp, status); + } + +#ifdef CDEMOIN3_LATER + /* check if the attribute is inherited */ + if (status = OCIAttrGet ((dvoid *)attrhp, OCI_DTYPE_PARAM, + &isInhattr, 0, OCI_ATTR_IS_INHERITED_ATTR, errhp) != OCI_SUCCESS) + { + printf ("Checking if attribute is inherited - Failed \n"); + checkerr (errhp, status); + } + else + { + if (isInhattr) + printf ("Attribute is inherited \n"); + else + printf ("Attribute is not inherited\n"); + } +#endif /* #ifdef CDEMOIN3_LATER */ + + if (status = OCIAttrGet (attrhp, OCI_DTYPE_PARAM, &typename, + (ub4 *)&typenameSize, OCI_ATTR_NAME, errhp) != OCI_SUCCESS) + { + printf ("Getting attribute name - Failed \n"); + checkerr (errhp, status); + } + else + { + if (type == SQLT_NTY) + { + if (status = OCIAttrGet ((dvoid *)attrhp, OCI_DTYPE_PARAM, &ntyname, + (ub4 *)&ntynameSize, OCI_ATTR_TYPE_NAME, errhp) != OCI_SUCCESS) + { + printf ("Getting type name - Failed \n"); + checkerr (errhp, status); + } + else + { + printf ("%.*s - Named Data Type :", typenameSize, typename); + printf ("%.*s\n", ntynameSize, ntyname); + } + } + else + printtypename (type, typename, typeSize ,typenameSize); + } + } /* end of for loop */ + + /* Calling function to describe the object methods */ + desc_obj_meth(parmhp); +} /* end of describe_obj () */ + +/* Function to describe the methods of an object */ +void desc_obj_meth(OCIParam *parmhp) +{ + OCIParam *methlshp; /* list of methods */ + OCIParam *methhp; /* methods handle */ + + ub4 in = 0; /* Loop counter */ + ub2 nummeth = 111; /* To get the number of methods */ + + ub1 isFinal = 0; /* To check if method is final */ + ub1 isInst = 0; /* To check if method is instantiable */ + ub1 isInhmeth = 0; /* To check if method is inherited */ + + ub4 methSize = 0; /* To get the size of the method name */ + text *methname; /* To get the method name */ + + /* get the number of methods in the object */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &nummeth, 0, + OCI_ATTR_NUM_TYPE_METHODS, errhp)) != OCI_SUCCESS) + { + printf ("Getting the number of methods - Fail \n"); + checkerr (errhp, status); + } + printf ("Number of methods = %d \n", nummeth); + + if (nummeth > 0) + { + /* get handle for parameter list */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &methlshp, 0, + OCI_ATTR_LIST_TYPE_METHODS, errhp)) != OCI_SUCCESS) + { + printf ("Getting methods list Handle - Fail \n"); + checkerr (errhp, status); + } + + for (in = 1; in <= nummeth; ++in) + { + if (status = OCIParamGet (methlshp, OCI_DTYPE_PARAM, errhp, + (dvoid **)&methhp, in) != OCI_SUCCESS) + { + printf ("Getting parameter Handle for the method - Failed \n"); + checkerr (errhp, status); + } + + if (status = OCIAttrGet ((dvoid *)methhp, OCI_DTYPE_PARAM, (dvoid *) + &methname, (ub4 *)&methSize, OCI_ATTR_NAME, errhp) != OCI_SUCCESS) + { + printf ("Getting method name - Failed \n"); + checkerr (errhp, status); + } + else + { + printf ("Method name:%.*s\n", methSize, methname); + } + + /* get whether the method is final*/ + if ((status = OCIAttrGet(methhp, OCI_DTYPE_PARAM, &isFinal, 0, + OCI_ATTR_IS_FINAL_METHOD, errhp)) != OCI_SUCCESS) + { + printf ("Getting whether method is final - Fail \n"); + checkerr (errhp, status); + } + if (isFinal) + printf ("Method is Final\n"); + else + printf ("Method is not Final\n"); + + /* get whether the method is instantiable*/ + if ( (status = OCIAttrGet(methhp, OCI_DTYPE_PARAM, &isInst, 0, + OCI_ATTR_IS_INSTANTIABLE_METHOD, errhp)) != OCI_SUCCESS) + { + printf ("Getting whether method is instantiable - Fail \n"); + checkerr (errhp, status); + } + if (isInst) + printf ("Method is instantiable\n"); + else + printf ("Method is not instantiable\n"); + + /* get whether the method is overriding*/ + if ( (status = OCIAttrGet(methhp, OCI_DTYPE_PARAM, &isInst, 0, + OCI_ATTR_IS_OVERRIDING_METHOD, errhp)) != OCI_SUCCESS) + { + printf ("Getting whether method is overriding - Fail \n"); + checkerr (errhp, status); + } + if (isInst) + printf ("Method is overriding\n"); + else + printf ("Method is not overriding\n"); +#ifdef CDEMOIN3_LATER + /* check if the method is inherited */ + if (status = OCIAttrGet ((dvoid *)methhp, OCI_DTYPE_PARAM, + &isInhmeth, 0, OCI_ATTR_IS_INHERITED_METHOD, errhp) != OCI_SUCCESS) + { + printf ("Checking if method is inherited - Failed \n"); + checkerr (errhp, status); + } + else + { + if (isInhmeth) + printf ("Method is inherited \n"); + else + printf ("Method is not inherited\n"); + } +#endif /* #ifdef CDEMOIN3_LATER */ + } /* end of for loop*/ + } +} /* End of desc_obj_meth (OCIParam *) */ + +/* describe the given table */ +void describe_tab ( OCIEnv *envhp, OCISvcCtx *svchp, OCIStmt *stmthp, +OCIError *errhp, text *table) +{ + ub4 tablen = strlen(table); + OCIParam *parmhp; /* parameter handle */ + OCIParam *agrlshp; /* list of args */ + OCIParam *arg; /* argument handle */ + OCIDescribe *deschp = (OCIDescribe *)0; + + ub4 in = 0; /* Loop counter */ + ub2 numcol = 111; /* To get the number of columns */ + + ub2 type = 111; /* To get the datatype */ + text *typename; /* To get the attribute name */ + ub2 typeSize = 111; + + ub4 len = 0; /*typename length */ + ub1 isSubtable = 0; /* To check if the table is a subtable */ + text superSchema[25]; /* to get the schema name of the super type */ + text superTable[25]; /* to get the name of the super table */ + + if (strcmp(table,(text *)"I_PEOPLE_TAB3_NT_TAB") ==0 ) + printf ("Describing the storage table of a nested table %s\n", table); + else + printf ("Describing the table %s \n", table); + + + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&deschp, + (ub4)OCI_HTYPE_DESCRIBE, (size_t)0, (dvoid **)0); + + /* get the describe handle for the table */ + if ((status = OCIDescribeAny(svchp, errhp, (dvoid *)table, tablen, + OCI_OTYPE_NAME, 0, OCI_PTYPE_TABLE, deschp)) != OCI_SUCCESS ) + checkerr (errhp, status); + else + printf ("Describe - Success \n"); + + /* get the parameter handle */ + if ((status = OCIAttrGet(deschp, OCI_HTYPE_DESCRIBE, &parmhp, 0, + OCI_ATTR_PARAM, errhp)) != OCI_SUCCESS) + checkerr (errhp, status); + + /* get the number of columns in the table */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &numcol, 0, + OCI_ATTR_NUM_COLS, errhp)) != OCI_SUCCESS) + checkerr (errhp, status); + + printf ("Number of Columns:%d \n", numcol); + +#ifdef CDEMOIN3_LATER + /* get whether the table is subtable*/ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &isSubtable, 0, + OCI_ATTR_IS_SUBOBJECT, errhp)) != OCI_SUCCESS) + { + printf ("Getting whether table is a subtable - Fail \n"); + checkerr (errhp, status); + } + if (isSubtable) + printf ("Table is a subtable\n"); + else + printf ("Table is not a subtable\n"); + + /* get the name of the schema of the supertable */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, (dvoid *)superSchema, 0, + OCI_ATTR_SUPEROBJECT_SCHEMA_NAME, errhp)) != OCI_SUCCESS) + { + printf ("Getting the name of the schema of supertable - Fail \n"); + checkerr (errhp, status); + } + printf ("Name of schema of supertable: %s\n", superSchema); + + /* get the name of the supertable */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, (dvoid *)superTable, 0, + OCI_ATTR_SUPEROBJECT_NAME, errhp)) != OCI_SUCCESS) + { + printf ("Getting the name of the supertable - Fail \n"); + checkerr (errhp, status); + } + printf ("Name of supertable: %s\n", superTable); +#endif /* #ifdef CDEMOIN3_LATER */ + + /* get handle for parameter list */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &agrlshp, 0, + OCI_ATTR_LIST_COLUMNS, errhp)) != OCI_SUCCESS) + checkerr (errhp, status); + for (in = 1; in <= numcol; ++in) + { + if (status = OCIParamGet (agrlshp, OCI_DTYPE_PARAM, errhp, + (dvoid **)&arg, in) != OCI_SUCCESS) + { + printf ("Getting parameter Handle for the arguments "); + printf ("- Failed \n"); + checkerr (errhp, status); + } + + if (status = OCIAttrGet ((dvoid *)arg, OCI_DTYPE_PARAM, &type, + 0, OCI_ATTR_DATA_TYPE, errhp) != OCI_SUCCESS) + { + printf ("Getting column type - Failed \n"); + checkerr (errhp, status); + } + + if (status = OCIAttrGet ((dvoid *)arg, OCI_DTYPE_PARAM, + &typeSize, 0, OCI_ATTR_DATA_SIZE, errhp) != OCI_SUCCESS) + { + printf ("Getting column type - Failed \n"); + checkerr (errhp, status); + } + + if (status = OCIAttrGet (arg, OCI_DTYPE_PARAM, &typename, (ub4 *)&len, + OCI_ATTR_NAME, errhp) != OCI_SUCCESS) + { + printf ("Getting type name - Failed \n"); + checkerr (errhp, status); + } + else + printtypename (type, typename, typeSize, len); + } /* end for loop */ +} /* end of describe_tab () */ + +/* printing typenames for given typecodes */ +void printtypename (ub2 type, text *name, ub2 typeSize, ub2 typenameSize) +{ + printf ("%.*s:", typenameSize, name); + switch (type) + { + case SQLT_CHR: printf ("VARCHAR2"); + break; + case SQLT_AFC: printf ("CHAR"); + break; + case SQLT_DAT: printf ("DATE"); + break; + case SQLT_INT: printf ("SIGNED INTEGER"); + break; + case SQLT_UIN: printf ("UNSIGNED INTEGER"); + break; + case SQLT_FLT: printf ("REAL"); + break; + case SQLT_PDN: printf ("PACKED DECIMAL"); + break; + case SQLT_BIN: printf ("BINARY DATA"); + break; + case SQLT_NUM: printf ("NUMBER"); + break; + case SQLT_BLOB : printf ("BLOB"); + break; + case SQLT_CLOB : printf ("CLOB"); + break; + case SQLT_FILE : printf ("BFILE"); + break; + case SQLT_NTY : printf ("NAMED DATA TYPE"); + break; + case SQLT_REF : printf ("REF to a Named Data Type"); + break; + default : printf ("*** UNKNOWN *** "); + break; + } + printf ("(%3d) \n", typeSize); +} /* end of printtypebyname () */ + + +/* cleaning up the allocated handles */ +void cleanup () +{ + if (stmthp) + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + if (svrhp) + (void) OCIServerDetach( svrhp, errhp, OCI_DEFAULT ); + if (svrhp) + checkerr(errhp, OCIHandleFree((dvoid *) svrhp, OCI_HTYPE_SERVER)); + if (sesnhp) + { + OCISessionEnd (svchp, errhp, sesnhp, OCI_DEFAULT ); + OCIHandleFree((dvoid *) sesnhp, OCI_HTYPE_SESSION); + } + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, OCI_HTYPE_SVCCTX); + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + return; +} /* end of cleanup () */ + +/* check for the errors */ +void checkerr (OCIError *err, sword status) +{ + text errbuf[514]; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS : + break; + case OCI_SUCCESS_WITH_INFO : + OCIErrorGet (err, 1, (text *)0, + (sb4 *)&errcode, errbuf, 514, + OCI_HTYPE_ERROR); + printf ("Warning %d : %.*s\n", errcode, 514, errbuf); + break; + case OCI_NO_DATA : + printf ("*** No Data Found *** \n"); + break; + case OCI_INVALID_HANDLE : + printf ("*** Invalid Handle *** \n"); + exit (-5); + case OCI_ERROR : + OCIErrorGet (err, 1, (text *)0, + (sb4 *)&errcode, errbuf, 514, + OCI_HTYPE_ERROR); + printf ("ERROR %d : %.*s\n", errcode, 514, errbuf); + break; + default : + printf ("*** Unknown Status *** \n"); + break; + } +} diff --git a/cdemoin3.h b/cdemoin3.h new file mode 100644 index 0000000..02866cf --- /dev/null +++ b/cdemoin3.h @@ -0,0 +1,31 @@ +/* Copyright (c) Oracle Corporation 1995. All Rights Reserved. */ + +/* + NAME + cdemoin3 - Demo program to describe an object, inherited types, object + table and subtable. + + DESCRIPTION + This program describes an object, an inherited object, methods of an + object, object table and a subtable and prints out the new type level + attributes, the new method level attributes and the new table level + attributes. + + + NOTES + dependent files : + cdemoin3.c - Source file. + cdemoin3.sql - SQL File to be run before execution of the test. + cdemoin3.tsc - Optional, test script file. + + MODIFIED + rdwajan 08/07/00 Created +*/ + +#ifndef CDEMOIN3_ORACLE +# define CDEMOIN3_ORACLE + +#ifndef OCI_ORACLE +# include +#endif +#endif diff --git a/cdemoin3.sql b/cdemoin3.sql new file mode 100644 index 0000000..f649e86 --- /dev/null +++ b/cdemoin3.sql @@ -0,0 +1,84 @@ +/* Copyright (c) Oracle Corporation 1995. All Rights Reserved. */ + +/* + NAME + cdemoin3 - Demo program to describe an object, inherited types, object + table and subtable. + + DESCRIPTION + This program describes an object, an inherited object, methods of an + object, object table and a subtable and prints out the new type level + attributes, the new method level attributes and the new table level + attributes. + + + NOTES + + MODIFIED + rdwajan 08/07/00 Created + +*/ +SET SERVEROUTPUT ON +connect scott/tiger; + +DROP TABLE i_people_tab3; +DROP TABLE i_people_tab2; +DROP TABLE i_people_tab1; +DROP TABLE i_employee_tab; +DROP TABLE i_student_tab; +DROP TABLE i_person_tab; +DROP TYPE i_employee; +DROP TYPE i_student; +DROP TYPE i_person; +DROP TYPE i_address_nest; +DROP TYPE i_address_arr; +DROP TYPE i_address; + +CREATE TYPE i_address AS OBJECT +( hno NUMBER, street VARCHAR2(10) + , MEMBER FUNCTION i_address_fun(arg1 NUMBER) RETURN NUMBER +); +/ + +CREATE TYPE i_address_arr AS VARRAY(3) OF REF i_address; +/ + +CREATE TYPE i_address_nest AS TABLE OF i_address; +/ + +CREATE TYPE i_person AS OBJECT +( ssn NUMBER, adrs i_address + , + NOT INSTANTIABLE + MEMBER PROCEDURE i_person_proc(arg1 NUMBER) +) NOT INSTANTIABLE NOT FINAL; +/ + +CREATE TYPE i_student UNDER i_person +( stud_id NUMBER, stud_add i_address_arr , +OVERRIDING +MEMBER PROCEDURE i_person_proc(arg1 NUMBER) +) NOT FINAL NOT INSTANTIABLE; +/ + +CREATE TYPE i_employee UNDER i_person +( emp_id NUMBER, emp_name VARCHAR2(10) , + FINAL + MEMBER PROCEDURE i_employee_proc(arg1 NUMBER) +) NOT FINAL NOT INSTANTIABLE; +/ + +CREATE TABLE i_person_tab OF i_person; + +CREATE TABLE i_student_tab OF i_student; + +CREATE TABLE i_employee_tab OF i_employee; + +CREATE TABLE i_people_tab1 (region varchar2(10), minister REF i_person); + +CREATE TABLE i_people_tab2 of i_address; + +CREATE TABLE i_people_tab3 (add_col i_address_nest) NESTED TABLE add_col STORE AS +i_people_tab3_nt_tab; + +COMMIT; diff --git a/cdemol2l.c b/cdemol2l.c new file mode 100644 index 0000000..526d16c --- /dev/null +++ b/cdemol2l.c @@ -0,0 +1,1283 @@ +/* Copyright (c) 2001, 2005, Oracle. All rights reserved. */ + +/* + + NAME + cdemol2l.c - OCI demo program for accessing LOBs using LONG API. + + DESCRIPTION + An example program which creates two tables + PERSON_1 (ssn NUMBER, resume LONG), + PERSON_2 (ssn NUMBER, photo LONG RAW). + A series of operations using LONG API: + simple insert/select, piecewise insert/select with polling, + piecewise insert/select with callback, array insert/select + are performed on the two tables respectively. + Then the tables are altered to + PERSON_1 (ssn NUMBER, resume CLOB), + PERSON_2 (ssn NUMBER, photo BLOB). + The same series of operations are performed on altered tables + and the same results are obtained. + + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + + + MODIFIED (MM/DD/YY) + aliu 02/01/05 - add order by in array select stmt + jchai 07/27/04 - add order by in select stmt + ani 04/30/01 - Merged ani_ocidemo + ani 04/24/01 - Creation + +*/ + +#include +#include +#include +#include + +#define DATA_SIZE 5000 +#define PIECE_SIZE 1000 +#define MAXCOLS 2 +#define MAXROWS 10 +#define NPIECE DATA_SIZE/PIECE_SIZE +#define MAX_IN_ROWS 10 + +typedef struct cdemol2lctx +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCISvcCtx *svchp; + OCIError *errhp; + OCISession *authp; + OCIStmt *stmthp; +} cdemol2lctx; + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +static text *username = (text *) "scott"; +static text *password = (text *) "tiger"; + +/*global variable for PIECEWISE operations with CALLBACK*/ +static text nextpiece[DATA_SIZE]; +static ub1 nextpiece2[DATA_SIZE]; +static ub4 len = DATA_SIZE; +static sb2 ind = 0; +static ub2 rc = 0; +static boolean glGetInd = 0; /* global var to control return of ind */ +static boolean glGetRc = 0; /* global var to control return of rc */ +static int column = 1; +static char in1[DATA_SIZE]; +static ub1 in2[DATA_SIZE]; + + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ +static void initialize(cdemol2lctx *ctxptr); +static void cleanup(cdemol2lctx *ctxptr); +static void checkprint(cdemol2lctx *ctxptr, sword status, ub4 nrows); +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void sql_stmt_execute(/*_ cdemol2lctx *ctxptx, text *sql_stmt _*/); +static void sql_exec_insert(/*_ cdemol2lctx *ctxptx _*/); +static void insert_piecewise_polling(/*_ cdemol2lctx *ctxptx _*/); +static void insert_piecewise_callback(/*_ cdemol2lctx *ctxptx _*/); +static sb4 cbf_in_data(/*_ dvoid *ctxp, OCIBind *bindp, ub4 iter, + ub4 index, dvoid **bufpp, ub4 *alenpp, + ub1 *piecep, dvoid **indpp _*/); +static void set_piece(/*_ ub1 *piece _*/); +static void sql_array_insert(/*_ cdemol2lctx *ctxptx _*/); +static void sql_exec_select(/*_ cdemol2lctx *ctxptx _*/); +static void select_piecewise_polling(/*_ cdemol2lctx *ctxptx _*/); +static void select_piecewise_callback(/*_ cdemol2lctx *ctxptx _*/); +static void sql_array_select(/*_ cdemol2lctx *ctxptx _*/); +static sb4 cdf_fetch_buffer(/*_ dvoid *ctxp, OCIDefine *defnp, ub4 iter, + dvoid **bufpp, ub4 **alen, ub1 *piecep, + dvoid **indp, ub2 **rcpp _*/); +int main(/*_ int argc, char *argv[] _*/); + + +int main(argc, argv) +int argc; +char *argv[]; +{ + cdemol2lctx ctx; + text *cretab_stmt1 = (text *)"CREATE TABLE PERSON_1 (SSN NUMBER, \ + RESUME LONG)"; + text *cretab_stmt2 = (text *)"CREATE TABLE PERSON_2 (SSN NUMBER, \ + PHOTO LONG RAW)"; + text *alter_stmt1 = (text *)"ALTER TABLE person_1 modify resume CLOB"; + text *alter_stmt2 = (text *)"ALTER TABLE person_2 modify photo BLOB"; + text *drop_stmt1 = (text *)"DROP TABLE PERSON_1"; + text *drop_stmt2 = (text *)"DROP TABLE PERSON_2"; + + printf("\n ######## start DEMO program ############ \n"); + + initialize(&ctx); + + /* execute sql statement */ + printf("\nCREATING TABLE PERSON_1 ... \n"); + sql_stmt_execute(&ctx, cretab_stmt1); + printf("\nCREATING TABLE PERSON_2 ... \n"); + sql_stmt_execute(&ctx, cretab_stmt2); + + /*perform a series of INSERT/SELECT operations */ + sql_exec_insert(&ctx); /*simple insert using LONG api*/ + sql_exec_select(&ctx); /*simple select using LONG api*/ + + insert_piecewise_polling(&ctx); + select_piecewise_polling(&ctx); + + insert_piecewise_callback(&ctx); + select_piecewise_callback(&ctx); + + sql_array_insert(&ctx); + sql_array_select(&ctx); + + printf("\nALTERING TABLE PERSON_1 ... \n"); + sql_stmt_execute(&ctx, alter_stmt1); + printf("\nALTERING TABLE PERSON_2 ... \n"); + sql_stmt_execute(&ctx, alter_stmt2); + + /*perform the same series of operations again*/ + sql_exec_insert(&ctx); + sql_exec_select(&ctx); + + insert_piecewise_polling(&ctx); + select_piecewise_polling(&ctx); + + insert_piecewise_callback(&ctx); + select_piecewise_callback(&ctx); + + sql_array_insert(&ctx); + sql_array_select(&ctx); + + printf("\nDROPPING TABLE PERSON_1 ... \n"); + sql_stmt_execute(&ctx, drop_stmt1); + printf("\nDROPPING TABLE PERSON_2 ... \n"); + sql_stmt_execute(&ctx, drop_stmt2); + + /* clean things up before exhit */ + cleanup(&ctx); + + return 1; + +} /*end main*/ + + +/*execute a single SQL statement */ +void sql_stmt_execute(ctxptr, sql_stmt) +cdemol2lctx *ctxptr; +text *sql_stmt; +{ + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sql_stmt, (ub4) strlen((char *)sql_stmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); +} /* end of sql_stmt_execute() */ + + +/*perform simple insert using LONG API*/ +void sql_exec_insert(ctxptr) +cdemol2lctx *ctxptr; +{ + text *ins_stmt1 = (text *)"INSERT INTO PERSON_1 VALUES (:1, :2)"; + text *ins_stmt2 = (text *)"INSERT INTO PERSON_2 VALUES (:1, :2)"; + OCIBind *bndp1 = (OCIBind *) NULL; + OCIBind *bndp2 = (OCIBind *) NULL; + + sword ssn= 1, i; + char col2[DATA_SIZE]; + ub1 col3[DATA_SIZE]; + ub2 col2len=DATA_SIZE, col3len=DATA_SIZE; + + for(i=0;ierrhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt1, (ub4) strlen((char *)ins_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SIMPLE INSERT INTO PERSON_1... \n"); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, + (dvoid *) &ssn, (sb4) sizeof(ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, + (dvoid *) col2, (sb4) col2len, SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt2, (ub4) strlen((char *)ins_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SIMPLE INSERT INTO PERSON_2... \n"); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, + (dvoid *) &ssn, (sb4) sizeof(ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, + (dvoid *) col3, (sb4) col3len, SQLT_BIN, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + +} /* end sql_exe_insert() */ + + +/*perform simple select using LONG API */ +void sql_exec_select(ctxptr) +cdemol2lctx *ctxptr; +{ + text *sel_stmt1 = (text *)"SELECT * FROM PERSON_1 ORDER BY SSN"; + text *sel_stmt2 = (text *)"SELECT * FROM PERSON_2 ORDER BY SSN"; + OCIDefine *defnp1 = (OCIDefine *) NULL; + OCIDefine *defnp2 = (OCIDefine *) NULL; + + ub4 i; + sword ssn; + char col2[DATA_SIZE]; + ub1 col3[DATA_SIZE]; + ub2 col2len, col3len; + boolean bufok; + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt1, (ub4) strlen((char *)sel_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SIMPLE SELECT OF PERSON_1... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &ssn, + (sb4) sizeof(ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) col2, + (sb4) sizeof(col2), (ub2)SQLT_CHR, (dvoid *)0, + (ub2 *)&col2len, (ub2 *)0, (ub4)OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + printf("ssn = %d\n", ssn); + printf("col2len = %d\n", col2len); + + bufok = TRUE; + for (i = 0; i < col2len; i++) + if (col2[i] != 'A') + bufok = FALSE; + + if (bufok) + printf("SUCCESS: contents of col2 have expected value\n"); + else + printf("FAILURE: contents of col2 do not have expected value\n"); + + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt2, (ub4) strlen((char *)sel_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SIMPLE SELECT OF PERSON_2... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &ssn, + (sb4) sizeof(ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) col3, + (sb4) sizeof(col3), (ub2)SQLT_BIN, (dvoid *)0, + (ub2 *)&col3len, (ub2 *)0, (ub4)OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + printf("ssn = %d\n", ssn); + printf("col3len = %d\n", col3len); + + bufok = TRUE; + for (i = 0; i < col3len; i++) + if (col3[i] != 'B') + bufok = FALSE; + + if (bufok) + printf("SUCCESS: contents of col3 have expected value\n"); + else + printf("FAILURE: contents of col3 do not have expected value\n"); + +} /* end sql_exe_select() */ + + +/*perform piecewise insert with polling*/ +void insert_piecewise_polling(ctxptr) +cdemol2lctx *ctxptr; +{ + text *ins_stmt1 = (text *)"INSERT INTO PERSON_1 VALUES (:1, :2)"; + text *ins_stmt2 = (text *)"INSERT INTO PERSON_2 VALUES (:1, :2)"; + OCIBind *bndp1 = (OCIBind *) NULL; + OCIBind *bndp2 = (OCIBind *) NULL; + sword status, ssn= 2, i; + char col2[PIECE_SIZE]; + ub1 col3[PIECE_SIZE]; + ub1 piece; + ub4 alenp2 = PIECE_SIZE; + ub2 rcode2; + + for(i=0;ierrhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt1, (ub4) strlen((char *)ins_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING PIECEWISE INSERT INTO PERSON_1 WITH POLLING ... \n"); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, + (dvoid *) &ssn, (sb4) sizeof(ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, + (dvoid *) col2, (sb4) DATA_SIZE, SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC)); + + while (1) + { + status = OCIStmtExecute(ctxptr->svchp, ctxptr->stmthp, ctxptr->errhp, + (ub4) 1, (ub4) 0, (CONST OCISnapshot*) 0, + (OCISnapshot*) 0, (ub4) OCI_DEFAULT); + switch(status) + { + case OCI_NEED_DATA: + set_piece(&piece); + if (OCIStmtSetPieceInfo((dvoid *)bndp2, + (ub4)OCI_HTYPE_BIND,ctxptr->errhp, (dvoid *)col2, + &alenp2, piece, (dvoid *) 0, &rcode2)) + { + printf("ERROR: OCIStmtSetPieceInfo returned %d \n", status); + break; + } + status = OCI_NEED_DATA; + break; + case OCI_SUCCESS: + break; + default: + printf( "oci exec returned %d \n", status); + checkerr(ctxptr->errhp, status); + status = 0; + } + if (!status) break; + } + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt2, (ub4) strlen((char *)ins_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING PIECEWISE INSERT INTO PERSON_2 WITH POLLING ... \n"); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, + (dvoid *) &ssn, (sb4) sizeof(ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, + (dvoid *) col3, (sb4) DATA_SIZE, SQLT_BIN, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC)); + + while (1) + { + status = OCIStmtExecute(ctxptr->svchp, ctxptr->stmthp, ctxptr->errhp, + (ub4) 1, (ub4) 0, (CONST OCISnapshot*) 0, + (OCISnapshot*) 0, (ub4) OCI_DEFAULT); + switch(status) + { + case OCI_NEED_DATA: + set_piece(&piece); + if (OCIStmtSetPieceInfo((dvoid *)bndp2, + (ub4)OCI_HTYPE_BIND,ctxptr->errhp, (dvoid *)col3, + &alenp2, piece, (dvoid *) 0, &rcode2)) + { + printf("ERROR: OCIStmtSetPieceInfo returned %d \n", status); + break; + } + status = OCI_NEED_DATA; + break; + case OCI_SUCCESS: + break; + default: + printf( "oci exec returned %d \n", status); + checkerr(ctxptr->errhp, status); + status = 0; + } + if (!status) break; + } + +} /* end insert_piecewise_polling() */ + + +/*set piece information for piecewise insert with polling*/ +void set_piece(piecep) +ub1 *piecep; +{ + static sword piece_cnt = 0; + + switch (piece_cnt) + { + case 0: + *piecep = OCI_FIRST_PIECE; + break; + case NPIECE - 1: + *piecep = OCI_LAST_PIECE; + piece_cnt = 0; + return; + default: + *piecep = OCI_NEXT_PIECE; + } + piece_cnt++; + return; +} + + +/*perform piecewise select with polling*/ +void select_piecewise_polling(ctxptr) +cdemol2lctx *ctxptr; +{ + text *sel_stmt1 = (text *)"SELECT * FROM PERSON_1 where ssn=2"; + text *sel_stmt2 = (text *)"SELECT * FROM PERSON_2 where ssn=2"; + OCIDefine *defnp1 = (OCIDefine *) NULL; + OCIDefine *defnp2 = (OCIDefine *) NULL; + ub4 i; + sword status, ssn; + boolean bufok = TRUE; + char buf1[PIECE_SIZE]; + ub1 buf2[PIECE_SIZE]; + ub4 alen = PIECE_SIZE; + ub1 piece = OCI_FIRST_PIECE; + dvoid *hdlptr = (dvoid *) 0; + ub4 hdltype = OCI_HTYPE_DEFINE, iter = 0, idx = 0; + ub1 in_out = 0; + sb2 indptr = 0; + ub2 rcode = 0; + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt1, (ub4) strlen((char *)sel_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SELECT PIECEWISE WITH POLLING OF PERSON_1 ... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &ssn, + (sb4) sizeof(ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) 0, + (sb4) DATA_SIZE, (ub2)SQLT_CHR, (dvoid *)0, + (ub2 *) 0, (ub2 *)0, (ub4)OCI_DYNAMIC_FETCH)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 0, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + status = OCIStmtFetch(ctxptr->stmthp, ctxptr->errhp, + (ub4) 1, (ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT); + checkerr(ctxptr->errhp, status); + + printf("ssn = %d\n", ssn); + printf("checking contents of RESUME piece by piece\n"); + while (status == OCI_NEED_DATA) + { + checkerr(ctxptr->errhp, OCIStmtGetPieceInfo(ctxptr->stmthp, + ctxptr->errhp, &hdlptr, &hdltype, + &in_out, &iter, &idx, &piece)); + + checkerr(ctxptr->errhp, OCIStmtSetPieceInfo((dvoid *)hdlptr, (ub4)hdltype, + ctxptr->errhp, (dvoid *) &buf1, &alen, piece, + (dvoid *)&indptr, &rcode)); + + status = OCIStmtFetch(ctxptr->stmthp,ctxptr->errhp, (ub4) 1, + (ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT); + + /*verify if fetch results are correct */ + for (i = 0; i < alen; i++) + if (buf1[i] != 'A') + bufok = FALSE; + + if (bufok) + printf("SUCCESS: contents of buf1 have expected value\n"); + else + printf("FAILURE: contents of buf1 do not have expected value\n"); + } + if(status == OCI_SUCCESS) + printf("SUCCESS: fetched all pieces of RESUME CORRECTLY\n"); + + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt2, (ub4) strlen((char *)sel_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SELECT PIECEWISE WITH POLLING OF PERSON_2 ... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &ssn, + (sb4) sizeof(ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) 0, + (sb4) DATA_SIZE, (ub2)SQLT_BIN, (dvoid *)0, + (ub2 *) 0, (ub2 *)0, (ub4)OCI_DYNAMIC_FETCH)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 0, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + status = OCIStmtFetch(ctxptr->stmthp, ctxptr->errhp, + (ub4) 1, (ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT); + checkerr(ctxptr->errhp, status); + + printf("ssn = %d\n", ssn); + printf("checking contents of PHOTO piece by piece\n"); + while (status == OCI_NEED_DATA) + { + checkerr(ctxptr->errhp, OCIStmtGetPieceInfo(ctxptr->stmthp, + ctxptr->errhp, &hdlptr, &hdltype, + &in_out, &iter, &idx, &piece)); + + checkerr(ctxptr->errhp, OCIStmtSetPieceInfo((dvoid *)hdlptr, (ub4)hdltype, + ctxptr->errhp, (dvoid *) &buf2, &alen, piece, + (dvoid *)&indptr, &rcode)); + + status = OCIStmtFetch(ctxptr->stmthp,ctxptr->errhp, (ub4) 1, + (ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT); + + /*verify if fetch results are correct */ + bufok = TRUE; + for (i = 0; i < alen; i++) + if (buf2[i] != 'B') + bufok = FALSE; + + if (bufok) + printf("SUCCESS: contents of buf2 have expected value\n"); + else + printf("FAILURE: contents of buf2 do not have expected value\n"); + } + if(status == OCI_SUCCESS) + printf("SUCCESS: fetched all pieces of PHOTO CORRECTLY\n"); +} /* end of select_piecewise_polling() */ + + +/*perform piecewise insert with callback*/ +void insert_piecewise_callback(ctxptr) +cdemol2lctx *ctxptr; +{ + text *ins_stmt1 = (text *)"INSERT INTO PERSON_1 VALUES (:1, :2)"; + text *ins_stmt2 = (text *)"INSERT INTO PERSON_2 VALUES (:1, :2)"; + OCIBind *bndp1 = (OCIBind *) NULL; + OCIBind *bndp2 = (OCIBind *) NULL; + sword status, ssn= 3, i; + ub4 pos[MAXCOLS]; + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt1, (ub4) strlen((char *)ins_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING PIECEWISE INSERT INTO PERSON_1 WITH CALLBACK ... \n"); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, + (dvoid *) &ssn, (sb4) sizeof(ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, + (dvoid *) 0, (sb4) DATA_SIZE, SQLT_LNG, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC)); + + for (i = 0; i < MAXCOLS; i++) + pos[i] = i+1; + + checkerr(ctxptr->errhp, OCIBindDynamic(bndp2, ctxptr->errhp, + (dvoid *) &pos[0], cbf_in_data, + (dvoid *) 0, (OCICallbackOutBind) 0)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt2, (ub4) strlen((char *)ins_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING PIECEWISE INSERT INTO PERSON_2 WITH CALLBACK ... \n"); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, + (dvoid *) &ssn, (sb4) sizeof(ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, + (dvoid *) 0, (sb4) DATA_SIZE, SQLT_BIN, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC)); + + checkerr(ctxptr->errhp, OCIBindDynamic(bndp2, ctxptr->errhp, + (dvoid *) &pos[1], cbf_in_data, + (dvoid *) 0, (OCICallbackOutBind) 0)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); +} /* end insert_piecewise_callback() */ + + +/* ----------------------------------------------------------------- */ +/* Inbind callback to specify input data. */ +/* ----------------------------------------------------------------- */ +static sb4 cbf_in_data(ctxp, bindp, iter, index, bufpp, alenpp, piecep, indpp) +dvoid *ctxp; +OCIBind *bindp; +ub4 iter; +ub4 index; +dvoid **bufpp; +ub4 *alenpp; +ub1 *piecep; +dvoid **indpp; +{ + sword j; + ub4 inpos = *((ub4 *)ctxp); + + switch(inpos) + { + case 1: + memset((void *)in1, (int) 'A', (size_t) DATA_SIZE); + *bufpp = (dvoid *) in1; + *alenpp = sizeof(in1); + break; + case 2: + memset((void *)in2, (int) 'B', (size_t) DATA_SIZE); + *bufpp = (dvoid *) in2; + *alenpp = sizeof(in2); + break; + default: + *bufpp = (dvoid *) 0; + *alenpp = 0; + printf("ERROR: invalid position number: %d\n", inpos); + } + + *indpp = (dvoid *) 0; + *piecep = OCI_ONE_PIECE; + + return OCI_CONTINUE; +} + + +/*perform piecewise select with callback*/ +void select_piecewise_callback(ctxptr) +cdemol2lctx *ctxptr; +{ + text *sel_stmt1 = (text *)"SELECT * FROM PERSON_1 where ssn=3"; + text *sel_stmt2 = (text *)"SELECT * FROM PERSON_2 where ssn=3"; + OCIDefine *defnp1 = (OCIDefine *) NULL; + OCIDefine *defnp2 = (OCIDefine *) NULL; + sword status, ssn; + char buf1[DATA_SIZE]; + ub1 buf2[DATA_SIZE]; + char *buf1p = buf1; + ub1 *buf2p = buf2; + boolean bufok = TRUE; + int i; + + column = 1; + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt1, (ub4) strlen((char *)sel_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SELECT PIECEWISE WITH CALLBACK OF PERSON_1... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &ssn, + (sb4) sizeof(ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) 0, + (sb4) DATA_SIZE, (ub2)SQLT_CHR, (dvoid *)0, + (ub2 *) 0, (ub2 *)0, (ub4)OCI_DYNAMIC_FETCH)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 0, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineDynamic(defnp2, ctxptr->errhp, + (dvoid *) &buf1p, (OCICallbackDefine) cdf_fetch_buffer)); + + status = OCIStmtFetch(ctxptr->stmthp, ctxptr->errhp, (ub4) 1, + (ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT); + + checkerr(ctxptr->errhp, status); + + /* check the contents of the last piece */ + for(i=0;ierrhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt2, (ub4) strlen((char *)sel_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SELECT PIECEWISE WITH CALLBACK OF PERSON_2... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &ssn, + (sb4) sizeof(ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) 0, + (sb4) DATA_SIZE, (ub2)SQLT_BIN, (dvoid *)0, + (ub2 *) 0, (ub2 *)0, (ub4)OCI_DYNAMIC_FETCH)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 0, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineDynamic(defnp2, ctxptr->errhp, + (dvoid *) &buf2p, (OCICallbackDefine) cdf_fetch_buffer)); + + status = OCIStmtFetch(ctxptr->stmthp, ctxptr->errhp, (ub4) 1, + (ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT); + + checkerr(ctxptr->errhp, status); + + /* check the contents of the last piece */ + bufok = TRUE; + for(i=0;ierrhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt1, (ub4) strlen((char *)ins_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING ARRAY INSERT INTO PERSON_1... \n"); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, (dvoid *) &data1[0].ssn, + (sb4) sizeof(data1[0].ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, (dvoid *) data1[0].buf1, + (sb4) sizeof(data1[0].buf1), SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + if (OCIBindArrayOfStruct(bndp1,ctxptr->errhp,valsk1, indsk, rlsk, rcsk) + || OCIBindArrayOfStruct(bndp2,ctxptr->errhp,valsk1, indsk, rlsk, rcsk)) + { + printf("FAILED: OCIBindeArrayOfStruct()\n"); + return; + } + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, ctxptr->stmthp, + ctxptr->errhp, (ub4) MAX_IN_ROWS, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + printf("\nBEGINING ARRAY INSERT INTO PERSON_2... \n"); + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt2, (ub4) strlen((char *)ins_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, (dvoid *) &data2[0].ssn, + (sb4) sizeof(data2[0].ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, (dvoid *) data2[0].buf2, + (sb4) sizeof(data2[0].buf2), SQLT_BIN, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + if (OCIBindArrayOfStruct(bndp1,ctxptr->errhp,valsk2, indsk, rlsk, rcsk) + || OCIBindArrayOfStruct(bndp2,ctxptr->errhp,valsk2, indsk, rlsk, rcsk)) + { + printf("FAILED: OCIBindeArrayOfStruct()\n"); + return; + } + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, ctxptr->stmthp, + ctxptr->errhp, (ub4) MAX_IN_ROWS, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); +} /* end sql_array_insert() */ + + +/*perform array select*/ +void sql_array_select(ctxptr) +cdemol2lctx *ctxptr; +{ + text *sel_stmt1 = (text *)"SELECT * FROM PERSON_1 where ssn>3 ORDER BY SSN"; + text *sel_stmt2 = (text *)"SELECT * FROM PERSON_2 where ssn>3 ORDER BY SSN"; + OCIDefine *defnp1 = (OCIDefine *) NULL; + OCIDefine *defnp2 = (OCIDefine *) NULL; + ub2 buflen1, buflen2; + boolean buf1ok = TRUE, buf2ok = TRUE; + ub4 i,j; + + typedef struct { + sword ssn; + char buf1[DATA_SIZE]; + } person_1; + + typedef struct { + sword ssn; + ub1 buf2[DATA_SIZE]; + } person_2; + + person_1 data1[MAX_IN_ROWS]; + person_2 data2[MAX_IN_ROWS]; + ub4 valsk1 = (ub4) sizeof(person_1); /* value skip */ + ub4 valsk2 = (ub4) sizeof(person_2); /* value skip */ + ub4 indsk = 0; /* indicator skips */ + ub4 rlsk = 0; /* return length skips */ + ub4 rcsk = 0; /* return code skips */ + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt1, (ub4) strlen((char *)sel_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING ARRAY SELECT OF PERSON_1... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &data1[0].ssn, + (sb4) sizeof(data1[0].ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) data1[0].buf1, + (sb4) sizeof(data1[0].buf1), (ub2)SQLT_CHR, (dvoid *)0, + (ub2 *) &buflen1, (ub2 *)0, (ub4)OCI_DEFAULT)); + + if (OCIDefineArrayOfStruct(defnp1,ctxptr->errhp,valsk1, indsk, rlsk, rcsk) + || OCIDefineArrayOfStruct(defnp2,ctxptr->errhp,valsk1, indsk, rlsk, rcsk)) + { + printf("FAILED: OCIDefineArrayOfStruct()\n"); + return; + } + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, ctxptr->stmthp, + ctxptr->errhp, (ub4) MAXROWS, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt2, (ub4) strlen((char *)sel_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING ARRAY SELECT OF PERSON_2... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &data2[0].ssn, + (sb4) sizeof(data2[0].ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) data2[0].buf2, + (sb4) sizeof(data2[0].buf2), (ub2)SQLT_BIN, (dvoid *)0, + (ub2 *) &buflen2, (ub2 *)0, (ub4)OCI_DEFAULT)); + + if (OCIDefineArrayOfStruct(defnp1,ctxptr->errhp,valsk2, indsk, rlsk, rcsk) + || OCIDefineArrayOfStruct(defnp2,ctxptr->errhp,valsk2, indsk, rlsk, rcsk)) + { + printf("FAILED: OCIDefineArrayOfStruct()\n"); + return; + } + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, ctxptr->stmthp, + ctxptr->errhp, (ub4) MAXROWS, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + /*check output */ + for(i=0;ienvhp, + (ub4)OCI_THREADED|OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0, + (size_t) 0, (dvoid **) 0 )) + printf("FAILED: OCIEnvCreate()\n"); + + + printf("\n ######## Connect to server ############# \n"); + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, + (dvoid **) &ctxptr->errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->errhp\n"); + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, + (dvoid **) &ctxptr->srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->srvhp\n"); + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, + (dvoid **) &ctxptr->svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->svchp\n"); + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, + (dvoid **) &ctxptr->authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->authp\n"); + + if (OCIServerAttach(ctxptr->srvhp, ctxptr->errhp, + (text *) "", (sb4) strlen((char *) ""), + (ub4) OCI_DEFAULT)) + printf("FAILED: OCIServerAttach()\n"); + + if (OCIAttrSet((dvoid *) ctxptr->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) ctxptr->srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, ctxptr->errhp)) + printf("FAILED: OCIAttrSet() server attribute\n"); + + /*begin log_on part */ + if (OCIAttrSet((dvoid *) ctxptr->authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) username, (ub4) strlen((char *) username), + (ub4) OCI_ATTR_USERNAME, ctxptr->errhp)) + printf("FAILED: OCIAttrSet() userid\n"); + + if (OCIAttrSet((dvoid *) ctxptr->authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *) password), + (ub4) OCI_ATTR_PASSWORD, ctxptr->errhp)) + printf("FAILED: OCIAttrSet() passwd\n"); + + printf("Logging on as %s ....\n", username); + + checkerr(ctxptr->errhp, OCISessionBegin((dvoid *)ctxptr->svchp, + ctxptr->errhp, ctxptr->authp, + (ub4) OCI_CRED_RDBMS,(ub4) OCI_DEFAULT )); + + printf("%s logged on.\n", username); + + if (OCIAttrSet((dvoid *) ctxptr->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) ctxptr->authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, + ctxptr->errhp)) + printf("FAILED: OCIAttrSet() session\n"); + /* end log_on part */ + + /* alocate stmt handle for sql queries */ + + if (OCIHandleAlloc((dvoid *)ctxptr->envhp, (dvoid **) &ctxptr->stmthp, + (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0)) + printf("FAILED: alloc statement handle\n"); + +} /* end initialize() */ + + +/*check status and print error information*/ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} /* end checkerr() */ + + +/*clean up envionment*/ +void cleanup(ctxptr) +cdemol2lctx *ctxptr; +{ + printf("\n ########## clean up ############ \n"); + + if (OCISessionEnd(ctxptr->svchp, ctxptr->errhp, + ctxptr->authp, (ub4) 0)) + printf("FAILED: OCISessionEnd()\n"); + + printf("%s Logged off.\n", username); + + if (OCIServerDetach(ctxptr->srvhp, ctxptr->errhp, + (ub4) OCI_DEFAULT)) + printf("FAILED: OCIServerDetach()\n"); + + printf("Detached from server.\n"); + + printf("Freeing handles ...\n"); + if (ctxptr->stmthp) + OCIHandleFree((dvoid *) ctxptr->stmthp, (ub4) OCI_HTYPE_STMT); + if (ctxptr->errhp) + OCIHandleFree((dvoid *) ctxptr->errhp, (ub4) OCI_HTYPE_ERROR); + if (ctxptr->srvhp) + OCIHandleFree((dvoid *) ctxptr->srvhp, (ub4) OCI_HTYPE_SERVER); + if (ctxptr->svchp) + OCIHandleFree((dvoid *) ctxptr->svchp, (ub4) OCI_HTYPE_SVCCTX); + if (ctxptr->authp) + OCIHandleFree((dvoid *) ctxptr->authp, (ub4) OCI_HTYPE_SESSION); + if (ctxptr->envhp) + OCIHandleFree((dvoid *) ctxptr->envhp, (ub4) OCI_HTYPE_ENV); + +} /* end cleanup() */ + + +/* end of file cdemol2l.c */ + diff --git a/cdemolb.c b/cdemolb.c new file mode 100644 index 0000000..2085f3e --- /dev/null +++ b/cdemolb.c @@ -0,0 +1,585 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemolb.c 05-apr-2005.11:49:19 lzhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1996, 2005, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemolb.c - C Demo program to illustrate the OCI Lob interface. + + DESCRIPTION + This C file contains code to demonstrate the use of the OCI LOB + (Large OBject) interface. It provides a typical example of how + OCI programs can be used to create/insert lob data, and then + access and manipulate (read, write,copy, append, trim) the data. + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + EX_SUCCESS - if the program terminates succesfully. + EX_FAILURE - if it encounters any error. + + NOTES + In the beta-1 release only Lob reads and writes (OCILobRead(), + OCILobWrite()) with no callbacks have been demonstrated. + More examples will be added in future releases. + + Before executing this program execute the following sql program: + cdemolb.sql + Executing this sql program will delete any earlier tables created + by this demo and create new tables. Each time the demo program runs + successfully it adds row to tables. So it might be a good idea to run + the sql program after several runs of the demo program. + + MODIFIED (MM/DD/YY) + lzhao 04/04/05 - bug4184359 + ani 02/19/02 - initialize OCIInd variables. + ani 01/16/02 - add indicator variable to DefineByPos using SQLT_CHR + dchatter 05/09/00 - lob read as char + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 10/01/98 - include stdlib.h - bug 714175 + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + svedala 02/17/98 - OCI obsoletion changes + cchau 03/03/97 - change functions to long names + azhao 01/31/97 - removed isnull + azhao 01/30/97 - fix lint error + echen 01/03/97 - OCI beautification + pshah 10/11/96 - + kosinski 09/24/96 - Merge Win32 changes into base development + aroy 07/22/96 - Demonstrate the OCI Lob interface. + aroy 07/22/96 - Creation + +*/ + +/*---------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include + +int main () +{ + ldemodef *ctx; + sword retval = 0; + ub2 i; + OCILobLocator *lobp; + + /* allocate and initialise ctx structure */ + ctx = alloc_handles(); + + /* allocate lob descriptor */ + alloc_lob_desc(ctx, &lobp); + + /* Allocate statement/bind/define handles */ + alloc_stmt_handles (ctx, ctx->s1, 0, 0); /* for the insert statement */ + alloc_stmt_handles (ctx, ctx->s2, 0, 2); /* Selecting lob descriptor */ + + /* Authenticate the user (connect to server) */ + authenticate_user(ctx); + + /* Insert/Select Lob locator */ + insert_select_loc(ctx, lobp); + + /* Write Data into Lob Locator */ + Write_to_loc(ctx, lobp); + + + /* Read data from Lob Locator using OCILobRead() */ + Read_from_loc(ctx, lobp); + + /* free lob locator */ + (void) OCIDescriptorFree((dvoid *) lobp, (ub4) OCI_DTYPE_LOB); + + /* Read data from Lob Column using Char type */ + select_loc_data(ctx); + + /* Deauthenticate (logout) user */ + deauthenticate(ctx); + + /* Clean up */ + cleanup(ctx); + return(EX_SUCCESS); +} + +/* --------------------------------------------------------------------- */ +/* Write data into the selected lob locator +*/ +void Write_to_loc(ctx, lobp) +ldemodef *ctx; +OCILobLocator *lobp; +{ + FILE *fp; + ub1 buf[BUFSIZE+1]; + ub4 offset; + ub4 amtp; + ub4 lenp; + sb4 err; + + if ((fp = fopen (CDEMOLB_TEXT_FILE, "r"))==NULL) + { + COMMENT ("Cannot open file for reading"); + exit (EX_FAILURE); + } + + offset = 1; /* Offset for Lobs start at 1 */ + + while (!feof(fp)) + { + /* Read the data from file */ + memset ((void *)buf, '\0', BUFSIZE); + fread((void *)buf, BUFSIZE, 1, fp); + buf[BUFSIZE]='\0'; + /* printf("%s",buf); */ + + /*Write it into the locator */ + amtp = BUFSIZE; /* IN/OUT : IN - amount if data to write */ + err = OCILobWrite (ctx->svchp, ctx->errhp, lobp, &amtp, offset, + (dvoid *) buf, (ub4) BUFSIZE, OCI_ONE_PIECE, + (dvoid *)0, (sb4 (*)()) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT); + if (err == OCI_SUCCESS) + { + printf("Written some data...\n"); + offset += amtp; + } + else + { + fclose(fp); + errrpt (ctx, (text *) "Write_to_loc : OCILobWrite"); + } + } + + COMMENT("Write Successful"); + /* Length of the Lob */ + err = OCILobGetLength(ctx->svchp, ctx->errhp, lobp, &lenp); + if (err != OCI_SUCCESS) + printf (" get lob length fails. err = %d\n\n", err); + else + printf (" Written %d bytes into Locator Successfully.\n\n", lenp); + + fclose (fp); +} + +/* --------------------------------------------------------------------- */ +/* Read data from the lob locator +*/ +void Read_from_loc(ctx, lobp) +ldemodef *ctx; +OCILobLocator *lobp; +{ + ub1 buf[BUFSIZE+1]; + ub4 offset; + ub4 amtp; + ub4 lenp=0; + sb4 err; + + COMMENT("Read from the locator."); + /* Length of the Lob */ + if (OCILobGetLength(ctx->svchp, ctx->errhp, lobp, &lenp) != OCI_SUCCESS) + errrpt(ctx, "Read_from_loc: OCILobGetLength"); + else + { + printf(" Length of Locator is %d\n", lenp); + } + + printf ("Enter the offset to read from (starting at 1): "); + scanf("%d", &offset); + printf ("Enter amount to read: "); + scanf("%d", &amtp); + + if ((offset + amtp - 1) > lenp) + { + printf ("Error: Trying to get more data than available!\n"); + exit (EX_FAILURE); + } + printf( + "\n------------------------------------------------------------------\n"); + + /* Read the locator */ + do + { + memset ((dvoid *)buf, '\0', BUFSIZE); + err = OCILobRead(ctx->svchp, ctx->errhp, lobp, &amtp, offset, + (dvoid *) buf, (ub4)BUFSIZE , (dvoid *) 0, + (OCICallbackLobRead) 0, (ub2) 0, (ub1) SQLCS_IMPLICIT); + if (err == OCI_SUCCESS || err == OCI_NEED_DATA) + { + buf[BUFSIZE] = '\0'; + printf ("%s", buf); + offset +=amtp; + } + else + errrpt(ctx, "Read_from_loc : OCILobRead"); + } + while (err == OCI_NEED_DATA); + printf( + "\n------------------------------------------------------------------\n"); + printf("\n"); +} + +/* --------------------------------------------------------------------- */ +/* insert one row into table and select the lob descriptor. +*/ +static +void alloc_stmt_handles (ctx, sptr, nbnd, ndfn) +ldemodef *ctx; +stmtdef *sptr; +sb2 nbnd; +sb2 ndfn; +{ + sb2 i; + + /* Get statement handles */ + if (OCIHandleAlloc( (dvoid *)(ctx->envhp), (dvoid **) &(sptr->stmhp), + (ub4) OCI_HTYPE_STMT, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + COMMENT("Fail to OCIHandleAlloc for statement handle"); + cleanup(ctx); + exit(EX_FAILURE); + } + + /* Get bind handles */ + +/* + for (i=0; istmhp), (dvoid **) &(sptr->bndhp[i]), + (ub4) OCI_HTYPE_BIND, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + COMMENT("Fail to OCIHandleAlloc for bind handle"); + cleanup(ctx); + exit(EX_FAILURE); + } + } +*/ + + /* Get define handles */ + +/* + for (i=0; istmhp), (dvoid **) &(sptr->dfnhp[i]), + (ub4) OCI_HTYPE_DEFINE, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + COMMENT("Fail to OCIHandleAlloc for define handle"); + cleanup(ctx); + exit(EX_FAILURE); + } + } +*/ + +} + +/* --------------------------------------------------------------------- */ +/* insert one row into table and select the lob descriptor. +*/ +static +void insert_select_loc(ctx, lobsrc) +ldemodef *ctx; +dvoid *lobsrc; +{ + + /* Insert an empty locator */ + if (OCIStmtPrepare (ctx->s1->stmhp, ctx->errhp, + insstmt[0], (ub4)strlen ((char *)insstmt[0])+1, + OCI_NTV_SYNTAX, OCI_DEFAULT) != OCI_SUCCESS) + errrpt (ctx, "insert_select_loc: OCIStmtPrepare"); + + if (OCIStmtExecute (ctx->svchp, ctx->s1->stmhp, ctx->errhp, 1, 0, 0, 0, + OCI_DEFAULT)) + errrpt (ctx, "insert_select_loc: OCIStmtExecute") ; + + printf("Inserted...\n"); + + /* Now select the locator */ + if (OCIStmtPrepare (ctx->s2->stmhp, ctx->errhp, + selstmt[0], (ub4)strlen ((char *)selstmt[0])+1, + OCI_NTV_SYNTAX, OCI_DEFAULT)) + errrpt (ctx, "insert_select_loc: OCIStmtPrepare"); + + + /* Call define for each column of interest */ + if (OCIDefineByPos (ctx->s2->stmhp, &(ctx->s2->dfnhp[1]), ctx->errhp, 1, + (dvoid *)&lobsrc, 0 , SQLT_CLOB, + (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)) + errrpt (ctx, "insert_select_loc: ocidefn"); + + printf("About to select locator...\n"); + + if (OCIStmtExecute (ctx->svchp, ctx->s2->stmhp, ctx->errhp, 1, 0, 0, 0, + OCI_DEFAULT)) + errrpt (ctx, "insert_select_loc: OCIStmtExecute") ; + +} + +/* --------------------------------------------------------------------- */ +/* select the lob data. +*/ + +static void select_loc_data(ctx) +ldemodef *ctx; +{ + + ub1 essay[1024]; + ub4 status = 0; + sb2 outind = 0; + + printf ("\nSelect Locator Data as SQLT_CHR\n"); + printf ("Reading first 1000 bytes\n\n"); + + memset ((void*)essay, 0, 1024); + + /* Now select the locator */ + if (OCIStmtPrepare (ctx->s2->stmhp, ctx->errhp, + selstmt[1], (ub4)strlen ((char *)selstmt[1])+1, + OCI_NTV_SYNTAX, OCI_DEFAULT)) + errrpt (ctx, "select_loc_data: OCIStmtPrepare"); + + /* Call define for each column of interest */ + if (OCIDefineByPos (ctx->s2->stmhp, &(ctx->s2->dfnhp[1]), ctx->errhp, 1, + (dvoid *)essay, 1000, SQLT_CHR, + (dvoid *) &outind, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)) + errrpt (ctx, "select_loc_data: OCIDefineByPos"); + + + if (OCIStmtExecute (ctx->svchp, ctx->s2->stmhp, ctx->errhp, 0, 0, 0, 0, + OCI_DEFAULT)) + errrpt (ctx, "select_loc_data: OCIStmtExecute") ; + + do + { + status = OCIStmtFetch(ctx->s2->stmhp, ctx->errhp, (ub4) 1, + (ub4) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT); + + if(outind !=0) + printf("Normal data not fetched, Output Indicator Value is %d\n",outind); + + if(status == OCI_SUCCESS || status == OCI_SUCCESS_WITH_INFO) + printf ("Essay %s\n", essay); + else + { + if (status != OCI_NO_DATA) + errrpt (ctx, "on fetching the lob as char"); + break; + } + }while(0); + + printf ("End of Reading Locator as SQLT_CHR\n\n"); +} + + +/*-------------------------------------------------------------------------*/ +/* Authenticate users and connect to server +*/ +static void authenticate_user(ctx) +ldemodef *ctx; +{ + COMMENT ("Authentication for scott is progress..."); + + if (OCIServerAttach(ctx->srvhp, ctx->errhp, (CONST OraText *)"", + 0, 0) != OCI_SUCCESS ) + errrpt(ctx, "conn2serv - OCIServerAttach"); + + /* Set the server handle in service handle */ + if (OCIAttrSet (ctx->svchp, OCI_HTYPE_SVCCTX, ctx->srvhp, 0, + OCI_ATTR_SERVER, ctx->errhp) != OCI_SUCCESS) + errrpt(ctx, "conn2serv - OCIAttrSet"); + + /* set the username/password in user handle */ + if (OCIAttrSet(ctx->authp, OCI_HTYPE_SESSION, "scott", 5, + OCI_ATTR_USERNAME, ctx->errhp) != OCI_SUCCESS) + errrpt(ctx, "conn2serv - OCIAttrSet"); + + if (OCIAttrSet(ctx->authp, OCI_HTYPE_SESSION, "tiger", 5, + OCI_ATTR_PASSWORD, ctx->errhp) != OCI_SUCCESS) + errrpt(ctx, "conn2serv - OCIAttrSet"); + + /* Authenticate */ + if (OCISessionBegin (ctx->svchp, ctx->errhp, ctx->authp, + OCI_CRED_RDBMS, OCI_DEFAULT) != OCI_SUCCESS) + errrpt(ctx, "conn2serv - ocisauth"); + + COMMENT ("Authentication for scott successful."); + + /* Set the Authentication handle in the service handle */ + if (OCIAttrSet(ctx->svchp, OCI_HTYPE_SVCCTX, ctx->authp, 0, + OCI_ATTR_SESSION, ctx->errhp) != OCI_SUCCESS) + errrpt(ctx, "conn2serv - OCIAttrSet"); +} + +/*-------------------------------------------------------------------------*/ +/* create all tables. +*/ +static void deauthenticate(ctx) +ldemodef *ctx; +{ + COMMENT ("Logging off...\n"); + if (OCISessionEnd(ctx->svchp, ctx->errhp, ctx->authp, (ub4) 0)) + { + errrpt(ctx, (CONST text *)"logout: ologof"); + } + COMMENT("Logged off.\n"); +} + +/*---------------------------------------------------------------*/ +/* +** Allocate and initialise global and local context structures. +*/ + +static ldemodef *alloc_handles() +{ + ldemodef * csptr; + int i; + + csptr = (ldemodef *) malloc(sizeof(ldemodef)); + if (csptr == (ldemodef *) 0) + { + COMMENT("Unable To Allocate Memory for ldemodef ..."); + exit(EX_FAILURE); + } + memset ((void *) csptr, '\0', sizeof(ldemodef)); + + if (OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)())0, (void (*)()) 0 ) != OCI_SUCCESS) + { + COMMENT("Fail to OCIInitialize..."); + /* cleanup(csptr); */ + exit(EX_FAILURE); + } + + if (OCIEnvInit( (OCIEnv **) &csptr->envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 ) != OCI_SUCCESS) + { + COMMENT("Fail to OCIEnvInit for service handle..."); + cleanup(csptr); + exit(EX_FAILURE); + } + + /* Get Error Handle */ + if (OCIHandleAlloc( (dvoid *) csptr->envhp, (dvoid **) &csptr->errhp, + (ub4) OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS) + { + COMMENT("Fail to OCIHandleAlloc for error handle..."); + cleanup(csptr); + exit(EX_FAILURE); + } + + /* server context */ + if (OCIHandleAlloc( (dvoid *) csptr->envhp, (dvoid **) &csptr->srvhp, + (ub4) OCI_HTYPE_SERVER, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS) + { + COMMENT("Fail to OCIHandleAlloc for server handle..."); + cleanup(csptr); + exit(EX_FAILURE); + } + + /* Service Context */ + if (OCIHandleAlloc( (dvoid *) csptr->envhp, (dvoid **) &csptr->svchp, + (ub4) OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + COMMENT("Fail to OCIHandleAlloc for service handle..."); + cleanup(csptr); + exit(EX_FAILURE); + } + + /* Auth Context */ + if (OCIHandleAlloc( (dvoid *) csptr->envhp, (dvoid **) &csptr->authp, + (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + COMMENT("Fail to OCIHandleAlloc for user handle..."); + cleanup(csptr); + exit(EX_FAILURE); + } + + /*Stmtdef structures */ + csptr->s1 = (stmtdef *) malloc(sizeof(stmtdef)); + if (csptr->s1 == (stmtdef *) 0) + { + COMMENT("Unable To Allocate Memory for stmtdef ..."); + exit(EX_FAILURE); + } + memset ((void *) csptr->s1, '\0', sizeof(stmtdef)); + + csptr->s2 = (stmtdef *) malloc(sizeof(stmtdef)); + if (csptr->s2 == (stmtdef *) 0) + { + COMMENT("Unable To Allocate Memory for stmtdef ..."); + exit(EX_FAILURE); + } + memset ((void *) csptr->s2, '\0', sizeof(stmtdef)); + return (csptr); + +} + +/* -------------------------------------------------------------- */ +/* Allocate lob descriptors. +*/ +static void alloc_lob_desc(ctx, lobsrc) + ldemodef *ctx; + OCILobLocator **lobsrc; +{ + if (OCIDescriptorAlloc((dvoid *) ctx->envhp, (dvoid **) lobsrc, + (ub4) OCI_DTYPE_LOB, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + errrpt(ctx, (CONST text *) "OCIDescriptorAlloc"); + cleanup(ctx); + exit(EX_FAILURE); + } +} + +/* -------------------------------------------------------------- */ +/* Clean up all structures used. +*/ + +static void cleanup(ctx) +ldemodef *ctx; +{ + (void) OCIHandleFree((dvoid *) ctx->srvhp, (ub4) OCI_HTYPE_SERVER); + (void) OCIHandleFree((dvoid *) ctx->svchp, (ub4) OCI_HTYPE_SVCCTX); + (void) OCIHandleFree((dvoid *) ctx->errhp, (ub4) OCI_HTYPE_ERROR); + (void) OCIHandleFree((dvoid *) ctx->authp, (ub4) OCI_HTYPE_SESSION); + (void) OCIHandleFree((dvoid *) ctx->s1, (ub4) OCI_HTYPE_STMT); + (void) OCIHandleFree((dvoid *) ctx->s2, (ub4) OCI_HTYPE_STMT); +} + +/* ------------------------------------------------------------------------- */ + +/* +** Format the output error message and obtain error string from Oracle +** given the error code +*/ +void errrpt(ctx, op) + ldemodef *ctx; + CONST text *op; +{ + text msgbuf[LONGTEXTLENGTH]; + sb4 errcode = 0; + + fprintf(stdout,"ORACLE error during %s\n", op); + OCIErrorGet ((dvoid *) ctx->errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + fprintf(stdout,"ERROR CODE = %d\n", errcode); + fprintf(stdout,"%s\n", msgbuf); + exit(EX_FAILURE); +} + +/* end of file cdemolb.c */ + diff --git a/cdemolb.dat b/cdemolb.dat new file mode 100644 index 0000000..cfaad80 --- /dev/null +++ b/cdemolb.dat @@ -0,0 +1,771 @@ +Photographic Lenses Tutorial + +By David Jacobson jacobson@hpl.hp.com + +Summary: + This posting contains a summary of optical facts for photographers. It is + more detailed that a FAQ file, but less so than a text book. It covers + focusing, apertures, bellows correction, depth of field, hyperfocal + distance, diffraction, the Modulation Transfer Function and illumination. + +Archive-name: rec-photo/lenses/tutorial +Last-modified 1994/3/19 +Version: 1.3 + +Lens Tutorial +by David M. Jacobson +jacobson@hpl.hp.com +Revised March 19, 1995 + +This note gives a tutorial on lenses and gives some common lens formulas. I +attempted to make it between an FAQ (just simple facts) and a textbook. I +generally give the starting point of an idea, and then skip to the results, +leaving out all the algebra. If any part of it is too detailed, just skip ahead +to the result and go on. + +It is in 6 parts. The first gives formulas relating subject and image distances +and magnification, the second discusses f-stops, the third discusses depth of +field, the fourth part discusses diffraction, the fifth part discusses the +Modulation Transfer Function, and the sixth illumination. The sixth part is +authored by John Bercovitz. Sometime in the future I will edit it to have all +parts use consistent notation and format. + +The theory is simplified to that for lenses with the same medium (eg air) front +and rear: the theory for underwater or oil immersion lenses is a bit more +complicated. + +Subject distance, image distance, and magnification + +In lens formulas it is convenient to measure distances from a set of points +called "principal points". There are two of them, one for the front of the lens +and one for the rear, more properly called the primary principal point and the +secondary principal point. While most lens formulas expect the subject distance +to be measured from the front principal point, most focusing scales are +calibrated to read the distance from the subject to the film plane. So you +can't use the distance on your focusing scale in most calculations, unless you +only need an approximate distance. Another interpretation of principal points +is that a (probably virtual) object at the primary principal point formed by +light entering from the front will appear from the rear to as a (probably +virtual) image at the secondary principal point with magnification exactly one. + +"Nodal points" are the two points such that a light ray entering the front of +the lens and headed straight toward the front nodal point will emerge going a +straight way from the rear nodal point at exactly the same angle to the lens's +axis as the entering ray had. The nodal points are equivalent to the principal +points when the front and rear media are the same, eg air, so for practical +purposes the terms can be used interchangeably. And again, the more proper +terms are primary nodal point and secondary nodal point. + +In simple double convex lenses the two principal points are somewhere inside +the lens (actually 1/n-th the way from the surface to the center, where n is +the index of refraction), but in a complex lens they can be almost anywhere, +including outside the lens, or with the rear principal point in front of the +front principal point. In a lens with elements that are fixed relative to each +other, the principal points are fixed relative to the glass. In zoom or +internal focusing lenses the principal points may move relative to the glass +and each other when zooming or focusing. + +When the lens is focused at infinity, the rear principal point is exactly one +focal length in front of the film. To find the front principal point, take the +lens off the camera and let light from a distant object pass through it +"backwards". Find the point where the image is formed, and measure toward the +lens one focal length. With some lenses, particularly ultra wides, you can't do +this, since the image is not formed in front of the front element. (This all +assumes that you know the focal length. I suppose you can trust the +manufacturers numbers enough for educational purposes.) + +So + subject (object) to front principal point distance. +Si + rear principal point to image distance +f + focal length +M + magnification + +1/So + 1/Si = 1/f +M = Si/So +(So-f)*(Si-f) = f^2 +M = f/(So-f) = (Si-f)/f + +If we interpret Si-f as the "extension" of the lens beyond infinity focus, then +we see that it is inversely proportional to a similar "extension" of the +subject. + +For rays close to and nearly parallel to the axis (these are called "paraxial" +rays) we can approximately model most lenses with just two planes perpendicular +to the optic axis and located at the principal points. "Nearly parallel" means +that for the angles involved, theta ~= sin(theta) ~= tan(theta). ("~=" means +approximately equal.) These planes are called principal planes. + +The light can be thought of as proceeding to the front principal plane, then +jumping to a point in the rear principal plane exactly the same displacement +from the axis and simultaneously being refracted (bent). The angle of +refraction is proportional the distance from the center at which the ray +strikes the plane and inversely proportional to the focal length of the lens. +(The "front principal plane" is the one associated with the front of the lens. +I could be behind the rear principal plane.) + +Apertures, f-stop, bellows correction factor, pupil magnification + +We define more symbols + +D + diameter of the entrance pupil, i.e. diameter of the aperture as seen from + the front of the lens +N + f-number (or f-stop) D = f/N, as in f/5.6 +Ne + effective f-number (corrected for "bellows factor", but not absorption) + +Light from a subject point spreads out in a cone whose base is the entrance +pupil. (The entrance pupil is the virtual image of the diaphragm formed by the +lens elements in front of the diaphragm.) The fraction of the total light +coming from the point that reaches the film is proportional to the solid angle +subtended by the cone. If the entrance pupil is distance y in front of the +front nodal point, this is approximately proportional to D^2/(So-y)^2. (Usually +we can ignore y.) If the magnification is M, the light from a tiny subject +patch of unit area gets spread out over an area M^2 on the film, and so the +brightness on the film is inversely proportional to M^2. With some algebraic +manipulation and assuming y=0 it can be shown that the relative brightness is + +(D/So)^2/M^2 = 1/(N^2 * (1+M)^2). + +Thus in the limit as So -> infinity and thus M -> 0, which is the usual case, +the brightness on the film is inversely proportional to the square of the +f-stop, N, and independent of the focal length. + +n For larger magnifications, M, the intensity on the film in is somewhat less +then what is indicated by just 1/N^2, and the correction is called bellows +factor. The short answer is that bellows factor when y=0 is just (1+M)^2. We +will first consider the general case when y != 0. + +n Let us go back to the original formula for the relative brightness on the +film. + +(D/(So-y))^2/M^2 + +The distance, y, that the aperture is in front of the front nodal point, +however, is not readily measurable. It is more convenient to use "pupil +magnification". Analogous to the entrance pupil is the exit pupil, which is the +virtual image of the diaphragm formed by any lens elements behind the +diaphragm. The pupil magnification is the ratio of exit pupil diameter to the +entrance pupil diameter. + +p + pupil magnification (exit_pupil_diameter/entrance_pupil_diameter) + +For all symmetrical lenses and most normal lenses the aperture appears the same +from front and rear, so p~=1. Wide angle lenses frequently have p>1, while true +telephoto lenses usually have p<1. It can be shown that y = f*(1-1/p), and +substituting this into the above equation and carrying out some algebraic +manipulation yields that the relative brightness on the film is proportional to + +1/(N^2 ( 1 + M/p)^2) + +Let us define Ne, the effective f-number, to be an f-number with the lens +focused at infinity (M=0) that would give the same relative brightness on the +film (ignoring light loss due to absorption and reflection) as the actual +f-number N does with magnification M. + +Ne = N*(1+M/p) + +n An alternate, but less fundamental, explanation of bellows correction is just +the inverse square law applied to the exit pupil to film distance. Ne is +exit_pupil_to_film_distance/exit_pupil_diameter. + +It is convenient to think of the correction in terms of f-stops (powers of +two). The correction in powers of two (stops) is 2*Log2(1+M/p) = 6.64386 +Log10(1+M/p). Note that for most normal lenses y=0 and thus p=1, so the M/p can +be replaced by just M in the above equations. + +Circle of confusion, depth of field and hyperfocal distance. + +The light from a single subject point passing through the aperture is converged +by the lens into a cone with its tip at the film (if the point is perfectly in +focus) or slightly in front of or behind the film (if the subject point is +somewhat out of focus). In the out of focus case the point is rendered as a +circle where the film cuts the converging cone or the diverging cone on the +other side of the image point. This circle is called the circle of confusion. +The farther the tip of the cone, ie the image point, is away from the film, the +larger the circle of confusion. + +Consider the situation of a "main subject" that is perfectly in focus, and an +"alternate subject point" this is in front of or behind the subject. + +Soa + alternate subject point to front principal point distance +Sia + rear principal point to alternate image point distance +h + hyperfocal distance +C + diameter of circle of confusion +c + diameter of largest acceptable circle of confusion +N + f-stop (focal length divided by diameter of entrance pupil) +Ne + effective f-stop Ne = N * (1+M/p) +D + the aperture (entrance pupil) diameter (D=f/N) +M + magnification (M=f/(So-f)) + +The diameter of the circle of confusion can be computed by similar triangles, +and then solved in terms of the lens parameters and subject distances. For a +while let us assume unity pupil magnification, i.e. p=1. + +When So is finite +C = D*(Sia-Si)/Sia = f^2*(So/Soa-1)/(N*(So-f)) +When So = Infinity, +C = f^2/(N Soa) + +Note that in this formula C is positive when the alternate image point is +behind the film (i.e. the alternate subject point is in front of the main +subject) and negative in the opposite case. In reality, the circle of confusion +is always positive and has a diameter equal to Abs(C). + +If the circle of confusion is small enough, given the magnification in printing +or projection, the optical quality throughout the system, etc., the image will +appear to be sharp. Although there is no one diameter that marks the boundary +between fuzzy and clear, .03 mm is generally used in 35mm work as the diameter +of the acceptable circle of confusion. (I arrived at this by observing the +depth of field scales or charts on/with a number of lenses from Nikon, Pentax, +Sigma, and Zeiss. All but the Zeiss lens came out around .03mm. The Zeiss lens +appeared to be based on .025 mm.) Call this diameter c. + +If the lens is focused at infinity (so the rear principal point to film +distance equals the focal length), the distance to closest point that will be +acceptably rendered is called the hyperfocal distance. + +h = f^2/(N*c) + +If the main subject is at a finite distance, the closest alternative point that +is acceptably rendered is at at distance + +Sclose = h So/(h + (So-F)) + +and the farthest alternative point that is acceptably rendered is at distance + +Sfar = h So/(h - (So - F)) + +except that if the denominator is zero or negative, Sfar = infinity. + +We call Sfar-So the rear depth of field and So-Sclose the front depth field. + +A form that is exact, even when P != 1, is + +depth of field = + =c Ne / (M^2 * (1 +or- (So-f)/h1)) + = c N (1+M/p) / (M^2 * (1 +or- (N c)/(f M)) + +where h1 = f^2/(N c), ie the hyperfocal distance given c, N, and f and assuming +P=1. Use + for front depth of field and - for rear depth of field. If the +denominator goes zero or negative, the rear depth of field is infinity. + +This is a very nice equation. It shows that for distances short with respect to +the hyperfocal distance, the depth of field is very close to just c*Ne/M^2. As +the distance increases, the rear depth of field gets larger than the front +depth of field. The rear depth of field is twice the front depth of field when +So-f is one third the hyperfocal distance. And when So-f = h1, the rear depth +of field extends to infinity. + +If we frame a subject the same way with two different lenses, i.e. M is the +same both both situations, the shorter focal length lens will have less front +depth of field and more rear depth of field at the same effective f-stop. (To a +first approximation, the depth of field is the same in both cases.) + +Another important consideration when choosing a lens focal length is how a +distant background point will be rendered. Points at infinity are rendered as +circles of size + +C = f M / N + +So at constant subject magnification a distant background point will be blurred +in direct proportion to the focal length. + +This is illustrated by the following example, in which lenses of 50mm and 100 +mm focal lengths are both set up to get a magnification of 1/10. Both lenses +are set to f/8. The graph shows the circle of confusions for points as a +function of the distance behind the subject. + +circle of confusion (mm) + # + # *** 100mm f/8 + # ... 50mm f/8 + 0.8 # ******* + # ********* + # ********* + # **** + # ***** + # **** + 0.6 # **** + # ***** ....... + # *** .................. + # ** ............. + 0.4 # **** ......... + # *** .... + # ** ..... + # * .... + # **.. + 0.2 # **. + # .*. + # ** + #* + *###################################################################### + 0 # + 250 500 750 1000 1250 1500 1750 2000 + distance behind subject (mm) + +The standard .03mm circle of confusion criterion is clear down in the ascii +fuzz. The slope of both graphs is the same near the origin, showing that to a +first approximation both lenses have the same depth of field. However, the +limiting size of the circle of confusion as the distance behind the subject +goes to infinity is twice as large for the 100mm lens as for the 50mm lens. + +Diffraction + +When a beam of parallel light passes through a circular aperture it spreads out +a little, a phenomenon known as diffraction. The smaller the aperture, the more +the spreading. The field strength (of the electric or magnetic field) at angle +phi from the axis is proportional to + +lambda/(phi Pi R) * BesselJ1(2 phi Pi R/lambda), + +where R is the radius of the aperture, lambda is the wavelength of the light, +and BesselJ1 is the first order Bessel function. The power (intensity) is +proportional to the square of this. + +n The field strength function forms a bell-shaped curve, but unlike the classic +E^(-x^2) one, it eventually oscillates about zero. Its first zero at 1.21967 +lambda/(2 R). There are actually an infinite number of lobes after this, but +about 86% of the power is in the circle bounded by the first zero. + + Relative field strength + + *** + 1 # **** + # ** + 0.8 # * + # ** + # * + # ** + # * + 0.6 # * + # * + # * + 0.4 # * + # * + # ** + 0.2 # ** + # ** + # ** ***************** + ###############################*###################*****################### + # ***** ****** + # 0.5 1 1.5****** 2 2.5 3 + + + Angle from axis (relative to lambda/diameter_of_aperture) + +Approximating the diaphragm to film distance as f and making use of the fact +that the aperture has diameter f/N, it follows directly that the diameter of +the first zero of the diffraction pattern is 2.43934*N*lambda. Applying this in +a normal photographic situation is difficult, since the light contains a whole +spectrum of colors. We really need to integrate over the visible spectrum. The +eye has maximum sensitive around 555 nm, in the yellow green. If, for +simplicity, we take 555 nm as the wavelength, the diameter of the first zero, +in mm, comes out to be 0.00135383 N. + +As was mentioned above, the normally accepted circle of confusion for depth of +field is .03 mm, but .03/0.00135383 = 22.1594, so we can see that at f/22 the +diameter of the first zero of the diffraction pattern is as large is the +acceptable circle of confusion. + +A common way of rating the resolution of a lens is in line pairs per mm. It is +hard to say when lines are resolvable, but suppose that we use a criterion that +the center of the dark area receive no more than 80% of the light power +striking the center of the lightest areas. Then the resolution is 0.823 +/(lambda*N) lpmm. If we again assume 555 nm, this comes out to 1482/N lpmm, +which is in close agreement with the widely used rule of thumb that the +resolution is diffraction limited to 1500/N lpmm. However, note that the MTF, +discussed below, provides another view of this subject. + +Modulation Transfer Function + +The modulation transfer function is a measure of the extent to which a lens, +film, etc., can reproduce detail in an image. It is the spatial analog of +frequency response in an electrical system. The exact definition of the +modulation transfer function and the related optical transfer function varies +slightly amongst different authorities. + +The 2-dimensional Fourier transform of the point spread function is known as +the optical transfer function (OTF). The value of this function along any +radius is the fourier transform of the line spread function in the same +direction. The modulation transfer function is the absolute value of the +fourier transform of the line spread function. + +Equivalently, the modulation transfer function of a lens is the ratio of +relative image contrast divided by relative subject contrast of a subject with +sinusoidally varying brightness as a function of spatial frequency (e.g. cycles +per mm). Relative contrast is defined as (Imax-Imin)/(Imax+Imin). MTF can also +be used for film, but since film has a non-linear characteristic curve, the +density is first transformed back to the equivalent intensity by applying the +inverse of the characteristic curve. + +For a lens the MTF can vary with almost every conceivable parameter, including +f-stop, subject distance, distance of the point from the center, direction of +modulation, and spectral distribution of the light. The two standard directions +are radial (also known as saggital) and tangential. + +The MTF for an an ideal diffraction-free lens is a constant 1 from 0 to +infinity at every point and direction. For a practical lens it starts out near +1, and falls off with increasing spatial frequency, with the falloff being +worse at the edges than at the center. Flare would make the MTF of a lens be +less than one even at zero spatial frequency. Adjacency effects in film can +make the MTF of film be greater than 1 in certain frequency ranges. + +An advantage of the MTF as a measure of performance is that under some +circumstances the MTF of the system is the product (frequency by frequency) of +the (properly scaled) MTFs of its components. Such multiplication is always +allowed when each step accepts as input solely the intensity of the output of +the previous state, or some function of that intensity. Thus it is legitimate +to multiply lens and film MTFs or the MTFs of a two lens system with a diffuser +in the middle. However, the MTFs of cascaded ordinary lenses can legitimately +be multiplied only when a set of quite restrictive and technical conditions is +satisfied. + +As an example of some OTF/MTF functions, below are the OTFs of pure diffraction +for an f/22 aperture, and the OTF induced by a .03mm circle of confusion of a +de-focused but otherwise perfect and diffraction free lens. (Note that these +cannot be multiplied.) + +Let lambda be the wavelength of the light, and spf the spatial frequency in +cycles per mm. + +For diffraction the formulas is + +OTF(lambda,N,spf) = + = ArcCos(lambda*N*spf) -lambda*N*spf*Sqrt(1-(lambda*N*spf)^2), + if lambda*N*spf <=1 + = 0, + if lambda*N*spf >=1 + +Note that for lambda = 555 nm, the OTF is zero at spatial frequencies of 1801/N +cycles per mm and beyond. + +For a circle of confusion of diameter C, + +OTF(C,spf) = 2 * BesselJ1(Pi C spf)/(Pi C spf) + +This goes negative at certain frequencies. Physically, this would mean that if +the test pattern were lighter right on the optical center then nearby, the +image would be darker right on the optical center than nearby. The MTF is the +absolute value of this function. Some authorities use the term "spurious +resolution" for spatial frequencies beyond the first zero. + +Here is a graph of the OTF of both a .03mm circle of confusion and an f/22 +diffraction limit. + + OTF + + # + 1 *** + #..** + # ..** + # ..* *** .03 mm circle of confusion + 0.8 # .* ... 555nm f/22 diffraction + # *. + # *.. + # * .. + 0.6 # * . + # * . + # * .. + # * ... + 0.4 # * .. + # * .. + # * .. + # * ... + 0.2 # * ... + # * ... + # * ... + # ** .. ********** + #########################*##################.*****..........*****........## + # ** *** ******** + # 20 40 *** 60**** 80 100 120 + # ******** + # + spatial frequency (cycles/mm) + +Although this graph is linear in both axes, the typical MTF is presented in a +log-log plot. + +Illumination + +(by John Bercovitz) + +The Photometric System + +Light flux, for the purposes of illumination engineering, is measured in +lumens. A lumen of light, no matter what its wavelength (color), appears +equally bright to the human eye. The human eye has a stronger response to some +wavelengths of light than to other wavelengths. The strongest response for the +light-adapted eye (when scene luminance > .001 Lambert) comes at a wavelength +of 555 nm. A light-adapted eye is said to be operating in the photopic region. +A dark-adapted eye is operating in the scotopic region (scene luminance +Last modified: Mon Mar 27 18:10:03 1995 diff --git a/cdemolb.h b/cdemolb.h new file mode 100644 index 0000000..746f6c7 --- /dev/null +++ b/cdemolb.h @@ -0,0 +1,129 @@ +/* + * $Header: cdemolb.h 14-jul-99.12:45:58 mjaeger Exp $ + */ + +/* Copyright (c) 1996, 1999,, 2000 Oracle Corporation. All rights reserved. +*/ + +/* NOTE: See 'header_template.doc' in the 'doc' dve under the 'forms' + directory for the header file template that includes instructions. +*/ + +/* + NAME + cdemolb.h - header file for cdemolb.c + + DESCRIPTION + see cdemolb.c + + RELATED DOCUMENTS + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + EXAMPLES + + NOTES + see cdemolb.c + + MODIFIED (MM/DD/YY) + dchatter 05/09/00 - lob read as char + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + azhao 01/31/97 - don't include orastd.h + azhao 01/30/97 - fix lint error + echen 01/03/97 - OCI beautification + pshah 10/11/96 - + aroy 07/22/96 - header file for cdemolb.c + aroy 07/22/96 - Creation + +*/ + + +#ifndef cdemolb +# define cdemolb + +#ifndef OCI_ORACLE +#include +#endif + +/*--------------------------------------------------------------------------- + TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +#define LFCOUNT 2 +#define STMTLEN 100 + +#define LONGTEXTLENGTH 1024 +#define BUFSIZE 1024 + +#define EX_FAILURE 1 +#define EX_SUCCESS 0 + +#define CDEMOLB_TEXT_FILE "cdemolb.dat" + +static CONST text insstmt[LFCOUNT][STMTLEN] = + { + "INSERT INTO CLBTAB VALUES ( 'Jack', EMPTY_CLOB())", + "" + }; + +static CONST text selstmt[LFCOUNT][STMTLEN] = + { + "SELECT essay FROM CLBTAB WHERE name = 'Jack' for update", + "SELECT essay FROM CLBTAB WHERE name = 'Jack'" + }; + +typedef struct { /* statement bind/define handles */ + OCIStmt *stmhp; + OCIBind *bndhp[2]; + OCIDefine *dfnhp[2]; +} stmtdef; + +typedef struct { /* GLOBAL STRUCTURE */ + OCIEnv *envhp; /* Environment handle */ + OCISvcCtx *svchp; /* Service handle */ + OCIServer *srvhp; /* Server handles */ + OCIError *errhp; /* Error handle */ + OCISession *authp; /* Authentication handle */ + stmtdef *s1; /*Statement handle 1 - for inserting*/ + stmtdef *s2; /* Handle for -select update */ +} ldemodef; + +/* define macros to be used in tests */ +#define COMMENT(x) (void) fprintf(stdout,"\nCOMMENT: %s\n", x) + +/*--------------------------------------------------------------------------- + FUNCTIONS + ---------------------------------------------------------------------------*/ +static void alloc_lob_desc(/*_ ldemodef *ctx, OCILobLocator **lobsrc _*/); +static ldemodef *alloc_handles(/*_ void _*/); +static void cleanup(/*_ ldemodef *ctx _*/); +static void errrpt(/*_ ldemodef *ctx, const text *op _*/); +static void authenticate_user(/*_ ldemodef *ctx _*/); +static void alloc_stmt_handles(/*_ ldemodef *ctx, stmtdef *sptr, + sb2 nbnd, sb2 ndfn _*/); +static void insert_select_loc (/*_ ldemodef *ctx, dvoid *lobsrc _*/); + +static void select_loc_data (/*_ ldemodef *ctx _*/); + +static void Write_to_loc(/*_ ldemodef *ctx, OCILobLocator *lobp _*/); +static void Read_from_loc(/*_ ldemodef *ctx, OCILobLocator *lobp _*/); +static void deauthenticate(/*_ ldemodef *ctx _*/); + + +#endif /* cdemolb */ + diff --git a/cdemolb.sql b/cdemolb.sql new file mode 100644 index 0000000..362c770 --- /dev/null +++ b/cdemolb.sql @@ -0,0 +1,27 @@ +rem +rem $Header: cdemolb.sql 14-jul-99.13:52:13 mjaeger Exp $ +rem +rem cdemolb.sql +rem +rem Copyright (c) 1996, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemolb.sql - +rem +rem DESCRIPTION +rem +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem aroy 07/22/96 - SQL program to create tables for cdemolb +rem aroy 07/22/96 - Created +rem + +connect scott/tiger; +DROP TABLE CLBTAB; +CREATE TABLE CLBTAB (name char(20), essay CLOB); +exit; + diff --git a/cdemolb2.c b/cdemolb2.c new file mode 100644 index 0000000..af66db8 --- /dev/null +++ b/cdemolb2.c @@ -0,0 +1,962 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemolb2.c 10-oct-2006.14:39:58 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1996, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemolb2.c - Demonstrates writing and reading of CLOB/BLOB columns + with stream mode and with callback functions. + + DESCRIPTION + This program takes 2 input files (the first a text file and the + second a binary file) and stores the files into CLOB, BLOB columns. + + On output, the program reads the newly populated CLOB/BLOB columns + and writes them to the output files (txtfile1.log, binfile1.log, + txtfile2.log, binfile2.log), where + + txtfile1.log -- created for stream reading CLOB contents to it + binfile1.log -- created for stream reading BLOB contents to it + + txtfile2.log -- created for callback reading CLOB contents to it + binfile2.log -- created for callback reading BLOB contents to it + + + Sample usage: cdemolb2 cdemolb.dat giffile.dat + + cdemolb.dat -- a text file in the demo directory + giffile.dat -- a gif file in the demo directory + + After successful execution of the program, the files, cdemolb.dat, + txtfile1.log, and txtfile2.log should be identical. giffile.dat, + binfile1.log, and binfile2.log should be identical. + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + aliu 02/17/05 - fix lint issues + aliu 02/16/05 - fix bug 4184372 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + azhao 08/19/97 - replace OCIStmtBindByPos with OCIBindByPos + azhao 06/25/97 - use rb, wb when opening bin file + cchau 03/03/97 - change functions to long names + azhao 01/31/97 - return OCI_ERROR if OCIStmtBindByPos fails + azhao 01/30/97 - fix lint error + azhao 12/31/96 - correct typo + azhao 12/31/96 - Creation + +*/ + +#include +#include +#include + +static sb4 init_handles(/*_ void _*/); +static sb4 log_on(/*_ void _*/); +static sb4 setup_table(/*_ void _*/); +static sb4 select_locator(/*_ int rowind _*/); +static ub4 file_length(/*_ FILE *fp _*/); +static sb4 test_file_to_lob(/*_ int rowind, char *tfname, char *bfname _*/); +static void test_lob_to_file(/*_ int rowind _*/); +static void stream_write_lob(/*_ int rowind, OCILobLocator *lobl, + FILE *fp, ub4 filelen _*/); +static void callback_write_lob(/*_ int rowind, OCILobLocator *lobl, + FILE *fp, ub4 filelen _*/); +static void stream_read_lob(/*_ int rowind, OCILobLocator *lobl, FILE *fp _*/); +static void callback_read_lob(/*_ int rowind, OCILobLocator *lobl, + FILE *fp _*/); +static sb4 cbk_fill_buffer(/*_ dvoid *ctxp, dvoid *bufxp, ub4 *lenp, + ub1 *piece _*/); +static sb4 cbk_write_buffer(/*_ dvoid *ctxp, CONST dvoid *bufxp, ub4 lenp, + ub1 piece _*/); + +static void logout(/*_ void _*/); +static void drop_table(/*_ void _*/); +static void report_error(/*_ void _*/); + +int main(/*_ int argc, char *argv[] _*/); + +#define TRUE 1 +#define FALSE 0 + +#define MAXBUFLEN 5000 + +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCISvcCtx *svchp; +static OCIError *errhp; +static OCISession *authp; +static OCIStmt *stmthp; +static OCILobLocator *clob, *blob; +static OCIDefine *defnp1 = (OCIDefine *) 0, *defnp2 = (OCIDefine *) 0; +static OCIBind *bndhp = (OCIBind *) 0; + +static FILE *fp1, *fp2; + +static ub4 txtfilelen = 0; +static ub4 binfilelen = 0; + +static boolean istxtfile; +static boolean tab_exists = FALSE; + +/*------------------------end of Inclusions-----------------------------*/ + +int main(argc, argv) +int argc; +char *argv[]; +{ + int rowind; + + if (argc != 3) + { + (void) printf("Usage: %s txtfilename binfilename\n", argv[0]); + return 0; + } + + if (init_handles()) + { + (void) printf("FAILED: init_handles()\n"); + return OCI_ERROR; + } + + if (log_on()) + { + (void) printf("FAILED: log_on()\n"); + return OCI_ERROR; + } + + if (setup_table()) + { + (void) printf("FAILED: setup_table()\n"); + logout(); + return OCI_ERROR; + } + + tab_exists = TRUE; + + for (rowind = 1; rowind <= 2; rowind++) + { + if (select_locator(rowind)) + { + (void) printf("FAILED: select_locator()\n"); + logout(); + return OCI_ERROR; + } + + if (test_file_to_lob(rowind, argv[1], argv[2])) + { + (void) printf("FAILED: load files to lobs\n"); + logout(); + return OCI_ERROR; + } + + test_lob_to_file(rowind); + } + + logout(); + + return OCI_SUCCESS; +} + + + + +/* ----------------------------------------------------------------- */ +/* initialize environment, allocate handles, etc. */ +/* ----------------------------------------------------------------- */ + +sb4 init_handles() +{ + if (OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + /* initialize environment handle */ + if (OCIEnvInit((OCIEnv **) &envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &clob, + (ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIDescriptorAlloc()\n"); + return OCI_ERROR; + } + + /* allocate the lob locator variables */ + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &blob, + (ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIDescriptorAlloc()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* attach to the server and log on as SCOTT/TIGER */ +/* ----------------------------------------------------------------- */ + +sb4 log_on() +{ + text *uid = (text *)"SCOTT"; + text *pwd = (text *)"tiger"; + text *cstring = (text *) ""; + + /* attach to the server */ + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *)uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *)pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* set the server attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* log on */ + if (OCISessionBegin(svchp, errhp, authp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionBegin()\n"); + return OCI_ERROR; + } + + /* set the session attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *) authp, + (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; + +} + + +/* ----------------------------------------------------------------- */ +/* Create table FOO with CLOB, BLOB columns and insert one row. */ +/* Both columns are empty lobs, not null lobs. */ +/* ----------------------------------------------------------------- */ + +sb4 setup_table() +{ + int colc; + + text *crtstmt = (text *) "CREATE TABLE FOO (A CLOB, B BLOB, C INTEGER)"; + text *insstmt = + (text *) "INSERT INTO FOO VALUES (EMPTY_CLOB(), EMPTY_BLOB(), :1)"; + + if (OCIStmtPrepare(stmthp, errhp, crtstmt, (ub4) strlen((char *) crtstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() crtstmt\n"); + return OCI_ERROR; + } + + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() crtstmt\n"); + return OCI_ERROR; + } + + if (OCIStmtPrepare(stmthp, errhp, insstmt, (ub4) strlen((char *) insstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() insstmt\n"); + return OCI_ERROR; + } + + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + + for (colc = 1; colc <= 2; colc++) + { + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() insstmt\n"); + return OCI_ERROR; + } + } + + (void) OCITransCommit(svchp, errhp, (ub4)0); + + return OCI_SUCCESS; +} + + + +/*---------------------------------------------------------------------*/ +/* Select lob locators from the CLOB, BLOB columns. */ +/* We need the 'FOR UPDATE' clause since we need to write to the lobs. */ +/*---------------------------------------------------------------------*/ + +sb4 select_locator(int rowind) +{ + int colc = rowind; + text *sqlstmt = (text *)"SELECT A, B FROM FOO WHERE C = :1 FOR UPDATE"; + + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4) strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() sqlstmt\n"); + return OCI_ERROR; + } + + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + + if (OCIDefineByPos(stmthp, &defnp1, errhp, (ub4) 1, + (dvoid *) &clob, (sb4) -1, (ub2) SQLT_CLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT) + || OCIDefineByPos(stmthp, &defnp2, errhp, (ub4) 2, + (dvoid *) &blob, (sb4) -1, (ub2) SQLT_BLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIDefineByPos()\n"); + return OCI_ERROR; + } + + /* execute the select and fetch one row */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() sqlstmt\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* Read operating system files into local buffers and then write the */ +/* buffers to lobs. */ +/* ----------------------------------------------------------------- */ + +sb4 test_file_to_lob(int rowind, char *txtfile, char *binfile) +{ + (void) printf("\n===> Testing loading files into lobs .....\n\n"); + + fp1 = fopen((const char *)txtfile, (const char *) "r"); + fp2 = fopen((const char *)binfile, (const char *) "rb"); + + if ( !(fp1 && fp2)) + { + (void) printf("ERROR: Failed to open file(s).\n"); + return -1; + } + + txtfilelen = file_length(fp1); + binfilelen = file_length(fp2); + + switch (rowind) + { + case 1: + stream_write_lob(rowind, clob, fp1, txtfilelen); + stream_write_lob(rowind, blob, fp2, binfilelen); + break; + case 2: + istxtfile = TRUE; + callback_write_lob(rowind, clob, fp1, txtfilelen); + istxtfile = FALSE; + callback_write_lob(rowind, blob, fp2, binfilelen); + break; + default: + (void) printf("ERROR: Invalid row indicator.\n"); + break; + } + + (void) fclose(fp1); + (void) fclose(fp2); + + return 0; +} + + +/* ----------------------------------------------------------------- */ +/* get the length of the input file. */ +/* ----------------------------------------------------------------- */ + +ub4 file_length(FILE *fp) +{ + fseek(fp, 0, SEEK_END); + return (ub4) (ftell(fp)); +} + + +/* ----------------------------------------------------------------- */ +/* Read operating system files into local buffers and then write the */ +/* buffers to lobs using stream mode. */ +/* ----------------------------------------------------------------- */ + +void stream_write_lob(int rowind, OCILobLocator *lobl, FILE *fp, ub4 filelen) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = filelen; + ub1 piece; + sword retval; + int readval; + ub4 len = 0; + ub4 nbytes; + ub4 remainder = filelen; + + (void) printf("--> To do streamed write lob, amount = %d\n", filelen); + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + (void) printf("Before stream write, LOB length = %d\n\n", loblen); + + (void) fseek(fp, 0, 0); + + if (filelen > MAXBUFLEN) + nbytes = MAXBUFLEN; + else + nbytes = filelen; + + if (fread((void *)bufp, (size_t)nbytes, 1, fp) != 1) + { + (void) printf("ERROR: read file.\n"); + return; + } + + remainder -= nbytes; + + if (remainder == 0) /* exactly one piece in the file */ + { + (void) printf("Only one piece, no need for stream write.\n"); + if (retval = OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) nbytes, OCI_ONE_PIECE, (dvoid *)0, + (OCICallbackLobWrite) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT) != OCI_SUCCESS) + { + (void) printf("ERROR: OCILobWrite(), retval = %d\n", retval); + return; + } + } + else /* more than one piece */ + { + if (OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) MAXBUFLEN, OCI_FIRST_PIECE, (dvoid *)0, + (OCICallbackLobWrite) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT) != OCI_NEED_DATA) + { + (void) printf("ERROR: OCILobWrite().\n"); + return; + } + + piece = OCI_NEXT_PIECE; + + do + { + if (remainder > MAXBUFLEN) + nbytes = MAXBUFLEN; + else + { + nbytes = remainder; + piece = OCI_LAST_PIECE; + } + + if (fread((void *)bufp, (size_t)nbytes, 1, fp) != 1) + { + (void) printf("ERROR: read file.\n"); + piece = OCI_LAST_PIECE; + } + + retval = OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) nbytes, piece, (dvoid *)0, + (OCICallbackLobWrite) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT); + remainder -= nbytes; + + } while (retval == OCI_NEED_DATA && !feof(fp)); + } + + if (retval != OCI_SUCCESS) + { + (void) printf("Error: stream writing LOB.\n"); + return; + } + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + (void) printf("After stream write, LOB length = %d\n\n", loblen); + + return; +} + + +/* ----------------------------------------------------------------- */ +/* Read operating system files into local buffers and then write the */ +/* buffers to lobs using callback function. */ +/* ----------------------------------------------------------------- */ + +void callback_write_lob(int rowind, OCILobLocator *lobl, FILE *fp, ub4 filelen) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = filelen; + ub4 nbytes; + sword retval; + + (void) printf("--> To do callback write lob, amount = %d\n", filelen); + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + (void) printf("Before callback write, LOB length = %d\n\n", loblen); + + (void) fseek(fp, 0, 0); + + if (filelen > MAXBUFLEN) + nbytes = MAXBUFLEN; + else + nbytes = filelen; + + if (fread((void *)bufp, (size_t)nbytes, 1, fp) != 1) + { + (void) printf("ERROR: read file.\n"); + return; + } + + if (filelen < MAXBUFLEN) /* exactly one piece in the file */ + { + (void) printf("Only one piece, no need for callback write.\n"); + if (retval = OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) nbytes, OCI_ONE_PIECE, (dvoid *)0, + (OCICallbackLobWrite) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT) != OCI_SUCCESS) + { + (void) printf("ERROR: OCILobWrite().\n"); + return; + } + } + else /* more than one piece */ + { + if (retval = OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *)bufp, + (ub4)nbytes, OCI_FIRST_PIECE, (dvoid *)0, + cbk_fill_buffer, (ub2) 0, (ub1) SQLCS_IMPLICIT)) + { + (void) printf("ERROR: OCILobWrite().\n"); + report_error(); + return; + } + } + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + (void) printf("After callback write, LOB length = %d\n\n", loblen); + + return; +} + + + +/* ----------------------------------------------------------------- */ +/* callback function to read the file into buffer. */ +/* ----------------------------------------------------------------- */ + +sb4 cbk_fill_buffer(ctxp, bufxp, lenp, piece) + dvoid *ctxp; + dvoid *bufxp; + ub4 *lenp; + ub1 *piece; +{ + FILE *fp = (istxtfile ? fp1 : fp2); + ub4 filelen = (istxtfile ? txtfilelen : binfilelen); + ub4 nbytes; + static ub4 len = MAXBUFLEN; /* because 1st piece has been written */ + + + if ((filelen - len) > MAXBUFLEN) + nbytes = MAXBUFLEN; + else + nbytes = filelen - len; + + *lenp = nbytes; + + if (fread((void *)bufxp, (size_t)nbytes, 1, fp) != 1) + { + (void) printf("ERROR: read file. Abort callback fill buffer\n"); + *piece = OCI_LAST_PIECE; + len = MAXBUFLEN; /* reset it for the next callback_write_lob() */ + return OCI_CONTINUE; + } + + len += nbytes; + + if (len == filelen) /* entire file has been read */ + { + *piece = OCI_LAST_PIECE; + len = MAXBUFLEN; /* reset it for the next callback_write_lob() */ + } + else + *piece = OCI_NEXT_PIECE; + + return OCI_CONTINUE; +} + + +/* ----------------------------------------------------------------- */ +/* Read lobs into local buffers and then write them to operating */ +/* system files. */ +/* ----------------------------------------------------------------- */ + +void test_lob_to_file(int rowind) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = MAXBUFLEN; + text txtfilename[20], binfilename[20]; + + (void) sprintf((char *) txtfilename, (char *)"txtfile%d.log", rowind); + (void) sprintf((char *) binfilename, (char *)"binfile%d.log", rowind); + + (void) printf("\n===> Testing writing lobs to files .....\n\n"); + + fp1 = fopen((char *)txtfilename, (const char *) "w"); + fp2 = fopen((char *)binfilename, (const char *) "wb"); + + if ( !(fp1 && fp2)) + { + (void) printf("ERROR: Failed to open file(s).\n"); + return; + } + + switch (rowind) + { + case 1: + stream_read_lob(rowind, clob, fp1); + stream_read_lob(rowind, blob, fp2); + break; + case 2: + istxtfile = TRUE; + callback_read_lob(rowind, clob, fp1); + + istxtfile = FALSE; + callback_read_lob(rowind, blob, fp2); + break; + default: + (void) printf("ERROR: Invalid row indicator.\n"); + break; + } + + (void) fclose(fp1); + (void) fclose(fp2); + + return; +} + + +/* ----------------------------------------------------------------- */ +/* Read lobs using stream mode into local buffers and then write */ +/* them to operating system files. */ +/* ----------------------------------------------------------------- */ + +void stream_read_lob(int rowind, OCILobLocator *lobl, FILE *fp) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = 0; + sword retval; + ub4 piece = 0; + ub4 remainder; /* the number of bytes for the last piece */ + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + amtp = loblen; + + (void) printf("--> To stream read LOB, loblen = %d.\n", loblen); + + memset((void *)bufp, '\0', MAXBUFLEN); + + retval = OCILobRead(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (loblen < MAXBUFLEN ? loblen : MAXBUFLEN), (dvoid *)0, + (OCICallbackLobRead) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT); + + switch (retval) + { + case OCI_SUCCESS: /* only one piece */ + (void) printf("stream read %d th piece\n", ++piece); + (void) fwrite((void *)bufp, (size_t)loblen, 1, fp); + break; + case OCI_ERROR: + report_error(); + break; + case OCI_NEED_DATA: /* there are 2 or more pieces */ + + remainder = loblen; + + (void) fwrite((void *)bufp, MAXBUFLEN, 1, fp); /* full buffer to write */ + + do + { + memset((void *)bufp, '\0', MAXBUFLEN); + amtp = 0; + + remainder -= MAXBUFLEN; + + retval = OCILobRead(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) MAXBUFLEN, (dvoid *)0, + (OCICallbackLobRead) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT); + + /* the amount read returned is undefined for FIRST, NEXT pieces */ + (void) printf("stream read %d th piece, amtp = %d\n", ++piece, amtp); + + if (remainder < MAXBUFLEN) /* last piece not a full buffer piece */ + (void) fwrite((void *)bufp, (size_t)remainder, 1, fp); + else + (void) fwrite((void *)bufp, MAXBUFLEN, 1, fp); + + } while (retval == OCI_NEED_DATA); + break; + default: + (void) printf("Unexpected ERROR: OCILobRead() LOB.\n"); + break; + } + + return; +} + + +/* ----------------------------------------------------------------- */ +/* Read lobs using callback function into local buffers and */ +/* then write them to operating system files. */ +/* ----------------------------------------------------------------- */ + +void callback_read_lob(int rowind, OCILobLocator *lobl, FILE *fp) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = 0; + sword retval; + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + amtp = loblen; + + (void) printf("--> To callback read LOB, loblen = %d.\n", loblen); + + if (retval = OCILobRead(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) MAXBUFLEN, (dvoid *) bufp, + (OCICallbackLobRead) cbk_write_buffer, + (ub2) 0, (ub1) SQLCS_IMPLICIT)) + { + (void) printf("ERROR: OCILobRead() LOB.\n"); + report_error(); + } + + return; +} + + +/* ----------------------------------------------------------------- */ +/* callback function to write buffer to the file. */ +/* ----------------------------------------------------------------- */ + +sb4 cbk_write_buffer(ctxp, bufxp, lenp, piece) + dvoid *ctxp; + CONST dvoid *bufxp; + ub4 lenp; + ub1 piece; +{ + static ub4 piece_count = 0; + FILE *fp = (istxtfile ? fp1 : fp2); + + piece_count++; + + switch (piece) + { + case OCI_LAST_PIECE: + (void) fwrite((void *)bufxp, (size_t)lenp, 1, fp); + (void) printf("callback read the %d th piece\n\n", piece_count); + piece_count = 0; + return OCI_CONTINUE; + + case OCI_FIRST_PIECE: + case OCI_NEXT_PIECE: + (void) fwrite((void *)bufxp, (size_t)lenp, 1, fp); + break; + default: + (void) printf("callback read error: unkown piece = %d.\n", piece); + return OCI_ERROR; + } + + (void) printf("callback read the %d th piece\n", piece_count); + + return OCI_CONTINUE; +} + + +/*-------------------------------------------------------------------*/ +/* Drop table FOO before logging off from the server. */ +/*-------------------------------------------------------------------*/ + +void drop_table() +{ + text *sqlstmt = (text *) "DROP TABLE FOO"; + + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4) strlen((char *) sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() sqlstmt\n"); + return; + } + + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + (void) printf("FAILED: OCIStmtExecute() sqlstmt\n"); + + return; +} + +/*-------------------------------------------------------------------*/ +/* Logoff and disconnect from the server. Free handles. */ +/*-------------------------------------------------------------------*/ + +void logout() +{ + if (tab_exists) + drop_table(); + + (void) OCISessionEnd(svchp, errhp, authp, (ub4) 0); + (void) OCIServerDetach(srvhp, errhp, (ub4) OCI_DEFAULT); + + (void) printf("Logged off and detached from server.\n"); + + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + (void) OCIHandleFree((dvoid *) authp, (ub4) OCI_HTYPE_SESSION); + (void) OCIDescriptorFree((dvoid *) clob, (ub4) OCI_DTYPE_LOB); + (void) OCIDescriptorFree((dvoid *) blob, (ub4) OCI_DTYPE_LOB); + (void) OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT); + + (void) printf("All handles freed\n"); + return; +} + + +/* ----------------------------------------------------------------- */ +/* retrieve error message and print it out. */ +/* ----------------------------------------------------------------- */ +void report_error() +{ + text msgbuf[512]; + sb4 errcode = 0; + + (void) OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("ERROR CODE = %d\n", errcode); + (void) printf("%.*s\n", 512, msgbuf); + return; +} + + +/* end of file cdemolb2.c */ + diff --git a/cdemolbs.c b/cdemolbs.c new file mode 100644 index 0000000..407108b --- /dev/null +++ b/cdemolbs.c @@ -0,0 +1,1012 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemolbs.c 10-oct-2006.14:39:58 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemolbs.c - Demonstrates reading and writing to LOBs through + the LOB Buffering Subsystem. + + DESCRIPTION + This program reads from an input binary/text file, writing into an + initialized B/CLOB column in buffered mode. It then reads in buffered + mode from the B/CLOB column and populates an output file. After building + the executable (assume it is called cdemolbs), run the program as follows: + cdemolbs src.txt src.bin dst.txt dst.bin + where src.txt and src.bin are text and binary files of size <= 512Kbytes. + IMPORTANT: . This program works only for single-byte CLOBs. + . Before running this program, ensure that the database is + started up and a table FOO does not exist in the SCOTT/ + TIGER sample account. + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + gtarora 10/18/99 - Correct parameters to printf + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ramkrish 03/06/98 - 546944: add/modify output statements for debug mode + skotsovo 08/07/97 - modified lbs buffer size so max read allowed changed + azhao 07/15/97 - fix reading files + azhao 05/30/97 - Use OCIBindByPos + azhao 05/27/97 - add savepoint code + ramkrish 05/01/97 - Creation + +*/ + +#include +#include +#include + +/*--------------------- Public Constants and Variables ----------------------*/ + +/* Constants */ +#define TRUE 1 +#define FALSE 0 +#define MAXBUFLEN 32768 +/* the size of the lob buffer depends on the usable chunk size. For + * this example, the maximum amount of lob data that can be read in + * one call is 508928. + */ +#define MAXLBSLEN 508928 + +/* OCI Handles */ +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCISvcCtx *svchp; +static OCIError *errhp; +static OCISession *authp; +static OCIStmt *stmthp; +static OCILobLocator *clob, *blob; +static OCIDefine *defnp1 = (OCIDefine *) 0, *defnp2 = (OCIDefine *) 0; +static OCIBind *bndhp = (OCIBind *) 0; + +/* Misellaneous */ +static FILE *fp1, *fp2; +static ub4 txtfilelen = 0; +static ub4 binfilelen = 0; +static boolean istxtfile; +static boolean tab_exists = FALSE; + +/*--------------------- Public functions - Specification --------------------*/ + +int main (/*_ int argc, char *argv[] _*/); + +static sb4 init_handles (/*_ void _*/); +static sb4 init_table (/*_ void _*/); +static sb4 log_on (/*_ void _*/); +static void log_off (/*_ void _*/); +static sb4 write_lobs (/*_ int rowind, char *txtfile, char *binfile _*/); +static sb4 read_lobs (/*_ int rowind, char *txtfile, char *binfile _*/); + +/*--------------------- Private functions - Specification -------------------*/ + +static sb4 select_clob (/*_ int rowind _*/); +static sb4 select_blob (/*_ int rowind _*/); +static sb4 select_lobs (/*_ int rowind _*/); +static sb4 buf_write_lob (/*_ int rowind, OCILobLocator *locator, FILE *fp, + ub4 filelen _*/); +static sb4 buf_read_lob (/*_ int rowind, OCILobLocator *locator, + FILE *fp _*/); +static void drop_table (/*_ void _*/); +static void report_error (/*_ void _*/); +static ub4 file_length (/*_ FILE *fp _*/); + +/*----------------------------- Public functions ----------------------------*/ + +/*---------------------------------- main -----------------------------------*/ + +/* main driver */ +int main(argc, argv) +int argc; +char *argv[]; +{ + int rowind; + + /* validate input arguments */ + if (argc != 5) + { + (void) printf("Usage: %s srctxtfile srcbinfile desttxtfile destbinfile\n", + argv[0]); + return 0; + } + /* initialize OCI handles */ + if (init_handles()) + { + (void) printf("FAILED: init_handles()\n"); + return OCI_ERROR; + } + /* log on to server */ + if (log_on()) + { + (void) printf("FAILED: log_on()\n"); + return OCI_ERROR; + } + /* init demo table */ + if (init_table()) + { + (void) printf("FAILED: init_table()\n"); + log_off(); + return OCI_ERROR; + } + /* write to LOBs in row 1 thro buffering subsystem, reading from src files */ + rowind = 1; + if (write_lobs(rowind, argv[1], argv[2])) + { + (void) printf("FAILED: write files to lobs\n"); + log_off(); + return OCI_ERROR; + } + /* read from LOBs in row 1 thro buffering subsystem, writing to dest files */ + rowind = 1; + if (read_lobs(rowind, argv[3], argv[4])) + { + (void) printf("FAILED: write lobs to files\n"); + log_off(); + return OCI_ERROR; + } + /* clean up and log off from server */ + log_off(); + + return OCI_SUCCESS; +} + +/*----------------------------- init_handles --------------------------------*/ + +/* initialize environment, and allocate all handles */ +sb4 init_handles() +{ + if (OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + /* initialize environment handle */ + if (OCIEnvInit((OCIEnv **) &envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + /* initialize service context */ + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + /* initialize error handle */ + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + /* initialize statement handle */ + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + /* initialize server handle */ + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + /* initialize session/authentication handle */ + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + /* allocate the lob locator variables */ + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &clob, + (ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIDescriptorAlloc()\n"); + return OCI_ERROR; + } + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &blob, + (ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIDescriptorAlloc()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/*------------------------------- init_table --------------------------------*/ + +/* create table FOO with initialized CLOB, BLOB columns, and insert two rows */ +sb4 init_table() +{ + int colc; + text *crtstmt = (text *) "CREATE TABLE FOO (C1 CLOB, C2 BLOB, C3 INTEGER)"; + text *insstmt = + (text *) "INSERT INTO FOO VALUES (EMPTY_CLOB(), EMPTY_BLOB(), :1)"; + + /* prepare create statement */ + if (OCIStmtPrepare(stmthp, errhp, crtstmt, (ub4) strlen((char *) crtstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() crtstmt\n"); + return OCI_ERROR; + } + /* execute create statement */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() crtstmt\n"); + return OCI_ERROR; + } + /* prepare insert statement */ + if (OCIStmtPrepare(stmthp, errhp, insstmt, (ub4) strlen((char *) insstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() insstmt\n"); + return OCI_ERROR; + } + /* associate variable colc with bind placeholder #1 in the SQL statement */ + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + /* insert two rows */ + for (colc = 1; colc <= 2; colc++) + { + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() insstmt\n"); + return OCI_ERROR; + } + } + + /* commit the Xn */ + (void) OCITransCommit(svchp, errhp, (ub4)0); + + /* set flag to be used by log_off() to drop the table */ + tab_exists = TRUE; + + return OCI_SUCCESS; +} + +/*---------------------------------- log_on ---------------------------------*/ + +/* attach to the server and log on as SCOTT/TIGER */ +sb4 log_on() +{ + text *uid = (text *)"SCOTT"; + text *pwd = (text *)"tiger"; + text *cstring = (text *)""; + + /* attach to the server */ + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + /* set username and password attributes of the server handle */ + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *)uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *)pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* set the server attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* log on */ + if (OCISessionBegin(svchp, errhp, authp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionBegin()\n"); + return OCI_ERROR; + } + + /* set the session attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *) authp, + (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + return OCI_SUCCESS; +} + +/*------------------------------------ logoff -------------------------------*/ + +/* Logoff and disconnect from the server. Free handles */ +void log_off() +{ + if (tab_exists) + drop_table(); + + (void) OCISessionEnd(svchp, errhp, authp, (ub4) 0); + (void) OCIServerDetach(srvhp, errhp, (ub4) OCI_DEFAULT); + + (void) printf("\n\nLogged off and detached from server.\n"); + + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + (void) OCIHandleFree((dvoid *) authp, (ub4) OCI_HTYPE_SESSION); + (void) OCIDescriptorFree((dvoid *) clob, (ub4) OCI_DTYPE_LOB); + (void) OCIDescriptorFree((dvoid *) blob, (ub4) OCI_DTYPE_LOB); + (void) OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT); + + (void) printf("\nAll handles freed\n"); + return; +} + +/*-------------------------------- write_lobs -------------------------------*/ + +/* write from files to LOBs */ +sb4 write_lobs (rowind, txtfile, binfile) +int rowind; +char *txtfile; +char *binfile; +{ + ub4 loblen = 0; + text *svptstmt = (text *)"SAVEPOINT cdemolbs_svpt"; + text *rlbkstmt = (text *)"ROLLBACK TO SAVEPOINT cdemolbs_svpt"; + ub4 txtfilelen = 0; + ub4 binfilelen = 0; + + /* validate row indicator */ + if (!rowind || (rowind > 2)) + { + (void) printf("ERROR: Invalid row indicator.\n"); + return OCI_ERROR; + } + /* open source files */ + fp1 = fopen((CONST char *)txtfile, (CONST char *) "r"); + fp2 = fopen((CONST char *)binfile, (CONST char *) "rb"); + if (!(fp1 && fp2)) + { + (void) printf("ERROR: Failed to open file(s).\n"); + return -1; + } + if ((txtfilelen = file_length(fp1)) > MAXLBSLEN) + { + (void) printf("ERROR: %s - length > 512Kbytes", txtfile); + return -1; + } + if ((binfilelen = file_length(fp2)) > MAXLBSLEN) + { + (void) printf("ERROR: %s - length > 512Kbytes", binfile); + return -1; + } + + /* reset file pointers to start of file */ + (void) fseek(fp1, 0, 0); + (void) fseek(fp2, 0, 0); + + /* set savepoint for Xn before commencing buffered mode operations */ + if (OCIStmtPrepare(stmthp, errhp, svptstmt, (ub4) strlen((char *)svptstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() svptstmt\n"); + return OCI_ERROR; + } + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() svptstmt\n"); + report_error(); + return OCI_ERROR; + } + + (void) printf("\n===> Writing CLOB from txtfile in buffered mode.....\n\n"); + + /* fetch the CLOB's locator from the table for update */ + if (select_clob(rowind)) + { + (void) printf("FAILED: select_clob()\n"); + log_off(); + return OCI_ERROR; + } + + /* report CLOB length before buffered write begins */ + (void) OCILobGetLength(svchp, errhp, clob, &loblen); + (void) printf("\nBefore buffered write, CLOB length = %d\n\n", loblen); + + /* enable the CLOB locator for buffering operations */ + if (OCILobEnableBuffering(svchp, errhp, clob)) + { + (void) printf("FAILED: OCILobEnableBuffering() CLOB\n"); + return OCI_ERROR; + } + + /* write the text file contents into CLOB through the buffering subsystem */ + if (buf_write_lob(rowind, clob, fp1, txtfilelen) == OCI_ERROR) + { + /* if buffered write operation failed, rollback Xn to savepoint & exit */ + if (OCIStmtPrepare(stmthp, errhp, rlbkstmt, (ub4) strlen((char *)rlbkstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() rlbkstmt\n"); + return OCI_ERROR; + } + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() rlbkstmt\n"); + report_error(); + return OCI_ERROR; + } + + (void) printf("FAILED: buf_write_lob() CLOB\n"); + return OCI_ERROR; + } + + /* commit the Xn if the CLOB's buffer was flushed successfully */ + (void) OCITransCommit(svchp, errhp, (ub4)0); + + /* disable CLOB locator from buffering */ + if (OCILobDisableBuffering(svchp, errhp, clob)) + { + (void) printf("FAILED: OCILobDisableBuffering() CLOB\n"); + return OCI_ERROR; + } + + (void) printf("\n===> Writing BLOB from binfile in buffered mode.....\n\n"); + + /* fetch the BLOB's locator from the table for update */ + if (select_blob(rowind)) + { + (void) printf("FAILED: select_blob()\n"); + log_off(); + return OCI_ERROR; + } + + /* report LOB length before buffered write begins */ + (void) OCILobGetLength(svchp, errhp, blob, &loblen); + (void) printf("\nBefore buffered write, BLOB length = %d\n\n", loblen); + + /* enable the BLOB locator for buffering operations */ + if (OCILobEnableBuffering(svchp, errhp, blob)) + { + (void) printf("FAILED: OCILobEnableBuffering() BLOB\n"); + return OCI_ERROR; + } + + /* write the bin file contents into BLOB through the buffering subsystem */ + if (buf_write_lob(rowind, blob, fp2, binfilelen) > 0) + { + /* if buffered write operation failed, rollback Xn to savepoint & exit */ + if (OCIStmtPrepare(stmthp, errhp, rlbkstmt, (ub4) strlen((char *)rlbkstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() rlbkstmt\n"); + return OCI_ERROR; + } + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() rlbkstmt\n"); + report_error(); + return OCI_ERROR; + } + + (void) printf("FAILED: buf_write_lob() BLOB\n"); + return OCI_ERROR; + } + + /* commit the Xn if the BLOB's buffer was flushed successfully */ + (void) OCITransCommit(svchp, errhp, (ub4)0); + + /* disable BLOB locator from buffering */ + if (OCILobDisableBuffering(svchp, errhp, blob)) + { + (void) printf("FAILED: OCILobDisableBuffering() BLOB\n"); + return OCI_ERROR; + } + + /* close input files */ + (void) fclose(fp1); + (void) fclose(fp2); + + return OCI_SUCCESS; +} + +/*-------------------------------- read_lobs --------------------------------*/ + +/* read from LOBs into files */ +sb4 read_lobs (rowind, txtfile, binfile) +int rowind; +char *txtfile; +char *binfile; +{ + ub4 loblen = 0; + text *svptstmt = (text *)"SAVEPOINT cdemolbs_svpt"; + text *rlbkstmt = (text *)"ROLLBACK TO SAVEPOINT cdemolbs_svpt"; + + if (!rowind || (rowind > 2)) + { + (void) printf("ERROR: Invalid row indicator.\n"); + return -1; + } + + /* open destination files */ + fp1 = fopen((CONST char *)txtfile, (CONST char *) "w"); + fp2 = fopen((CONST char *)binfile, (CONST char *) "wb"); + if (!(fp1 && fp2)) + { + (void) printf("ERROR: Failed to open file(s).\n"); + return -1; + } + + /* reset file pointers to start of file */ + (void) fseek(fp1, 0, 0); + (void) fseek(fp2, 0, 0); + + /* fetch both the LOB locators from the table for reads */ + if (select_lobs(rowind)) + { + (void) printf("FAILED: select_lobs()\n"); + log_off(); + return OCI_ERROR; + } + + /* report CLOB length before buffered read begins */ + (void) OCILobGetLength(svchp, errhp, clob, &loblen); + (void) printf("\n\nBefore buffered read, CLOB length = %d\n\n", loblen); + + /* report BLOB length before buffered read begins */ + (void) OCILobGetLength(svchp, errhp, blob, &loblen); + (void) printf("\nBefore buffered read, BLOB length = %d\n\n", loblen); + + /* set savepoint for Xn before commencing buffered mode operations */ + if (OCIStmtPrepare(stmthp, errhp, svptstmt, (ub4) strlen((char *)svptstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() svptstmt\n"); + return OCI_ERROR; + } + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() svptstmt\n"); + report_error(); + return OCI_ERROR; + } + + /* enable the locators for buffering operations */ + if (OCILobEnableBuffering(svchp, errhp, clob)) + { + (void) printf("FAILED: OCILobEnableBuffering() CLOB\n"); + return OCI_ERROR; + } + if (OCILobEnableBuffering(svchp, errhp, blob)) + { + (void) printf("FAILED: OCILobEnableBuffering() BLOB\n"); + return OCI_ERROR; + } + + (void) printf("\n===> Reading CLOB into dst.txt in buffered mode...\n\n"); + + /* read the CLOB into buffer and write the contents to a text file */ + if (buf_read_lob(rowind, clob, fp1) == OCI_ERROR) + { + /* if buffered read operation failed, rollback Xn to savepoint & exit */ + if (OCIStmtPrepare(stmthp, errhp, rlbkstmt, (ub4) strlen((char *)rlbkstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() rlbkstmt\n"); + return OCI_ERROR; + } + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() rlbkstmt\n"); + report_error(); + return OCI_ERROR; + } + + (void) printf("FAILED: buf_read_lob() CLOB\n"); + return OCI_ERROR; + } + + (void) printf("\n===> Reading BLOB into dst.bin in buffered mode...\n\n"); + + /* read the BLOB into buffer and write the contents to a binary file */ + if (buf_read_lob(rowind, blob, fp2) > 0) + { + /* if buffered read operation failed, rollback Xn to savepoint & exit */ + if (OCIStmtPrepare(stmthp, errhp, rlbkstmt, (ub4) strlen((char *)rlbkstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() rlbkstmt\n"); + return OCI_ERROR; + } + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() rlbkstmt\n"); + report_error(); + return OCI_ERROR; + } + + (void) printf("FAILED: buf_read_clob()\n"); + return OCI_ERROR; + } + + /* commit the Xn if buffered reads went off successfully */ + (void) OCITransCommit(svchp, errhp, (ub4)0); + + /* disable locator for buffering */ + if (OCILobDisableBuffering(svchp, errhp, clob)) + { + (void) printf("FAILED: OCILobDisableBuffering() \n"); + return OCI_ERROR; + } + if (OCILobDisableBuffering(svchp, errhp, blob)) + { + (void) printf("FAILED: OCILobDisableBuffering() \n"); + return OCI_ERROR; + } + + /* close output files */ + (void) fclose(fp1); + (void) fclose(fp2); + + /* report output file sizes */ + printf("\n\nInput and Output file sizes should be the same.\n"); + printf("Please verify using OS commands\n"); + + return OCI_SUCCESS; +} + +/*----------------------------- Public functions ----------------------------*/ + +/*------------------------------- select_clob -------------------------------*/ + +/* select locator from the CLOB column */ +sb4 select_clob(rowind) +int rowind; +{ + int colc = rowind; + text *sqlstmt = (text *)"SELECT C1 FROM FOO WHERE C3 = :1 FOR UPDATE"; + /* we need the 'FOR UPDATE' clause since we need to write to the lobs */ + + /* prepare select statement */ + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4) strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() sqlstmt\n"); + return OCI_ERROR; + } + /* associate variable colc with bind placeholder #1 in the SQL statement */ + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + /* associate clob var with its define handle */ + if (OCIDefineByPos(stmthp, &defnp1, errhp, (ub4) 1, + (dvoid *) &clob, (sb4) -1, (ub2) SQLT_CLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIDefineByPos() CLOB\n"); + return OCI_ERROR; + } + /* execute the select and fetch one row */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() sqlstmt\n"); + return OCI_ERROR; + } + return OCI_SUCCESS; +} + +/*------------------------------- select_blob -------------------------------*/ + +/* select locator from the BLOB column */ +sb4 select_blob(rowind) +int rowind; +{ + int colc = rowind; + text *sqlstmt = (text *)"SELECT C2 FROM FOO WHERE C3 = :1 FOR UPDATE"; + /* we need the 'FOR UPDATE' clause since we need to write to the lobs */ + + /* prepare select statement */ + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4) strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() sqlstmt\n"); + return OCI_ERROR; + } + /* associate variable colc with bind placeholder #1 in the SQL statement */ + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + /* associate blob var with its define handle */ + if (OCIDefineByPos(stmthp, &defnp2, errhp, (ub4) 1, + (dvoid *) &blob, (sb4) -1, (ub2) SQLT_BLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIDefineByPos()\n"); + return OCI_ERROR; + } + /* execute the select and fetch one row */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() sqlstmt\n"); + return OCI_ERROR; + } + return OCI_SUCCESS; +} + +/*------------------------------- select_lobs -------------------------------*/ + +/* select lob locators from the CLOB, BLOB columns */ +sb4 select_lobs(rowind) +int rowind; +{ + int colc = rowind; + text *sqlstmt = (text *)"SELECT C1, C2 FROM FOO WHERE C3 = :1"; + /* we don't need the 'FOR UPDATE' clause since we are just reading the LOBs*/ + + /* prepare select statement */ + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4) strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() sqlstmt\n"); + return OCI_ERROR; + } + /* associate variable colc with bind placeholder #1 in the SQL statement */ + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + /* associate clob and blob vars with their define handles */ + if (OCIDefineByPos(stmthp, &defnp1, errhp, (ub4) 1, + (dvoid *) &clob, (sb4) -1, (ub2) SQLT_CLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT) + || OCIDefineByPos(stmthp, &defnp2, errhp, (ub4) 2, + (dvoid *) &blob, (sb4) -1, (ub2) SQLT_BLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIDefineByPos()\n"); + return OCI_ERROR; + } + /* execute the select and fetch one row */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() sqlstmt\n"); + return OCI_ERROR; + } + return OCI_SUCCESS; +} + +/*------------------------------- buf_write_lob -----------------------------*/ + +/* + * Read operating system files into local buffers and then write these local + * buffers to LOBs using buffering system. + */ +sb4 buf_write_lob(rowind, locator, fp, filelen) +int rowind; +OCILobLocator *locator; +FILE *fp; +ub4 filelen; +{ + ub4 offset = 1; + ub1 bufp[MAXBUFLEN]; + ub4 amtp, nbytes; + ub4 remainder = filelen; + + while (remainder > 0 && !feof(fp)) + { + amtp = nbytes = (remainder > MAXBUFLEN) ? MAXBUFLEN : remainder; + + if (fread((void *)bufp, (size_t)nbytes, (size_t)1, fp) != 1) + { + (void) printf("ERROR: read file.\n"); + return OCI_ERROR; + } + + if (OCILobWrite(svchp, errhp, locator, &amtp, offset, (dvoid *) bufp, + (ub4) nbytes, OCI_ONE_PIECE, (dvoid *)0, + (sb4 (*)(dvoid *, dvoid *, ub4 *, ub1 *)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT) != OCI_SUCCESS) + { + (void) printf("ERROR: OCILobWrite()\n"); + report_error(); + return OCI_ERROR; + } + + (void) printf("Wrote %d of %d bytes starting at offset %d;; ", + amtp, filelen, offset); + + remainder -= nbytes; + offset += nbytes; + (void) printf("%d remaining\n\n", remainder); + } + + /* flush the buffers back to the server */ + (void) printf("\nFlush LOB's buffer to server\n"); + if (OCILobFlushBuffer(svchp, errhp, locator, OCI_LOB_BUFFER_NOFREE)) + { + (void) printf("FAILED: OCILobFlushBuffer() \n"); + return OCI_ERROR; + } + (void) printf("\n\nBuffered Write done\n\n"); + return OCI_SUCCESS; +} + +/*--------------------------------- buf_read_lob ----------------------------*/ + +/* + * Read LOBs using buffered mode into local buffers and writes them into + * operating system files. + */ +sb4 buf_read_lob(rowind, locator, fp) +int rowind; +OCILobLocator *locator; +FILE *fp; +{ + ub4 offset = 1; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = 0; + ub4 nbytes = 0; + ub4 filelen = 0; + ub4 total = 0; + + /* + * read from CLOB and write to text file (in the process, populating upto + * 16 pages in the buffering subsystem). + */ + + /* set amount to be read per iteration */ + amtp = nbytes = MAXBUFLEN; + + while (amtp) + { + if (OCILobRead(svchp, errhp, locator, &amtp, (ub4) offset, (dvoid *) bufp, + (ub4) nbytes, (dvoid *)0, + (sb4 (*)(dvoid *, CONST dvoid *, ub4, ub1)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT)) + { + (void) printf("FAILED: OCILobRead() \n"); + report_error(); + return OCI_ERROR; + } + + if (amtp > 0) + { + total += amtp; + (void) printf("Read %d bytes starting at offset %d; Total %d\n\n", + amtp, offset, total); + (void) fwrite((void *)bufp, (size_t)amtp, (size_t)1, fp); + offset += nbytes; + } + else + break; + } + printf("\n\nBuffered Read Done\n\n"); + return OCI_SUCCESS; +} + +/*--------------------------------- drop_table ------------------------------*/ + +/* Drop table FOO before logging off from the server */ +void drop_table() +{ + text *dropstmt = (text *) "DROP TABLE FOO"; + + /* prepare drop statement */ + if (OCIStmtPrepare(stmthp, errhp, dropstmt, (ub4) strlen((char *) dropstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() dropstmt\n"); + return; + } + /* execute drop statement */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() dropstmt\n"); + return; + } + return; +} + +/*-------------------------------- report_error -----------------------------*/ + +/* retrieve error message and print it out */ +void report_error() +{ + text msgbuf[512]; + sb4 errcode = 0; + + (void) OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("ERROR CODE = %d\n", errcode); + (void) printf("%.*s\n", 512, msgbuf); + return; +} + +/*-------------------------------- file_length ------------------------------*/ + +/* get the length of the input file */ +ub4 file_length(fp) +FILE *fp; +{ + fseek(fp, 0, SEEK_END); + return (ub4) (ftell(fp)); +} + +/* end of file cdemolbs.c */ diff --git a/cdemoplb.c b/cdemoplb.c new file mode 100644 index 0000000..33f2b72 --- /dev/null +++ b/cdemoplb.c @@ -0,0 +1,807 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoplb.c 14-jul-99.13:14:39 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemoplb.c - C Demo program - using LOBs in partitioned tables. + + DESCRIPTION + This program demonstrates using LOBs in partitioned tables. + A partitioned table is created with one BLOB and two CLOB columns + and LOB storage clause is specified to store lobs in different + tablespaces based on value of column A and if the LOB in question + is column B, C or D. + + Two data files, a text file and a binary file are expected as + arguments. + + The program creates six log files: + binfile1.log + txtfile2.log + txtfile3.log + binfile11.log + txtfile12.log + txtfile13.log + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 07/22/98 - Creation + +*/ + +#include +#include + +static sb4 init_handles(/*_ void _*/); +static sb4 log_on(/*_ void _*/); +static sb4 create_table(/*_ void _*/); +static sb4 select_locator(/*_ int rowind _*/); +static ub4 file_length(/*_ FILE *fp _*/); +static sb4 test_file_to_lob(/*_ int rowind, char *tfname, char *bfname _*/); +static void test_lob_to_file(/*_ int rowind _*/); +static void stream_write_lob(/*_ int rowind, OCILobLocator *lobl, + FILE *fp, ub4 filelen _*/); +static void stream_read_lob(/*_ int rowind, OCILobLocator *lobl, FILE *fp _*/); +static sb4 cbk_fill_buffer(/*_ dvoid *ctxp, dvoid *bufxp, ub4 *lenp, + ub1 *piece _*/); +static sb4 cbk_write_buffer(/*_ dvoid *ctxp, CONST dvoid *bufxp, ub4 lenp, + ub1 piece _*/); + +static void logout(/*_ void _*/); +static void report_error(/*_ void _*/); + +int main(/*_ int argc, char *argv[] _*/); + +#define TRUE 1 +#define FALSE 0 + +#define MAXBUFLEN 5000 + +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCISvcCtx *svchp; +static OCIError *errhp; +static OCISession *authp; +static OCIStmt *stmthp; +static OCILobLocator *lob; +static OCIDefine *defnp1 = (OCIDefine *) 0, *defnp2 = (OCIDefine *) 0; +static OCIBind *bndhp = (OCIBind *) 0; + +static FILE *fp1; + +static ub4 filelen = 0; + +static boolean istxtfile; + +/*------------------------end of Inclusions-----------------------------*/ + +int main(argc, argv) +int argc; +char *argv[]; +{ + int rowind; + + if (argc != 3) + { + (void) printf("Usage: %s txtfilename binfilename\n", argv[0]); + return 0; + } + + if (init_handles()) + { + (void) printf("FAILED: init_handles()\n"); + return OCI_ERROR; + } + + if (log_on()) + { + (void) printf("FAILED: log_on()\n"); + return OCI_ERROR; + } + + if (create_table()) + { + (void) printf("FAILED: create_table()\n"); + logout(); + return OCI_ERROR; + } + + /************************************************ + ** First three inserts will go into partition P1 + ** column A = 1, column B into tablespace tbs_2 + ** column A = 2, column C into tablespace tbs_4 + ** column A = 3, column D into tablesapce tbs_2 + */ + for (rowind = 1; rowind <= 3; rowind++) + { + if (insert_record(rowind)) + { + (void) printf("FAILED: insert_record()\n"); + logout(); + return OCI_ERROR; + } + + if (select_locator(rowind)) + { + (void) printf("FAILED: select_locator()\n"); + logout(); + return OCI_ERROR; + } + + if (test_file_to_lob(rowind, argv[1], argv[2])) + { + (void) printf("FAILED: load files to lobs\n"); + logout(); + return OCI_ERROR; + } + + test_lob_to_file(rowind); + } + + /************************************************ + ** First three inserts will go into partition P1 + ** column A = 11, column B into tablespace tbs_3 + ** column A = 12, column C into tablespace tbs_3 + ** column A = 13, column D into tablesapce tbs_3 + */ + for (rowind = 11; rowind <= 13; rowind++) + { + if (insert_record(rowind)) + { + (void) printf("FAILED: insert_record()\n"); + logout(); + return OCI_ERROR; + } + + if (select_locator(rowind)) + { + (void) printf("FAILED: select_locator()\n"); + logout(); + return OCI_ERROR; + } + + if (test_file_to_lob(rowind, argv[1], argv[2])) + { + (void) printf("FAILED: load files to lobs\n"); + logout(); + return OCI_ERROR; + } + + test_lob_to_file(rowind); + } + + logout(); + + return OCI_SUCCESS; +} + + + + +/* ----------------------------------------------------------------- */ +/* initialize environment, allocate handles, etc. */ +/* ----------------------------------------------------------------- */ + +sb4 init_handles() +{ + if (OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + /* initialize environment handle */ + if (OCIEnvInit((OCIEnv **) &envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &lob, + (ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIDescriptorAlloc()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* attach to the server and log on as SCOTT/TIGER */ +/* ----------------------------------------------------------------- */ + +sb4 log_on() +{ + text *uid = (text *)"CDEMOPLB"; + text *pwd = (text *)"CDEMOPLB"; + text *cstring = (text *) ""; + + /* attach to the server */ + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *)uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *)pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* set the server attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* log on */ + if (OCISessionBegin(svchp, errhp, authp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionBegin()\n"); + return OCI_ERROR; + } + + /* set the session attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *) authp, + (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; + +} + + +/* ----------------------------------------------------------------- */ +/* Create table FOO with CLOB, BLOB columns and insert one row. */ +/* Both columns are empty lobs, not null lobs. */ +/* ----------------------------------------------------------------- */ + +sb4 create_table() +{ + int colc; + + text *crtstmt = (text *) + "CREATE TABLE PT1 (A NUMBER, B BLOB, C CLOB, D CLOB) " + "PARTITION BY RANGE (A)" + " (PARTITION P1 VALUES LESS THAN (10) TABLESPACE TBS_1" + " LOB (B,D) STORE AS (TABLESPACE TBS_2)," + " PARTITION P2 VALUES LESS THAN (MAXVALUE)" + " LOB (B,C,D) STORE AS (TABLESPACE TBS_3)" + " ) TABLESPACE TBS_4"; + + if (OCIStmtPrepare(stmthp, errhp, crtstmt, (ub4) strlen((char *) crtstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() crtstmt\n"); + return OCI_ERROR; + } + + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() crtstmt\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* Insert record into table PT1 with empty_blob() and empty_clob() */ +/* as values for columns b, c or d */ +/* ----------------------------------------------------------------- */ + +sb4 insert_record(int rowind) +{ + int colc; + + text insstmt[100]; + + switch (rowind) + { + case 1: + case 11: + sprintf(insstmt, "INSERT INTO PT1 (A, B) VALUES (:1, EMPTY_BLOB())"); + break; + case 2: + case 12: + sprintf(insstmt, "INSERT INTO PT1 (A, C) VALUES (:1, EMPTY_CLOB())"); + break; + case 3: + case 13: + sprintf(insstmt, "INSERT INTO PT1 (A, D) VALUES (:1, EMPTY_CLOB())"); + break; + default: + (void) printf("ERROR: Invalid row indicator.\n"); + break; + } + + if (OCIStmtPrepare(stmthp, errhp, insstmt, (ub4) strlen((char *) insstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() insstmt\n"); + return OCI_ERROR; + } + + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + + colc = rowind; + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() insstmt\n"); + return OCI_ERROR; + } + + (void) OCITransCommit(svchp, errhp, (ub4)0); + + return OCI_SUCCESS; +} + +/*---------------------------------------------------------------------*/ +/* Select lob locators from the CLOB, BLOB columns. */ +/* We need the 'FOR UPDATE' clause since we need to write to the lobs. */ +/*---------------------------------------------------------------------*/ + +sb4 select_locator(int rowind) +{ + int colc = rowind; + text sqlstmt[100]; + + switch(rowind) + { + case 1: + case 11: + sprintf(sqlstmt, "SELECT B FROM PT1 WHERE A = :1 FOR UPDATE"); + break; + case 2: + case 12: + sprintf(sqlstmt, "SELECT C FROM PT1 WHERE A = :1 FOR UPDATE"); + break; + case 3: + case 13: + sprintf(sqlstmt, "SELECT D FROM PT1 WHERE A = :1 FOR UPDATE"); + break; + default: + (void) printf("ERROR: Invalid row indicator.\n"); + break; + } + + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4) strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() sqlstmt\n"); + return OCI_ERROR; + } + + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + + switch (rowind) + { + case 1: + case 11: + if (OCIDefineByPos(stmthp, &defnp2, errhp, (ub4) 1, + (dvoid *) &lob, (sb4) -1, (ub2) SQLT_BLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIDefineByPos() - BLOB\n"); + return OCI_ERROR; + } + break; + case 2: + case 3: + case 12: + case 13: + if (OCIDefineByPos(stmthp, &defnp1, errhp, (ub4) 1, + (dvoid *) &lob, (sb4) -1, (ub2) SQLT_CLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIDefineByPos() - CLOB\n"); + return OCI_ERROR; + } + break; + default: + (void) printf("ERROR: Invalid row indicator.\n"); + break; + } + + /* execute the select and fetch one row */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() sqlstmt\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* Read operating system files into local buffers and then write the */ +/* buffers to lobs. */ +/* ----------------------------------------------------------------- */ + +sb4 test_file_to_lob(int rowind, char *txtfile, char *binfile) +{ + (void) printf("\n===> Testing loading files into lobs .....\n\n"); + + if (rowind == 1 || rowind == 11) + { + fp1 = fopen((const char *)binfile, (const char *) "rb"); + } + else + { + fp1 = fopen((const char *)txtfile, (const char *) "r"); + } + + if (!fp1) + { + (void) printf("ERROR: Failed to open file(s).\n"); + return -1; + } + + filelen = file_length(fp1); + + stream_write_lob(rowind, lob, fp1, filelen); + + (void) fclose(fp1); + + return 0; +} + + +/* ----------------------------------------------------------------- */ +/* get the length of the input file. */ +/* ----------------------------------------------------------------- */ + +ub4 file_length(FILE *fp) +{ + fseek(fp, 0, SEEK_END); + return (ub4) (ftell(fp)); +} + + +/* ----------------------------------------------------------------- */ +/* Read operating system files into local buffers and then write the */ +/* buffers to lobs using stream mode. */ +/* ----------------------------------------------------------------- */ + +void stream_write_lob(int rowind, OCILobLocator *lobl, FILE *fp, ub4 filelen) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = filelen; + ub1 piece; + sword retval; + int readval; + ub4 len = 0; + ub4 nbytes; + ub4 remainder = filelen; + + (void) printf("--> To do streamed write lob, amount = %d\n", filelen); + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + (void) printf("Before stream write, LOB length = %d\n\n", loblen); + + (void) fseek(fp, 0, 0); + + if (filelen > MAXBUFLEN) + nbytes = MAXBUFLEN; + else + nbytes = filelen; + + if (fread((void *)bufp, (size_t)nbytes, 1, fp) != 1) + { + (void) printf("ERROR: read file.\n"); + return; + } + + remainder -= nbytes; + + if (remainder == 0) /* exactly one piece in the file */ + { + (void) printf("Only one piece, no need for stream write.\n"); + if (retval = OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) nbytes, OCI_ONE_PIECE, (dvoid *)0, + (sb4 (*)(dvoid *, dvoid *, ub4 *, ub1 *)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT) != OCI_SUCCESS) + { + (void) printf("ERROR: OCILobWrite(), retval = %d\n", retval); + return; + } + } + else /* more than one piece */ + { + if (OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) MAXBUFLEN, OCI_FIRST_PIECE, (dvoid *)0, + (sb4 (*)(dvoid *, dvoid *, ub4 *, ub1 *)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT) != OCI_NEED_DATA) + { + (void) printf("ERROR: OCILobWrite().\n"); + return; + } + + piece = OCI_NEXT_PIECE; + + do + { + if (remainder > MAXBUFLEN) + nbytes = MAXBUFLEN; + else + { + nbytes = remainder; + piece = OCI_LAST_PIECE; + } + + if (fread((void *)bufp, (size_t)nbytes, 1, fp) != 1) + { + (void) printf("ERROR: read file.\n"); + piece = OCI_LAST_PIECE; + } + + retval = OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) nbytes, piece, (dvoid *)0, + (sb4 (*)(dvoid *, dvoid *, ub4 *, ub1 *)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT); + remainder -= nbytes; + + } while (retval == OCI_NEED_DATA && !feof(fp)); + } + + if (retval != OCI_SUCCESS) + { + (void) printf("Error: stream writing LOB.\n"); + return; + } + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + (void) printf("After stream write, LOB length = %d\n\n", loblen); + + return; +} + + + +/* ----------------------------------------------------------------- */ +/* Read lobs into local buffers and then write them to operating */ +/* system files. */ +/* ----------------------------------------------------------------- */ + +void test_lob_to_file(int rowind) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = MAXBUFLEN; + text filename[20]; + + if (rowind == 1 || rowind == 11) + { + (void) sprintf((char *) filename, (char *)"binfile%d.log", rowind); + fp1 = fopen((char *)filename, (const char *) "wb"); + } + else + { + (void) sprintf((char *) filename, (char *)"txtfile%d.log", rowind); + fp1 = fopen((char *)filename, (const char *) "w"); + } + + (void) printf("\n===> Testing writing lobs to files .....\n\n"); + + if (!fp1) + { + (void) printf("ERROR: Failed to open file(s).\n"); + return; + } + + stream_read_lob(rowind, lob, fp1); + + (void) fclose(fp1); + + return; +} + + +/* ----------------------------------------------------------------- */ +/* Read lobs using stream mode into local buffers and then write */ +/* them to operating system files. */ +/* ----------------------------------------------------------------- */ + +void stream_read_lob(int rowind, OCILobLocator *lobl, FILE *fp) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = 0; + sword retval; + ub4 piece = 0; + ub4 remainder; /* the number of bytes for the last piece */ + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + amtp = loblen; + + (void) printf("--> To stream read LOB, loblen = %d.\n", loblen); + + memset(bufp, '\0', MAXBUFLEN); + + retval = OCILobRead(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (loblen < MAXBUFLEN ? loblen : MAXBUFLEN), (dvoid *)0, + (sb4 (*)(dvoid *, const dvoid *, ub4, ub1)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT); + + switch (retval) + { + case OCI_SUCCESS: /* only one piece */ + (void) printf("stream read %d th piece\n", ++piece); + (void) fwrite((void *)bufp, (size_t)loblen, 1, fp); + break; + case OCI_ERROR: + report_error(); + break; + case OCI_NEED_DATA: /* there are 2 or more pieces */ + + remainder = loblen; + + /* a full buffer to write */ + (void) fwrite((void *)bufp, MAXBUFLEN, 1, fp); + + do + { + memset(bufp, '\0', MAXBUFLEN); + amtp = 0; + + remainder -= MAXBUFLEN; + + retval = OCILobRead(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) MAXBUFLEN, (dvoid *)0, + (sb4 (*)(dvoid *, const dvoid *, ub4, ub1)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT); + + /* the amount read returned is undefined for FIRST, NEXT pieces */ + (void) printf("stream read %d th piece, amtp = %d\n", ++piece, amtp); + + if (remainder < MAXBUFLEN) /* last piece not a full buffer piece */ + (void) fwrite((void *)bufp, (size_t)remainder, 1, fp); + else + (void) fwrite((void *)bufp, MAXBUFLEN, 1, fp); + + } while (retval == OCI_NEED_DATA); + break; + default: + (void) printf("Unexpected ERROR: OCILobRead() LOB.\n"); + break; + } + + return; +} + + +/*-------------------------------------------------------------------*/ +/* Logoff and disconnect from the server. Free handles. */ +/*-------------------------------------------------------------------*/ + +void logout() +{ + + (void) OCISessionEnd(svchp, errhp, authp, (ub4) 0); + (void) OCIServerDetach(srvhp, errhp, (ub4) OCI_DEFAULT); + + (void) printf("Logged off and detached from server.\n"); + + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + (void) OCIHandleFree((dvoid *) authp, (ub4) OCI_HTYPE_SESSION); + (void) OCIDescriptorFree((dvoid *) lob, (ub4) OCI_DTYPE_LOB); + (void) OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT); + + (void) printf("All handles freed\n"); + return; +} + + +/* ----------------------------------------------------------------- */ +/* retrieve error message and print it out. */ +/* ----------------------------------------------------------------- */ +void report_error() +{ + text msgbuf[512]; + sb4 errcode = 0; + + (void) OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("ERROR CODE = %d\n", errcode); + (void) printf("%.*s\n", 512, msgbuf); + return; +} + + +/* end of file cdemolb2.c */ + diff --git a/cdemoqc.c b/cdemoqc.c new file mode 100644 index 0000000..4a278e8 --- /dev/null +++ b/cdemoqc.c @@ -0,0 +1,544 @@ +/* Copyright (c) 2007, 2008, Oracle and/or its affiliates. + All rights reserved. */ + +/* + NAME + cdemoqc - Basic OCI Query Cache(result cache) functionality + + DESCRIPTION + This program uses multiple sessions to demonstrate the working of Query + cache. To use the query cache feature (and hence this program), database + should have been brought up with client side result cache enabled. To bring + the database with result cache enabled, add the following lines in + initialization parameter file, + client_result_cache_size= + client_result_cache_lag= + compatible=11.0.0.0.0 + and bring up the database. + + After this, when the result cache hint is specified, fetched data will be + cached locally. When the same query is executed again, data will be fetched + from this local client cache rather than fetching the data from the server. + Hence there will be substantial improvement in the performance if this + feature is used on the transactions where the same query is executed + multiple times on the tables which will be rarely updated. + + When the contents of the table is changed, the next fetch statement will + fetch the data from the server and also the local cache will be updated. + This updated cache will be used thereafter. + + NOTE: + 1.To check the performance improvement with this feature measure the time + taken by this program using your operating specific commands. For example + in Linux, "time cdemoqc" will give you the time taken by this program for + completion. After this repeat the same program without result_cache hint + and measure the time taken. You should able to see some difference in these + times and this difference will be remarkable when the server is running + remotely. + 2.print_stats() will query the stats table. This function can be used to + check the cache usage statistics. The call to this funtion has been + commented out. If you want to see this statistics info please uncomment the + corresponding lines in main(). + For getting this statistics, user needs to login as SYSDBA. Hence if you + uncomment this call, the program will prompt for sys user password. scanf() + has been used for fetching the password from user and you may want to + replace it with your platform specific function to hide the echoing of + password. + + MODIFIED (MM/DD/YY) + dgopal 12/19/07 - Updated + dgopal 05/08/07 - Created + +*/ + +#if defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32) +#include +#define sleep(x) Sleep(1000*(x)) +#endif + +# include + +# include +# include +# include + +#if !defined(WIN32COMMON) && !defined(WIN32) && !defined(_WIN32) +#include +#endif + +#define EMPLOYEE 0 +#define HR 1 + +/* Function prototypes */ +static void query_tab(ub4 idx); +static void upd_table(ub4 idx); +static void print_stats(); +static void dbLogon(); +static void dbLogoff(); +static void Checkerr(OCIError *errhp, sword status, text *msg); + +int main(); + +static sword status = 0; +static OCISvcCtx *svchp[2]; +static OCIError *errhp; +static OCIEnv *envhp; +static OCIAuthInfo *authhp; + +/* Queries with result cache hints */ +static text *cache_query= +(text *)"SELECT /*+ result_cache */ empno, ename, sal FROM qctable"; + +static text *upd_stmt= +(text *)"UPDATE qctable SET sal=sal+50 WHERE empno=1"; + +/* - main -------------------------------------------------------------------*/ +int main () +{ + printf ("Query cache is enabled by using result_cache hints\n\n"); + + /* Logging on to multiple sessions */ + dbLogon (); + + /* + Querying same table from different sessions. For the same queries result + cache will be shared across sessions. + */ + printf ("Employee: Execute will fetch rows from server\n"); + query_tab(EMPLOYEE); + printf ("Employee: Execute will fetch rows from local cache\n"); + query_tab(EMPLOYEE); + + printf ("HR: Execute will cause a roundtrip during first execute, but the " + "same result \n\tset created in Employee Session will be shared " + "thereafter\n"); + query_tab(HR); + printf ("HR: Execute will fetch rows from local cache\n"); + query_tab(HR); + + /* + Updating the table. This will invalidate the result caches of all the + sessions involving this table data. + */ + printf ("\nHR: Updating the table\n\n"); + upd_table(HR); + + printf ("Employee: Execute will fetch rows from server and hence the local " + "result set \n\twill be updated\n"); + query_tab(EMPLOYEE); + printf ("HR: Execute will fetch rows from updated local cache\n"); + query_tab(HR); + printf ("Employee: Execute will fetch rows from local cache\n"); + query_tab(EMPLOYEE); + + /* + Stats table will get updated only once in few seconds. So data should be + fetched from the stats table after sleeping for few seconds. + */ + +/* Below lines should be uncommented if you want to see the cache usage stats */ + /* + printf ("\nSleeping for few seconds to let the stat table to get " + "updated\n\n"); + + sleep (60); + print_stats(); + */ + + dbLogoff (); + return 0; +} + +/* - Logon to the DB in two sessions ----------------------------------------*/ +static void dbLogon () +{ + int idx; + ub4 cachesize=10; + OraText *connStr = (text *)""; + OraText *username = (text *)"ocitest"; + OraText *password = (text *)"ocitest"; + + OCIEnvCreate ((OCIEnv **)&envhp, (ub4)OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t))0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *))0, (size_t)0, (dvoid **)0); + + OCIHandleAlloc ((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&authhp, + (ub4)OCI_HTYPE_AUTHINFO, (size_t)0, (dvoid **)0); + + /* Connecting to session 1 */ + idx=0; + + OCIAttrSet ((dvoid *)authhp, (ub4)OCI_HTYPE_AUTHINFO, (dvoid *)username, + (ub4)strlen((char *)username), (ub4)OCI_ATTR_USERNAME, + (OCIError *)errhp); + + OCIAttrSet ((dvoid *)authhp, (ub4)OCI_HTYPE_AUTHINFO, (dvoid *)password, + (ub4)strlen((char *)password), (ub4)OCI_ATTR_PASSWORD, + (OCIError *)errhp); + + Checkerr (errhp, + OCISessionGet ((OCIEnv *)envhp, (OCIError *)errhp, + (OCISvcCtx **)&svchp[idx], (OCIAuthInfo *)authhp, (OraText *)connStr, + (ub4)strlen((char *)connStr), (OraText *)NULL, (ub4)0, (OraText **)0, + (ub4 *)0, (boolean *)0,(ub4)OCI_DEFAULT), + (oratext *)"OCISessionGet"); + + printf ("Connected to Employee Session\n"); + + OCIAttrSet((dvoid *)svchp[idx], OCI_HTYPE_SVCCTX, (dvoid *)&cachesize, + (ub4)0,OCI_ATTR_STMTCACHESIZE,errhp); + + /* Connecting to session 2 */ + idx=1; + + OCIAttrSet ((dvoid *)authhp, (ub4)OCI_HTYPE_AUTHINFO, (dvoid *)username, + (ub4)strlen((char *)username), (ub4)OCI_ATTR_USERNAME, + (OCIError *)errhp); + + OCIAttrSet ((dvoid *)authhp, (ub4)OCI_HTYPE_AUTHINFO, (dvoid *)password, + (ub4)strlen((char *)password), (ub4)OCI_ATTR_PASSWORD, + (OCIError *)errhp); + + Checkerr (errhp, + OCISessionGet ((OCIEnv *)envhp, (OCIError *)errhp, + (OCISvcCtx **)&svchp[idx], (OCIAuthInfo *)authhp, (OraText *)connStr, + (ub4)strlen((char *)connStr), (OraText *)NULL, (ub4)0, (OraText **)0, + (ub4 *)0, (boolean *)0,(ub4)OCI_DEFAULT), + (oratext *)"OCISessionGet"); + + printf ("Connected to HR Session\n\n"); + + OCIAttrSet((dvoid *)svchp[idx], OCI_HTYPE_SVCCTX, (dvoid *)&cachesize, + (ub4)0,OCI_ATTR_STMTCACHESIZE,errhp); +} + +/* - Execute SQL query and prints the data ----------------------------------*/ +static void query_tab (ub4 idx) +{ + OCIStmt *stmthp = (OCIStmt *)0; + OCIDefine *def1hp = (OCIDefine *)0; + OCIDefine *def2hp = (OCIDefine *)0; + OCIDefine *def3hp = (OCIDefine *)0; + ub4 empno; + text ename[100]; + ub4 sal; + sb4 empnoSz = sizeof (empno); + sb4 enameSz = sizeof (ename); + sb4 salSz = sizeof (sal); + ub2 datelen=0; + ub4 prefetch = 0; + + Checkerr (errhp, + OCIStmtPrepare2 ((OCISvcCtx *)svchp[idx],(OCIStmt **)&stmthp, + (OCIError *)errhp, (text *)cache_query, (ub4)strlen((char *)cache_query), + (oratext *)NULL, (ub4) 0, (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT), + (oratext *)"OCIStmtPrepare"); + + /* Setting the prefetch count = 0 */ + Checkerr(errhp, + OCIAttrSet((OCIStmt *) stmthp, OCI_HTYPE_STMT, (dvoid *)&prefetch, + sizeof(prefetch), OCI_ATTR_PREFETCH_ROWS, (OCIError *)errhp), + (oratext *) "OCIAttrSet-prefetch"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def1hp, + (OCIError *)errhp, (ub4)1, (dvoid *)&(empno), (sb4)empnoSz, (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def2hp, + (OCIError *)errhp, (ub4)2, (dvoid *)&(ename), (sb4)enameSz, (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos2"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def3hp, + (OCIError *)errhp, (ub4)3, (dvoid *)&(sal), (sb4)salSz, (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos3"); + + if ((status = OCIStmtExecute ((OCISvcCtx *)svchp[idx], (OCIStmt *)stmthp, + (OCIError *)errhp, (ub4)0, (ub4)0, (OCISnapshot *)0, + (OCISnapshot *)0, (ub4)OCI_DEFAULT)) != OCI_SUCCESS ) + { + printf ("OCIStmtExecute for SELECT - Fail\n" ); + Checkerr (errhp, status,(oratext *)"Stmt Execute"); + } + else + { + do + { + status = OCIStmtFetch2((OCIStmt *)stmthp, (OCIError *)errhp, (ub4)1, + (ub2)OCI_FETCH_NEXT, (sb4)0, (ub4)OCI_DEFAULT); + + if (status == OCI_ERROR || status == OCI_INVALID_HANDLE) + { + Checkerr(errhp, status, (oratext *)"OCIStmtFetch2"); + break; + } + else if (status != OCI_NO_DATA) + { + /* + printf("EMPNO is %d, ENAME is %s, SAL is %d\n", empno, ename, sal); + */ + } + }while(status != OCI_NO_DATA); + } + + Checkerr (errhp, + OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,(dvoid *)NULL, 0, + OCI_DEFAULT), (oratext *)"StmtRelease"); +} + +/* - Execute DML statement --------------------------------------------------*/ +void upd_table(ub4 idx) +{ + OCIStmt *stmthp = (OCIStmt *)0; + + Checkerr (errhp, + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&stmthp, (ub4)OCI_HTYPE_STMT, + (size_t)0, (dvoid **)0), (oratext *)"OCIHandleAlloc"); + + Checkerr (errhp, + OCIStmtPrepare ((OCIStmt *)stmthp, (OCIError *)errhp, (text *)upd_stmt, + (ub4)strlen((char *)upd_stmt), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT), + (oratext *)"OCIStmtPrepare"); + + if (status = OCIStmtExecute ((OCISvcCtx *)svchp[idx], (OCIStmt *)stmthp, + (OCIError *)errhp, (ub4)1, (ub4)0, (OCISnapshot *)0, + (OCISnapshot *)0, (ub4)OCI_COMMIT_ON_SUCCESS)) + { + printf ("OCIStmtExecute update - Fail\n"); + Checkerr (errhp, status,(oratext *)"Stmt Execute Update"); + } + + Checkerr (errhp, + OCIHandleFree ((dvoid *)stmthp, (ub4)OCI_HTYPE_STMT), + (oratext *)"OCIHandleFree"); +} + +/* - Fetches and prints result cache statistics information -----------------*/ +void print_stats() +{ + OCISvcCtx *syssvchp = NULL; + OCIServer *srvhp = NULL; + OCIStmt *stmthp = (OCIStmt *)0; + OCISession *sysauthhp = (OCISession *)0; + OCIDefine *def1hp = (OCIDefine *)0; + OCIDefine *def2hp = (OCIDefine *)0; + OCIDefine *def3hp = (OCIDefine *)0; + OCIDefine *def4hp = (OCIDefine *)0; + ub4 statid; + text name[128]; + ub4 value; + ub4 cacheid; + sb4 statidSz = sizeof(statid); + sb4 nameSz = sizeof (name); + sb4 valueSz= sizeof(value); + sb4 cacheidSz = sizeof(cacheid); + ub4 prefetch = 0; + OraText *connStr = (text *)""; + OraText *sysuser = (text *)"sys"; + OraText syspass[128]; + text *StatQuery= + (text *)"SELECT c1.stat_id, c1.name, c1.value, c1.cache_id \ + FROM client_result_cache_stats$ c1 \ + order by c1.cache_id, c1.stat_id"; + + printf ("Please enter password for sys user to continue:\n"); + scanf ("%s", (char *)syspass); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&srvhp, (ub4)OCI_HTYPE_SERVER, + (size_t)0, (dvoid **)0); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&syssvchp, (ub4)OCI_HTYPE_SVCCTX, + (size_t)0, (dvoid **)0); + + Checkerr (errhp, + OCIServerAttach (srvhp, errhp, (text *)connStr, + (sb4)strlen((char *)connStr), 0), (oratext *)"OCIServerAttach"); + + OCIAttrSet ((dvoid *) syssvchp, OCI_HTYPE_SVCCTX, (dvoid *)srvhp, (ub4) 0, + OCI_ATTR_SERVER, (OCIError *) errhp); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&sysauthhp, + (ub4)OCI_HTYPE_SESSION, (size_t)0, (dvoid **)0); + + OCIAttrSet ((dvoid *)sysauthhp, (ub4)OCI_HTYPE_SESSION, (dvoid *)sysuser, + (ub4)strlen((char *)sysuser), (ub4)OCI_ATTR_USERNAME, + (OCIError *)errhp); + + OCIAttrSet ((dvoid *)sysauthhp, (ub4)OCI_HTYPE_SESSION, (dvoid *)syspass, + (ub4)strlen((char *)syspass), (ub4)OCI_ATTR_PASSWORD, + (OCIError *)errhp); + + /* Connecting to Database as sysdba */ + Checkerr (errhp, + OCISessionBegin (syssvchp, errhp, sysauthhp, OCI_CRED_RDBMS, + (ub4)OCI_SYSDBA), (oratext *)"OCISessionBegin"); + + OCIAttrSet ((dvoid *)syssvchp, OCI_HTYPE_SVCCTX, (dvoid *)sysauthhp, (ub4)0, + OCI_ATTR_SESSION, errhp); + + Checkerr (errhp, + OCIStmtPrepare2 ((OCISvcCtx *)syssvchp,(OCIStmt **)&stmthp, + (OCIError *)errhp, (text *)StatQuery, (ub4)strlen((char *)StatQuery), + (oratext *)NULL, (ub4) 0, (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT), + (oratext *)"OCIStmtPrepare"); + + Checkerr(errhp, + OCIAttrSet((OCIStmt *) stmthp, OCI_HTYPE_STMT, (dvoid *)&prefetch, + sizeof(prefetch), OCI_ATTR_PREFETCH_ROWS, (OCIError *)errhp), + (oratext *) "OCIAttrSet-prefetch"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def2hp, + (OCIError *)errhp, (ub4)1, (dvoid *)&(statid), (sb4)statidSz, + (ub2)SQLT_INT, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def3hp, + (OCIError *)errhp, (ub4)2, (dvoid *)&(name), (sb4)nameSz, (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def4hp, + (OCIError *)errhp, (ub4)3, (dvoid *)&(value), (sb4)valueSz, (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def1hp, + (OCIError *)errhp, (ub4)4, (dvoid *)&(cacheid), (sb4)cacheidSz, + (ub2)SQLT_INT, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos"); + + /* Fetching the data from the stats table */ + if ((status = OCIStmtExecute ((OCISvcCtx *)syssvchp, (OCIStmt *)stmthp, + (OCIError *)errhp, (ub4)0, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, + (ub4)OCI_DEFAULT)) != OCI_SUCCESS ) + { + printf ("OCIStmtExecute for SELECT - Fail\n" ); + Checkerr (errhp, status,(oratext *)"Stmt Execute"); + } + else + { + printf("Contents of CLIENT_RESULT_CACHE_STATS$\n"); + printf("STAT_ID NAME OF STATISTICS VALUE CACHE_ID\n"); + printf("======= ================== ===== ========\n"); + do + { + status = OCIStmtFetch2((OCIStmt *)stmthp, (OCIError *)errhp, (ub4)1, + (ub2)OCI_FETCH_NEXT, (sb4)0, (ub4)OCI_DEFAULT); + + if (status == OCI_ERROR || status == OCI_INVALID_HANDLE) + { + Checkerr(errhp, status, (oratext *)"OCIStmtFetch2"); + break; + } + else if (status != OCI_NO_DATA) + { + printf("%5d %-20s %8d %6d\n", statid, name, value, cacheid); + } + }while(status != OCI_NO_DATA); + + } + + Checkerr (errhp, + OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,(dvoid *)NULL, 0, + OCI_DEFAULT), (oratext *)"StmtRelease"); + + Checkerr (errhp, + OCISessionEnd (syssvchp, errhp, sysauthhp, OCI_DEFAULT), + (oratext *) "Session-End"); + + Checkerr (errhp, + OCIServerDetach (srvhp, errhp, OCI_DEFAULT), + (oratext *) "Server-detach"); + + OCIHandleFree((dvoid *)sysauthhp, OCI_HTYPE_SESSION); + OCIHandleFree((dvoid *)syssvchp, OCI_HTYPE_SVCCTX); + OCIHandleFree((dvoid *)srvhp, OCI_HTYPE_SERVER); +} + +/* - Session Logoff --------------------------------------------------------*/ +static void dbLogoff () +{ + int idx; + + printf ("\nLogging off all the connected sessions.\n"); + + for (idx=0; idx<2; idx++) + Checkerr (errhp, + OCISessionRelease(svchp[idx], errhp, 0,0, OCI_DEFAULT), + (oratext *) "Session-Release"); + + OCIHandleFree((dvoid *)authhp, OCI_HTYPE_AUTHINFO); + OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR); +} + +/* - Error checking routing -------------------------------------------------*/ +void Checkerr(OCIError *errhp, sword status, text *msg) +{ + text msgbuf[512]; + sb4 errcode = 0; + + memset((void *) msgbuf, (int)'\0', (size_t)512); + if(status!=OCI_SUCCESS) + { + printf("error msg: %s\n",msg); + } + + switch (status) + { + case OCI_SUCCESS: break; + case OCI_SUCCESS_WITH_INFO: + printf("status = OCI_SUCCESS_WITH_INFO\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_NEED_DATA: + printf("status = OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("status = OCI_NO_DATA\n"); + break; + case OCI_ERROR: + printf("status = OCI_ERROR\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_INVALID_HANDLE: + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + printf("status = OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("status = OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("status = OCI_CONTINUE\n"); + break; + default: + break; + } + return; +} diff --git a/cdemoqc.sql b/cdemoqc.sql new file mode 100644 index 0000000..015c4f5 --- /dev/null +++ b/cdemoqc.sql @@ -0,0 +1,53 @@ +Rem +Rem $Header: rdbms/demo/cdemoqc.sql /main/3 2008/10/23 23:36:35 dgopal Exp $ +Rem +Rem cdemoqc.sql +Rem +Rem Copyright (c) 2007, 2008, Oracle and/or its affiliates. +Rem All rights reserved. +Rem +Rem NAME +Rem cdemoqc.sql +Rem +Rem DESCRIPTION +Rem Creates schema for query cache OCI demo cdemoqc.c +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem dgopal 10/10/08 - Added a new table from cdemoqc2.c +Rem dgopal 12/19/07 - Modified schema +Rem dgopal 05/10/07 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +CONNECT system/manager +GRANT CONNECT, RESOURCE TO ocitest IDENTIFIED BY ocitest; + +CONNECT ocitest/ocitest + +DROP TABLE qctable; +DROP TABLE ssntable; + +CREATE TABLE qctable (empno NUMBER, ename VARCHAR2(20), sal NUMBER); +CREATE TABLE ssntable (ssn NUMBER, empno NUMBER); + +CREATE OR REPLACE PROCEDURE insert_val +AS BEGIN +for i in 1..1000 loop + INSERT INTO qctable VALUES (i, 'EMP_'||i, i*100); + INSERT INTO ssntable VALUES (56345000+i, i); +end loop; +end; +/ +EXECUTE insert_val; + +COMMIT; diff --git a/cdemoqc2.c b/cdemoqc2.c new file mode 100644 index 0000000..495926e --- /dev/null +++ b/cdemoqc2.c @@ -0,0 +1,619 @@ +/* Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. */ + +/* + NAME + cdemoqc2 - OCI Query Cache(result cache) table annotation functionality + + DESCRIPTION + For using client result cache, result_cache hint not necessarily needs to + be used in query. If the table is created/altered with result_cache mode + FORCE, cache will be enabled by default and it will be used even if + result_cache hint is not used in the query. If result_cache mode is not + mentioned while creating table, the default mode is DEFAULT. In this case, + cache will be used only when result_cache hint is used in the query. + + Note that even when the result_cache mode is specified as FORCE, caching + will be enabled only for those queries which are cache worthy. + + In the below table, + rows -> represent the result_cache hint usage in the query + columns -> represent, the mode with which table was created + YES -> represents result cache will be used + NO -> represents result cache will not be used + + ----------------------------------------------- + | | DEFAULT MODE | FORCE MODE | + ----------------------------------------------- + | No Hint used | NO | YES | + | result_cache | YES | YES | + | no_result_cache | NO | NO | + ----------------------------------------------- + + NOTE: + To use the query cache feature (and hence this program), database should + have been brought up with client side result cache enabled. To bring the + database with result cache enabled, add the following lines in + initialization parameter file, + client_result_cache_size= + client_result_cache_lag= + compatible=11.0.0.0.0 + and bring up the database. + + MODIFIED (MM/DD/YY) + dgopal 10/10/08 - Created + +*/ + +#include + +#include +#include +#include + +#define NO_HINT 0 +#define CACHE_HINT 1 +#define NO_CACHE_HINT 2 + +#define FORCE_MODE 0 +#define DEFAULT_MODE 1 + +#define USER_TABLES 0 +#define ALL_TABLES 1 +#define DBA_TABLES 2 + +/* Function prototypes */ +static void query_emp(int idx); +static void query_ssn(int idx); +static void alt_table(int idx); +static void print_stats(int idx); +static void dbLogon(); +static void dbLogoff(); +static void Checkerr(OCIError *errhp, sword status, text *msg); + +int main(); + +static sword status = 0; +static OCISvcCtx *svchp; +static OCIError *errhp; +static OCIEnv *envhp; +static OCIAuthInfo *authhp; + +/* Queries from qctable */ +static text *query_emp_stmt[]={ +(text *)"SELECT empno, ename, sal FROM qctable", +(text *)"SELECT /*+ result_cache */ empno, ename, sal FROM qctable", +(text *)"SELECT /*+ no_result_cache */ empno, ename, sal FROM qctable" +}; + +/* Queries from ssntable */ +static text *query_ssn_stmt[]={ +(text *)"SELECT ssn, empno FROM ssntable", +(text *)"SELECT /*+ result_cache */ ssn, empno FROM ssntable", +(text *)"SELECT /*+ no_result_cache */ ssn, empno FROM ssntable" +}; + +/* Alter table statements with result_cache annotations */ +static text *alt_stmt[]={ +(text *)"ALTER TABLE ssntable RESULT_CACHE (MODE FORCE)", +(text *)"ALTER TABLE qctable RESULT_CACHE (MODE DEFAULT)" +}; + +/* Table can also be created with result_cache annotations. +(e.g.) +1. CREATE TABLE ssntable(ssn NUMBER, empno NUMBER) RESULT_CACHE (MODE FORCE) +2. CREATE TABLE qctable(empno NUMBER, ename VARCHAR2(20), sal NUMBER) RESULT_CACHE (MODE DEFAULT) +*/ + +/* - main -------------------------------------------------------------------*/ +int main () +{ + printf ("Executing table annotation demo - cdemoqc2\n\n"); + + /* Logging on to the database */ + dbLogon (); + + /* + Table was created by the cdemoqc.sql script without any result_cache mode + parameter. In this case caching will happen only when RESULT_CACHE sql + hint is used in the query. + */ + printf ("\nQuerying qctable which was created without specifying any " + "result_cache mode\n"); + printf ("Execute query with result_cache hint in query\n"); + query_emp(CACHE_HINT); + printf ("Re-execute would fetch from local cache\n"); + query_emp(CACHE_HINT); + + /* + If table RESULT_CACHE (MODE FORCE) is specified in CREATE or ALTER TABLE + statement caching will be used even if RESULT_CACHE sql hint is not + specified in query. However NO_RESULT_CACHE sql hint can be used to + explicitily disable caching. + + This FORCE MODE can be specified for the table which hardly gets updated. + */ + printf ("\nAltering ssntable with RESULT_CACHE (MODE FORCE)\n"); + alt_table(FORCE_MODE); + printf ("Execute would create local client cache even if no hint is " + "specified in query\n"); + query_ssn(NO_HINT); + printf ("Re-execute would fetch from local cache\n"); + query_ssn(NO_HINT); + + printf ("Even if the table is created with RESULT_CACHE MODE FORCE, execute " + "will not \n cache the results if NO_RESULT_CACHE is specified in " + "query\n"); + query_ssn(NO_CACHE_HINT); + printf ("Re-execute would fetch from the server\n"); + query_ssn(NO_CACHE_HINT); + + /* + Creating or altering table with RESULT_CACHE (MODE DEFAULT) is as good as + having table without any RESULT_CACHE hint. In this case caching will be + done only when RESULT_CACHE sql hint is used in the query. + */ + printf ("\nAltering qctable with RESULT_CACHE (MODE DEFAULT)\n"); + alt_table(DEFAULT_MODE); + printf ("Execute query without any result_cache hint in query\n"); + query_emp(NO_HINT); + printf ("Re-execute would fetch from the server\n"); + query_emp(NO_HINT); + + printf ("Execute query with sql result_cache hint\n"); + query_emp(CACHE_HINT); + printf ("Re-execute would fetch from local cache\n"); + query_emp(CACHE_HINT); + + printf("\nRESULT_CACHE parameter from USER_TABLES,\n"); + print_stats(USER_TABLES); + printf("\nRESULT_CACHE parameter from ALL_TABLES,\n"); + print_stats(ALL_TABLES); + /* + For quering DBA_TABLES, user needs to login as SYSDBA. Hence if you + uncomment this call, the program will prompt for sys user password. scanf() + has been used for fetching the password from user and you may want to + replace it with your platform specific function to hide the echoing of + password. + */ + /* + printf("\nRESULT_CACHE parameter from ALL_TABLES,\n"); + print_stats(DBA_TABLES); + */ + + dbLogoff (); + return 0; +} + +/* - Logon to the DB --------------------------------------------------------*/ +static void dbLogon () +{ + ub4 cachesize=10; + OraText *connStr = (text *)""; + OraText *username = (text *)"ocitest"; + OraText *password = (text *)"ocitest"; + + OCIEnvCreate ((OCIEnv **)&envhp, (ub4)OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t))0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *))0, (size_t)0, (dvoid **)0); + + OCIHandleAlloc ((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&authhp, + (ub4)OCI_HTYPE_AUTHINFO, (size_t)0, (dvoid **)0); + + /* Connecting to database */ + + OCIAttrSet ((dvoid *)authhp, (ub4)OCI_HTYPE_AUTHINFO, (dvoid *)username, + (ub4)strlen((char *)username), (ub4)OCI_ATTR_USERNAME, + (OCIError *)errhp); + + OCIAttrSet ((dvoid *)authhp, (ub4)OCI_HTYPE_AUTHINFO, (dvoid *)password, + (ub4)strlen((char *)password), (ub4)OCI_ATTR_PASSWORD, + (OCIError *)errhp); + + Checkerr (errhp, + OCISessionGet ((OCIEnv *)envhp, (OCIError *)errhp, + (OCISvcCtx **)&svchp, (OCIAuthInfo *)authhp, (OraText *)connStr, + (ub4)strlen((char *)connStr), (OraText *)NULL, (ub4)0, (OraText **)0, + (ub4 *)0, (boolean *)0,(ub4)OCI_DEFAULT), + (oratext *)"OCISessionGet"); + + printf ("Connected to Database Session\n"); + + OCIAttrSet((dvoid *)svchp, OCI_HTYPE_SVCCTX, (dvoid *)&cachesize, + (ub4)0,OCI_ATTR_STMTCACHESIZE,errhp); +} + +/* - Execute SQL query (from qctable) ---------------------------------------*/ +static void query_emp (int idx) +{ + OCIStmt *stmthp = (OCIStmt *)0; + OCIDefine *def1hp = (OCIDefine *)0; + OCIDefine *def2hp = (OCIDefine *)0; + OCIDefine *def3hp = (OCIDefine *)0; + ub4 empno; + text ename[100]; + ub4 sal; + sb4 empnoSz = sizeof (empno); + sb4 enameSz = sizeof (ename); + sb4 salSz = sizeof (sal); + ub4 prefetch = 0; + + Checkerr (errhp, + OCIStmtPrepare2 ((OCISvcCtx *)svchp,(OCIStmt **)&stmthp, (OCIError *)errhp, + (text *)query_emp_stmt[idx], (ub4)strlen((char *)query_emp_stmt[idx]), + (oratext *)NULL, (ub4) 0, (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT), + (oratext *)"OCIStmtPrepare-emp"); + + /* Setting the prefetch count = 0 */ + Checkerr(errhp, + OCIAttrSet((OCIStmt *) stmthp, OCI_HTYPE_STMT, (dvoid *)&prefetch, + sizeof(prefetch), OCI_ATTR_PREFETCH_ROWS, (OCIError *)errhp), + (oratext *) "OCIAttrSet-prefetch-emp"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def1hp, + (OCIError *)errhp, (ub4)1, (dvoid *)&(empno), (sb4)empnoSz, (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos-emp"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def2hp, + (OCIError *)errhp, (ub4)2, (dvoid *)&(ename), (sb4)enameSz, (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos2-emp"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def3hp, + (OCIError *)errhp, (ub4)3, (dvoid *)&(sal), (sb4)salSz, (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos3-emp"); + + if ((status = OCIStmtExecute ((OCISvcCtx *)svchp, (OCIStmt *)stmthp, + (OCIError *)errhp, (ub4)0, (ub4)0, (OCISnapshot *)0, + (OCISnapshot *)0, (ub4)OCI_DEFAULT)) != OCI_SUCCESS ) + { + printf ("OCIStmtExecute for SELECT - Fail\n" ); + Checkerr (errhp, status,(oratext *)"Stmt Execute-emp"); + } + else + { + do + { + status = OCIStmtFetch2((OCIStmt *)stmthp, (OCIError *)errhp, (ub4)1, + (ub2)OCI_FETCH_NEXT, (sb4)0, (ub4)OCI_DEFAULT); + + if (status == OCI_ERROR || status == OCI_INVALID_HANDLE) + { + Checkerr(errhp, status, (oratext *)"OCIStmtFetch2-emp"); + break; + } + else if (status != OCI_NO_DATA) + { + /* + printf("EMPNO is %d, ENAME is %s, SAL is %d\n", empno, ename, sal); + */ + } + }while(status != OCI_NO_DATA); + } + + Checkerr (errhp, + OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,(dvoid *)NULL, 0, + OCI_DEFAULT), (oratext *)"StmtRelease-emp"); +} + +/* - Execute SQL query (from ssntable) --------------------------------------*/ +static void query_ssn (int idx) +{ + OCIStmt *stmthp = (OCIStmt *)0; + OCIDefine *def1hp = (OCIDefine *)0; + OCIDefine *def2hp = (OCIDefine *)0; + ub4 ssn; + ub4 empno; + sb4 ssnSz = sizeof (ssn); + sb4 empnoSz = sizeof (empno); + ub4 prefetch = 0; + + Checkerr (errhp, + OCIStmtPrepare2 ((OCISvcCtx *)svchp,(OCIStmt **)&stmthp, (OCIError *)errhp, + (text *)query_ssn_stmt[idx], (ub4)strlen((char *)query_ssn_stmt[idx]), + (oratext *)NULL, (ub4) 0, (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT), + (oratext *)"OCIStmtPrepare-ssn"); + + /* Setting the prefetch count = 0 */ + Checkerr(errhp, + OCIAttrSet((OCIStmt *) stmthp, OCI_HTYPE_STMT, (dvoid *)&prefetch, + sizeof(prefetch), OCI_ATTR_PREFETCH_ROWS, (OCIError *)errhp), + (oratext *) "OCIAttrSet-prefetch-ssn"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def1hp, + (OCIError *)errhp, (ub4)1, (dvoid *)&(ssn), (sb4)ssnSz, (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos1-ssn"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def2hp, + (OCIError *)errhp, (ub4)2, (dvoid *)&(empno), (sb4)empnoSz, (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos2-ssn"); + + if ((status = OCIStmtExecute ((OCISvcCtx *)svchp, (OCIStmt *)stmthp, + (OCIError *)errhp, (ub4)0, (ub4)0, (OCISnapshot *)0, + (OCISnapshot *)0, (ub4)OCI_DEFAULT)) != OCI_SUCCESS ) + { + printf ("OCIStmtExecute for SELECT - Fail\n" ); + Checkerr (errhp, status,(oratext *)"Stmt Execute-ssn"); + } + else + { + do + { + status = OCIStmtFetch2((OCIStmt *)stmthp, (OCIError *)errhp, (ub4)1, + (ub2)OCI_FETCH_NEXT, (sb4)0, (ub4)OCI_DEFAULT); + + if (status == OCI_ERROR || status == OCI_INVALID_HANDLE) + { + Checkerr(errhp, status, (oratext *)"OCIStmtFetch2-ssn"); + break; + } + else if (status != OCI_NO_DATA) + { + /* + printf("SSN is %d, EMPNO is %d\n", ssn, empno); + */ + } + }while(status != OCI_NO_DATA); + } + + Checkerr (errhp, + OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,(dvoid *)NULL, 0, + OCI_DEFAULT), (oratext *)"StmtRelease-ssn"); +} + +/* - Execute alter result_cache mode statement ------------------------------*/ +void alt_table(int idx) +{ + OCIStmt *stmthp = (OCIStmt *)0; + + Checkerr (errhp, + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&stmthp, (ub4)OCI_HTYPE_STMT, + (size_t)0, (dvoid **)0), (oratext *)"OCIHandleAlloc-ddl"); + + Checkerr (errhp, + OCIStmtPrepare ((OCIStmt *)stmthp, (OCIError *)errhp, (text *)alt_stmt[idx], + (ub4)strlen((char *)alt_stmt[idx]), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT), + (oratext *)"OCIStmtPrepare-ddl"); + + if (status = OCIStmtExecute ((OCISvcCtx *)svchp, (OCIStmt *)stmthp, + (OCIError *)errhp, (ub4)1, (ub4)0, (OCISnapshot *)0, + (OCISnapshot *)0, (ub4)OCI_COMMIT_ON_SUCCESS)) + { + printf ("OCIStmtExecute update - Fail\n"); + Checkerr (errhp, status,(oratext *)"Stmt Execute Update-ddl"); + } + + Checkerr (errhp, + OCIHandleFree ((dvoid *)stmthp, (ub4)OCI_HTYPE_STMT), + (oratext *)"OCIHandleFree-ddl"); +} + +/* - Fetches and prints result cache statistics information -----------------*/ +void print_stats(int idx) +{ + OCISvcCtx *statsvchp = NULL; + OCIServer *srvhp = NULL; + OCIStmt *stmthp = (OCIStmt *)0; + OCISession *sysauthhp = (OCISession *)0; + OCIDefine *def1hp = (OCIDefine *)0; + OCIDefine *def2hp = (OCIDefine *)0; + text tablename[128]; + text cacheusage[128]; + sb4 tablenameSz = sizeof (tablename); + sb4 cacheusageSz = sizeof (cacheusage); + ub4 prefetch = 0; + OraText *connStr = (text *)""; + OraText *sysuser = (text *)"sys"; + OraText syspass[128]; + text StatQuery[128]; + + /* For querying from USER_TABLES */ + if (idx==USER_TABLES) + { + strcpy ((char *)StatQuery, "SELECT table_name, result_cache FROM user_tables WHERE table_name='QCTABLE' OR table_name='SSNTABLE' ORDER BY table_name"); + statsvchp=svchp; + } + /* For querying from ALL_TABLES */ + else if (idx=ALL_TABLES) + { + strcpy ((char *)StatQuery, "SELECT table_name, result_cache FROM all_tables WHERE table_name='QCTABLE' OR table_name='SSNTABLE' ORDER BY table_name"); + statsvchp=svchp; + } + /* For querying from DBA_TABLES */ + else if (idx==DBA_TABLES) + { + strcpy ((char *)StatQuery, "SELECT table_name, result_cache FROM dba_tables WHERE table_name='QCTABLE' OR table_name='SSNTABLE' ORDER BY table_name"); + + /* To access DBA_TABLES sysdba perviledge is required */ + printf ("\nPlease enter password for sys user to continue:\n"); + scanf ("%s", (char *)syspass); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&srvhp, (ub4)OCI_HTYPE_SERVER, + (size_t)0, (dvoid **)0); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&statsvchp, (ub4)OCI_HTYPE_SVCCTX, + (size_t)0, (dvoid **)0); + + Checkerr (errhp, + OCIServerAttach (srvhp, errhp, (text *)connStr, + (sb4)strlen((char *)connStr), 0), (oratext *)"OCIServerAttach-stat"); + + OCIAttrSet ((dvoid *) statsvchp, OCI_HTYPE_SVCCTX, (dvoid *)srvhp, (ub4) 0, + OCI_ATTR_SERVER, (OCIError *) errhp); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&sysauthhp, + (ub4)OCI_HTYPE_SESSION, (size_t)0, (dvoid **)0); + + OCIAttrSet ((dvoid *)sysauthhp, (ub4)OCI_HTYPE_SESSION, (dvoid *)sysuser, + (ub4)strlen((char *)sysuser), (ub4)OCI_ATTR_USERNAME, + (OCIError *)errhp); + + OCIAttrSet ((dvoid *)sysauthhp, (ub4)OCI_HTYPE_SESSION, (dvoid *)syspass, + (ub4)strlen((char *)syspass), (ub4)OCI_ATTR_PASSWORD, + (OCIError *)errhp); + + /* Connecting to Database as sysdba */ + Checkerr (errhp, + OCISessionBegin (statsvchp, errhp, sysauthhp, OCI_CRED_RDBMS, + (ub4)OCI_SYSDBA), (oratext *)"OCISessionBegin-stat"); + + OCIAttrSet ((dvoid *)statsvchp, OCI_HTYPE_SVCCTX, (dvoid *)sysauthhp, (ub4)0, + OCI_ATTR_SESSION, errhp); + } + + Checkerr (errhp, + OCIStmtPrepare2 ((OCISvcCtx *)statsvchp,(OCIStmt **)&stmthp, + (OCIError *)errhp, (text *)StatQuery, (ub4)strlen((char *)StatQuery), + (oratext *)NULL, (ub4) 0, (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT), + (oratext *)"OCIStmtPrepare-stat"); + + Checkerr(errhp, + OCIAttrSet((OCIStmt *) stmthp, OCI_HTYPE_STMT, (dvoid *)&prefetch, + sizeof(prefetch), OCI_ATTR_PREFETCH_ROWS, (OCIError *)errhp), + (oratext *) "OCIAttrSet-prefetch-stat"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def1hp, + (OCIError *)errhp, (ub4)1, (dvoid *)&(tablename), (sb4)tablenameSz, + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos-stat"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def2hp, + (OCIError *)errhp, (ub4)2, (dvoid *)&(cacheusage), (sb4)cacheusageSz, + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos2-stat"); + + /* Fetching the data from the stats table */ + if ((status = OCIStmtExecute ((OCISvcCtx *)statsvchp, (OCIStmt *)stmthp, + (OCIError *)errhp, (ub4)0, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, + (ub4)OCI_DEFAULT)) != OCI_SUCCESS ) + { + printf ("OCIStmtExecute for SELECT - Fail\n" ); + Checkerr (errhp, status,(oratext *)"Stmt Execute-stat"); + } + else + { + printf("TABLE_NAME RESULT_CACHE\n"); + printf("========== ============\n"); + do + { + status = OCIStmtFetch2((OCIStmt *)stmthp, (OCIError *)errhp, (ub4)1, + (ub2)OCI_FETCH_NEXT, (sb4)0, (ub4)OCI_DEFAULT); + + if (status == OCI_ERROR || status == OCI_INVALID_HANDLE) + { + Checkerr(errhp, status, (oratext *)"OCIStmtFetch2-stat"); + break; + } + else if (status != OCI_NO_DATA) + { + printf("%-15s %-15s\n", tablename, cacheusage); + } + }while(status != OCI_NO_DATA); + } + + Checkerr (errhp, + OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,(dvoid *)NULL, 0, + OCI_DEFAULT), (oratext *)"StmtRelease-stat"); + + /* If sysdba session is created, terminate it */ + if (idx==DBA_TABLES) + { + Checkerr (errhp, + OCISessionEnd (statsvchp, errhp, sysauthhp, OCI_DEFAULT), + (oratext *) "Session-End-stat"); + + Checkerr (errhp, + OCIServerDetach (srvhp, errhp, OCI_DEFAULT), + (oratext *) "Server-detach-stat"); + + OCIHandleFree((dvoid *)sysauthhp, OCI_HTYPE_SESSION); + OCIHandleFree((dvoid *)statsvchp, OCI_HTYPE_SVCCTX); + OCIHandleFree((dvoid *)srvhp, OCI_HTYPE_SERVER); + } +} + +/* - Session Logoff --------------------------------------------------------*/ +static void dbLogoff () +{ + printf ("\nLogging off from the connected session.\n"); + + Checkerr (errhp, + OCISessionRelease(svchp, errhp, 0,0, OCI_DEFAULT), + (oratext *) "Session-Release"); + + OCIHandleFree((dvoid *)authhp, OCI_HTYPE_AUTHINFO); + OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR); +} + +/* - Error checking routing -------------------------------------------------*/ +void Checkerr(OCIError *errhp, sword status, text *msg) +{ + text msgbuf[512]; + sb4 errcode = 0; + + memset((void *) msgbuf, (int)'\0', (size_t)512); + if(status!=OCI_SUCCESS) + { + printf("error msg: %s\n",msg); + } + + switch (status) + { + case OCI_SUCCESS: break; + case OCI_SUCCESS_WITH_INFO: + printf("status = OCI_SUCCESS_WITH_INFO\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_NEED_DATA: + printf("status = OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("status = OCI_NO_DATA\n"); + break; + case OCI_ERROR: + printf("status = OCI_ERROR\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_INVALID_HANDLE: + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + printf("status = OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("status = OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("status = OCI_CONTINUE\n"); + break; + default: + break; + } + return; +} diff --git a/cdemorid.c b/cdemorid.c new file mode 100644 index 0000000..5bae213 --- /dev/null +++ b/cdemorid.c @@ -0,0 +1,517 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemorid.c 14-jul-99.13:15:16 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemorid - example of array DML and fetches using prefetch + example of getting multiple rowids in one roundtrip + + + DESCRIPTION + test retrieves ROWIDs from table and use it for a subsequent + UPDATE. 2 roundtrips, one to get all the rowids, and another to update it + Does not require use of ROWID psuedo column in the text of the SQL. + Uses OCI_COMMIT_ON_SUCCESS to cut down a roundtrip to commit the update. + + NOTES + The ROWID used for INSERT, UPDATE, or DELETE must be obtained + through a SELECT ... FOR UPDATE ... statement, not through a + simple SELECT statement, using OCIGetAttr. Prefetching must be used. + Not compatible with pre 8i servers. + + Please run cdemorid.sql before this. + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + dchatter 10/16/98 - Creating new demo for select for update and update + using rowids in two roundtrips. + dchatter 10/16/98 - Creation + + + +*/ + +/*------------------------Inclusions-------------------------------*/ + +#ifndef CDEMORID +#include +#endif + +static boolean logged_on = FALSE; + + +static ub4 ridlen = 0; /* for the one obtained from RDD */ +static ub4 i; + +/*------------------------end of Inclusions-----------------------------*/ + +int main(argc, argv) +int argc; +char *argv[]; +{ + text *username = (text *)"CDEMORID"; + text *password = (text *)"CDEMORID"; + + OCIEnv *envhp; + OCISvcCtx *svchp; + OCIError *errhp; + OCIRowid *Rowid[MAXROWS]; + OCIStmt *select_p, *update_p; + + /* + * Initialize the handles for the program + */ + + if (init_handles(&envhp, &errhp, (ub4)OCI_DEFAULT)) + { + printf("FAILED: init_handles()\n"); + return cleanup(logged_on, envhp, svchp, errhp); + } + + /* + * Connect and create an user session + */ + + if (OCILogon(envhp, errhp, &svchp, username, strlen (username), + password, strlen (password), "", 0)) + { + printf("FAILED: log_on()\n"); + return cleanup(logged_on, envhp, svchp, errhp); + } + + logged_on = TRUE; + + /* allocate the statement handles for Select and Update */ + + if (OCIHandleAlloc((dvoid *)envhp, (dvoid **) &select_p, + (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0) + || OCIHandleAlloc((dvoid *)envhp, (dvoid **) &update_p, + (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0)) + { + printf("FAILED: alloc statement handles\n"); + return cleanup(logged_on, envhp, svchp, errhp); + } + + for (i = 0; i < MAXROWS; i++) + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &(Rowid[i]), + (ub4) OCI_DTYPE_ROWID, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIDescriptorAlloc()\n"); + return cleanup(logged_on, envhp, svchp, errhp); + } + + + /* + * First we select all the rows that are to be updated. + * There are five rows that satisfy the example query and we get all the five + * rows in one roundtrip since prefetch count is 10. + */ + if (get_all_rows(svchp, errhp, select_p, Rowid)) + { + printf("Fetch of all rowids failed\n"); + return cleanup(logged_on, envhp, svchp, errhp); + } + + /* + * We update five rows in one roundtrip by binding an array of rowids fetched + * in the previous functions. + * We also commit in the same roundtrip. + * We do another roundtrip to fetch the updated rows for display although we + * could have used the returning clause to even cut that roundtrip. See + * cdemodr.c for details on how to use DML returning. + */ + + if (update_all_rows(svchp, errhp, update_p, select_p, Rowid)) + { + printf("Update of all rows failed\n"); + return cleanup(logged_on, envhp, svchp, errhp); + } + + return cleanup(logged_on, envhp, svchp, errhp); +} + + +/* ----------------------------------------------------------------- */ +/* initialize environment, allocate handles */ +/* ----------------------------------------------------------------- */ +sword init_handles(envhp, errhp, init_mode) +OCIEnv **envhp; +OCIError **errhp; +ub4 init_mode; +{ + printf("Environment setup ....\n"); + + if (OCIInitialize(init_mode, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + if (OCIEnvInit((OCIEnv **) envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on errhp\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/*---------------------------------------------------------------------* + * cleanup() + * disconnects and cleans up the allocated memory + *---------------------------------------------------------------------*/ + +sword cleanup(loggedon, envhp, svchp, errhp) +boolean loggedon; +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIError *errhp; +{ + + report_error(errhp); + + if (loggedon) + OCILogoff (svchp, errhp); + + printf("Freeing handles ...\n"); + + if (envhp) + OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV); + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +void report_error(errhp) +OCIError *errhp; +{ + text msgbuf[512]; + sb4 errcode = 0; + + memset((void *) msgbuf, (int)'\0', (size_t)512); + + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + if (errcode) + { + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + exit(1); + } + +} + +/* ----------------------------------------------------------------- */ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + switch (status) + { + case OCI_SUCCESS: break; + case OCI_SUCCESS_WITH_INFO: + printf("status = OCI_SUCCESS_WITH_INFO\n"); + report_error(errhp); + break; + case OCI_NEED_DATA: + printf("status = OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("status = OCI_NO_DATA\n"); + break; + case OCI_ERROR: + printf("status = OCI_ERROR\n"); + report_error(errhp); + break; + case OCI_INVALID_HANDLE: + printf("status = OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("status = OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("status = OCI_CONTINUE\n"); + break; + default: + break; + } +} + +sword get_all_rows(svchp, errhp, select_p, Rowid) +OCISvcCtx *svchp; +OCIError *errhp; +OCIStmt *select_p; +OCIRowid **Rowid; + +{ + + + text *mySql = (text *) "SELECT C1, C2 from FOO where C1 > 15 for UPDATE"; + ub4 prefetch = 10; + sword errr; + ub4 c1; + text c2[30]; + OCIDefine *defnp1, *defnp2; + + /* prepare the select statement for fetching all rows */ + + if (OCIStmtPrepare (select_p, errhp, + mySql, strlen(mySql), OCI_NTV_SYNTAX, OCI_DEFAULT)) + { + printf ("Prepare failed \n"); + return (OCI_ERROR); + } + + /* + * since we are interested in all the rows lets set prefetch to 10 + * before execute + */ + + + if (OCIAttrSet (select_p, + OCI_HTYPE_STMT, + &prefetch, /* prefetch upto 10 rows */ + 0, + OCI_ATTR_PREFETCH_ROWS, + errhp)) + { + printf ("Setting the prefetch count failed \n"); + return (OCI_ERROR); + } + + + if (errr = OCIStmtExecute(svchp, + select_p, + errhp, + (ub4) 0, + (ub4) 0, + (OCISnapshot *) NULL, + (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)) + { + if (errr != OCI_NO_DATA) return errr; + + } + + + /* + * now fetch all the rows. + * we will just define one piece of storage each for the columns and get the + * data into it since we really do not care for the column data. + * after each fetch we will retrieve the rowid of the fetched row. + */ + + if (OCIDefineByPos ( select_p, + &defnp1, + errhp, + 1, + &c1, + sizeof (c1), + SQLT_INT, + (dvoid *) 0, + (dvoid *) 0, + (dvoid *) 0, + OCI_DEFAULT) || + OCIDefineByPos ( select_p, + &defnp2, + errhp, + 2, + &c2, + 30, + SQLT_STR, + (dvoid *) 0, + (dvoid *) 0, + (dvoid *) 0, + OCI_DEFAULT)) + { + printf ("Failed to define\n"); + return (OCI_ERROR); + } + + printf ("Column C1 Column C2\n"); + printf ("_______________________\n"); + + for (i = 0; i < MAXROWS; i++) + { + if (OCIStmtFetch (select_p, + errhp, + 1, + OCI_FETCH_NEXT, + OCI_DEFAULT)) + { + printf ("Fetch failed \n"); + return (OCI_ERROR); + } + + printf ("%d %s\n", c1, c2); + + if (OCIAttrGet (select_p, + OCI_HTYPE_STMT, + Rowid[i], /* get the current rowid */ + 0, + OCI_ATTR_ROWID, + errhp)) + { + printf ("Getting the Rowid failed \n"); + return (OCI_ERROR); + } + + } + + return OCI_SUCCESS; +} + + +sword update_all_rows(svchp, errhp, update_p, select_p, Rowid) +OCISvcCtx *svchp; +OCIError *errhp; +OCIStmt *update_p; +OCIStmt *select_p; +OCIRowid **Rowid; + +{ + + + text *mySql = (text *) "UPDATE FOO set c1 = c1 - 1 where rowid = :a"; + ub4 prefetch = 10; + sword errr; + ub4 c1; + text c2[30]; + OCIBind *bndhp; + OCIDefine *defnp1, + *defnp2; + + /* prepare the select statement for fetching all rows */ + + if (OCIStmtPrepare (update_p, errhp, + mySql, strlen(mySql), OCI_NTV_SYNTAX, OCI_DEFAULT)) + { + printf ("Prepare failed \n"); + return (OCI_ERROR); + } + + if (OCIBindByPos ( update_p, + &bndhp, + errhp, + 1, + &Rowid[0], + sizeof(OCIRowid *), + SQLT_RDD, + (ub2 *) 0, + (ub2 *) 0, + (ub4) 0, + (ub4) 0, + (ub4 *) 0, + (ub4) OCI_DEFAULT)) + { + printf ("Bind failed \n"); + return (OCI_ERROR); + } + + if (errr = OCIStmtExecute(svchp, + update_p, + errhp, + (ub4) MAXROWS, + (ub4) 0, + (OCISnapshot *) NULL, + (OCISnapshot *) NULL, + (ub4) OCI_COMMIT_ON_SUCCESS)) + { + printf ("Update failed \n"); + return (OCI_ERROR); + } + + + /* + * now fetch all the rows for display. + * we will just define one piece of storage each for the columns and get the + * data into it since we really do not care for the column data. + */ + + if (errr = OCIStmtExecute(svchp, + select_p, + errhp, + (ub4) 0, + (ub4) 0, + (OCISnapshot *) NULL, + (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)) + { + if (errr != OCI_NO_DATA) return errr; + + } + + if (OCIDefineByPos ( select_p, + &defnp1, + errhp, + 1, + &c1, + sizeof (c1), + SQLT_INT, + (dvoid *) 0, + (dvoid *) 0, + (dvoid *) 0, + OCI_DEFAULT) || + OCIDefineByPos ( select_p, + &defnp2, + errhp, + 2, + &c2, + 30, + SQLT_STR, + (dvoid *) 0, + (dvoid *) 0, + (dvoid *) 0, + OCI_DEFAULT)) + { + printf ("Failed to define\n"); + return (OCI_ERROR); + } + + + printf ("after UPDATE\n"); + printf ("Column C1 Column C2\n"); + printf ("_______________________\n"); + + + for (i = 0; i < MAXROWS; i++) + { + if (OCIStmtFetch (select_p, + errhp, + 1, + OCI_FETCH_NEXT, + OCI_DEFAULT)) + { + printf ("Fetch failed \n"); + return (OCI_ERROR); + } + + printf ("%d %s\n", c1, c2); + + } + + return OCI_SUCCESS; +} + + +/* end of file cdemorid.c */ + + diff --git a/cdemorid.h b/cdemorid.h new file mode 100644 index 0000000..70472cd --- /dev/null +++ b/cdemorid.h @@ -0,0 +1,105 @@ +/* + * $Header: cdemorid.h 13-sep-2000.22:27:29 emendez Exp $ + */ + +/* Copyright (c) 1997, 2000 Oracle Corporation. All rights reserved. +*/ + +/* NOTE: See 'header_template.doc' in the 'doc' dve under the 'forms' + directory for the header file template that includes instructions. +*/ + +/* + NAME + cdemorid.h - + + DESCRIPTION + test using ROWID with INSERT, UPDATE, DELETE. + + RELATED DOCUMENTS + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + emendez 09/13/00 - fix top 5 olint errors + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + dchatter 10/16/98 - Creating new demo cdemorid + dchatter 10/16/98 - Creation + + +*/ + +#ifndef CDEMORID +#define CDEMORID + +/*------------------------------------------------------------------------ + * Include Files + */ + +#include +#include +#include +#include + +#define MAXBINDS 2 +#define MAXROWS 5 +/*-------------------------------------------------------------------------- + * Static Function Declarations + */ + +sword init_handles(/*_ OCIEnv **envhp, + OCIError **errhp, + ub4 init_mode _*/); + +sword cleanup(/*_ boolean loggedon, + OCIEnv *envhp, + OCISvcCtx *svchp, + OCIError *errhp _*/); + +void report_error(/*_ OCIError *errhp _*/); + +void checkerr(/*_ OCIError *errhp, + sword status _*/); + +sword get_all_rows(/*_ OCISvcCtx *svchp, + OCIError *errhp, + OCIStmt *select_p, + OCIRowid **Rowid _*/); + +sword update_all_rows(/*_ OCISvcCtx *svchp, + OCIError *errhp, + OCIStmt *update_p, + OCIStmt *select_p, + OCIRowid **Rowid _*/); + +int main(/*_ int argc, char *argv[] _*/); + + +#endif /* CDEMORID */ + + + + + + + diff --git a/cdemorid.sql b/cdemorid.sql new file mode 100644 index 0000000..550e56f --- /dev/null +++ b/cdemorid.sql @@ -0,0 +1,57 @@ +rem +rem $Header: cdemorid.sql 14-jul-99.13:52:59 mjaeger Exp $ +rem +rem cdemorid.sql +rem +rem Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemorid.sql - SQL to set up cdemorid demo +rem +rem DESCRIPTION +rem set up for testing ROWID with UPDATE +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem dchatter 10/16/98 - SQL for cdemorid +rem dchatter 10/16/98 - Created +rem + +connect system/manager +drop user cdemorid cascade; +grant connect, resource to cdemorid identified by cdemorid; + + +CONNECT cdemorid/cdemorid + +CREATE TABLE FOO (C1 INTEGER, C2 VARCHAR2(20)); + +INSERT INTO FOO VALUES (1, 'Row 1'); +INSERT INTO FOO VALUES (2, 'Row 2'); +INSERT INTO FOO VALUES (3, 'Row 3'); +INSERT INTO FOO VALUES (4, 'Row 4'); +INSERT INTO FOO VALUES (5, 'Row 5'); +INSERT INTO FOO VALUES (6, 'Row 6'); +INSERT INTO FOO VALUES (7, 'Row 7'); +INSERT INTO FOO VALUES (8, 'Row 8'); +INSERT INTO FOO VALUES (9, 'Row 9'); +INSERT INTO FOO VALUES (10, 'Row 10'); +INSERT INTO FOO VALUES (11, 'Row 11'); +INSERT INTO FOO VALUES (12, 'Row 12'); +INSERT INTO FOO VALUES (13, 'Row 13'); +INSERT INTO FOO VALUES (14, 'Row 14'); +INSERT INTO FOO VALUES (15, 'Row 15'); +INSERT INTO FOO VALUES (17, 'Row 16'); +INSERT INTO FOO VALUES (18, 'Row 17'); +INSERT INTO FOO VALUES (19, 'Row 18'); +INSERT INTO FOO VALUES (20, 'Row 19'); +INSERT INTO FOO VALUES (21, 'Row 20'); + +COMMIT + + +EXIT + diff --git a/cdemort.c b/cdemort.c new file mode 100644 index 0000000..52d1a73 --- /dev/null +++ b/cdemort.c @@ -0,0 +1,621 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemort.c 14-jul-99.13:21:07 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1995, 1999,, 2000 Oracle Corporation. All rights reserved. +*/ + +/* + NAME + cdemort.c + DESCRIPTION + Tests ORT user interface type access. + + cdemo_ort takes the username, password and a type name + (created in the database) as a command line argument and + dumps all the information about the type -- its attribute + types, methods, method parameters, etc. + + NOTES + See routines. + + MODIFIED (MM/DD/YY) + svedala 01/24/00 - 4th argument to OCITypeMethodOverload should be + "CONST text *" - bug 1078623 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + cchau 05/19/97 - change OCITypeByName to OCIDescribeAny + echen 03/05/97 - remove unnecessary code + cxcheng 02/20/97 - fix oro names + cxcheng 02/10/97 - remove short ORO names + cxcheng 01/15/97 - change prototype of OCITypeElemParameterizedType() + echen 01/03/97 - modify the test + echen 11/15/96 - oci beautification + echen 07/25/96 - enhance the demo + dchatter 07/18/96 - remove Oracle specific code + echen 07/16/96 - Creation +*/ + +#ifndef CDEMO_ORT_ORACLE +#include "cdemort.h" +#endif + +/*****************************************************************************/ +static void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + break; + case OCI_NEED_DATA: + break; + case OCI_NO_DATA: + break; + case OCI_ERROR: + (void) OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("Error - %s\n", errbuf); + break; + case OCI_INVALID_HANDLE: + break; + case OCI_STILL_EXECUTING: + break; + case OCI_CONTINUE: + break; + default: + break; + } +} + +/*****************************************************************************/ +static void print_method_positions(meth_name, methpos, om_count) +text *meth_name; +ub4 methpos[10]; +ub4 om_count; +{ + ub4 i; + + (void) printf("The position(s) for method %s -- %d", + meth_name, methpos[0]); + for (i = 1; i < om_count; i++) + (void) printf(", %d", methpos[i]); + + (void) printf(".\n"); +} + + +/*****************************************************************************/ +static void unit_test_type_access(envhp, errhp, svchp, type_name) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +char *type_name; +{ + ub1 meth_flags; + ub4 i, j, k; + text *text_value, *ret_param; + ub4 text_len, len; + ub4 count, pcount, pos, methpos[10], om_count; + OCITypeCode typecode; + OCIType *at_tdo = (OCIType *) 0, + *tdo_stored, *param_tdo, *attr_tdo, *non_collection, + *return_tdo; + OCITypeElem *rdo, *pdo; + OCITypeIter *iterator; + OCITypeMethod *mdoPtr_array = (OCITypeMethod *) 0; + OCITypeElem *ado = (OCITypeElem *) 0, **bad_ado = (OCITypeElem **) 0, + *ado1 = (OCITypeElem *) 0; + OCITypeMethod *mdo, **bad_mdo = (OCITypeMethod **) 0; + OCITypeElem *ms_ado; + ub2 sqtcode, sqttype; + ub4 num_elems; + OCITypeElem *element; + OCIType *element_type; + OCIType *table_type; + text *method, *pname, *meth_name; + ub4 mname_len; + OCIRef *type_ref = (OCIRef *) 0; + OCIDescribe *dschp = (OCIDescribe *) 0; + OCIParam *parmp; + + + + /* ----------------- GET INFORMATION ABOUT A TYPE ----------------- */ + + /* allocate describe handle for OCIDescribeAny */ + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + /* if (OCITypeByName(envhp, errhp, svchp, (const text *)"", + (ub4) strlen(""), (const text *) type_name, + (ub4) strlen(type_name), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, + &at_tdo) != OCI_SUCCESS || !at_tdo) + { + (void) printf("Can not get type descriptor.\n"); + return; + } */ + + checkerr(errhp, OCIDescribeAny(svchp, errhp, (text *)type_name, + (ub4) strlen(type_name), OCI_OTYPE_NAME, (ub1)1, + (ub1) OCI_PTYPE_TYPE, dschp)); + + checkerr(errhp, OCIAttrGet((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, errhp)); + + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &type_ref, (ub4 *) 0, + (ub4) OCI_ATTR_REF_TDO, (OCIError *) errhp)); + + checkerr(errhp, OCIObjectPin(envhp, errhp, type_ref, (OCIComplexObject *) 0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&at_tdo)); + + if (!at_tdo) + { + (void) printf("Can not get type descriptor.\n"); + return; + } + + if (OCITypeTypeCode(envhp, errhp, at_tdo) != OCI_TYPECODE_OBJECT) + (void) printf("The type is not name type.\n"); + + /* version name will be "$8.0" for future label */ + if (memcmp((const void *) OCITypeVersion(envhp, errhp, at_tdo, &text_len), + (const void *) "$8.0", text_len)) + (void) printf("return version is wrong.\n"); + + /* ---------- GET IMMEDIATE ATTRIBUTES IN A TYPE ---------- */ + + /* loop through all attributes in the type */ + count = OCITypeAttrs(envhp, errhp, at_tdo); + + if (OCITypeIterNew(envhp, errhp, at_tdo, &iterator) != OCI_SUCCESS) + (void) printf("BUG -- OCITypeIterNew, test return code OCI_SUCCESS.\n"); + + for (i = 0; OCITypeAttrNext(envhp, errhp, + iterator, &ado) != OCI_NO_DATA; i++) + { + /* get the attribute's name */ + (void) printf("Attribute # %d -- %s\n", i + 1, + OCITypeElemName(envhp, errhp, ado, &text_len)); + + /* get information about the attribute by name */ + if (OCITypeAttrByName(envhp, errhp, at_tdo, + OCITypeElemName(envhp, errhp, ado, &text_len), + text_len, &ado1) != OCI_SUCCESS) + (void) printf("Can not get attribute by name.\n"); + + /* get the attribute's type code */ + sqtcode = OCITypeElemExtTypeCode(envhp, errhp, ado); + (void) printf("The SQT code is %d.\n", sqtcode); + + /* get the attribute's type code */ + typecode = OCITypeElemTypeCode(envhp, errhp, ado); + + switch (typecode) + { + /* scalar types */ + case OCI_TYPECODE_DATE: /* date */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_DATE.\n"); + break; + case OCI_TYPECODE_SIGNED8: /* byte */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_SIGNED8.\n"); + break; + case OCI_TYPECODE_SIGNED16: /* short */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_SIGNED16.\n"); + break; + case OCI_TYPECODE_UNSIGNED8: /* unsigned byte */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_UNSIGNED8.\n"); + break; + case OCI_TYPECODE_UNSIGNED16: /* unsigned short */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_UNSIGNED16.\n"); + break; + case OCI_TYPECODE_OCTET: /* octet */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_OCTET.\n"); + break; + case OCI_TYPECODE_MLSLABEL: /* oracle mlslabel */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_MLSLABEL.\n"); + break; + case OCI_TYPECODE_CLOB: /* clob */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_CLOB.\n"); + break; + case OCI_TYPECODE_BLOB: /* blob */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_BLOB.\n"); + break; + case OCI_TYPECODE_CFILE: /* cfile */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_CFILE.\n"); + break; + case OCI_TYPECODE_BFILE: /* bfile */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_BFILE.\n"); + break; + /* number types */ + case OCI_TYPECODE_INTEGER: + (void) printf(" TYPE CODE -- OCI_TYPECODE_INTEGER.\n"); + break; + case OCI_TYPECODE_NUMBER: /* oracle number */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_NUMBER.\n"); + (void) printf(" Scale -- %d\n", + OCITypeElemNumScale(envhp, errhp, ado)); + break; + case OCI_TYPECODE_DECIMAL: /* decimal */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_DECIMAL.\n"); + (void) printf(" Scale -- %d\n", + OCITypeElemNumScale(envhp, errhp, ado)); + break; + + /* fall through to get the precision */ + case OCI_TYPECODE_FLOAT: /* float */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_FLOAT.\n"); + (void) printf(" Scale -- %d, Precision %d\n", + OCITypeElemNumScale(envhp, errhp, ado), + OCITypeElemNumPrec(envhp, errhp, ado) ); + break; + case OCI_TYPECODE_SIGNED32: /* long */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_SIGNED32.\n"); + (void) printf(" Scale -- %d, Precision %d\n", + OCITypeElemNumScale(envhp, errhp, ado), + OCITypeElemNumPrec(envhp, errhp, ado) ); + break; + case OCI_TYPECODE_UNSIGNED32: /* unsigned long */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_UNSIGNED32.\n"); + (void) printf(" Scale -- %d, Precision %d\n", + OCITypeElemNumScale(envhp, errhp, ado), + OCITypeElemNumPrec(envhp, errhp, ado) ); + break; + case OCI_TYPECODE_REAL: /* real */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_REAL.\n"); + (void) printf(" Scale -- %d, Precision %d\n", + OCITypeElemNumScale(envhp, errhp, ado), + OCITypeElemNumPrec(envhp, errhp, ado) ); + break; + case OCI_TYPECODE_DOUBLE: /* double */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_DOUBLE.\n"); + (void) printf(" Scale -- %d, Precision %d\n", + OCITypeElemNumScale(envhp, errhp, ado), + OCITypeElemNumPrec(envhp, errhp, ado) ); + break; + + /* string types */ + case OCI_TYPECODE_CHAR: /* fixed length string */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_CHAR.\n"); + (void) printf(" Character set id -- %d\n", + OCITypeElemCharSetID(envhp, errhp, ado)); + (void) printf(" String length -- %d\n", + OCITypeElemLength(envhp, errhp, ado)); + break; + case OCI_TYPECODE_VARCHAR2: /* variable length string */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_VARCHAR2.\n"); + (void) printf(" Character set id -- %d\n", + OCITypeElemCharSetID(envhp, errhp, ado)); + (void) printf(" String length -- %d\n", + OCITypeElemLength(envhp, errhp, ado)); + break; + case OCI_TYPECODE_VARCHAR: /* variable length string old */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_VARCHAR.\n"); + (void) printf(" Character set id -- %d\n", + OCITypeElemCharSetID(envhp, errhp, ado)); + (void) printf(" String length -- %d\n", + OCITypeElemLength(envhp, errhp, ado)); + break; + case OCI_TYPECODE_RAW: /* raw */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_RAW.\n"); + (void) printf(" String length -- %d\n", + OCITypeElemLength(envhp, errhp, ado)); + break; + + /* parameterized types */ + case OCI_TYPECODE_VARRAY: /* variable array */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_VARRAY.\n"); + if ( OCITypeElemParameterizedType(envhp, errhp, + ado, &tdo_stored) != OCI_SUCCESS ) + (void) printf( + "Error -- can not get parameterized types's descriptor.\n"); + (void) printf(" Array elements type code -- %d\n", + OCITypeTypeCode(envhp, errhp, tdo_stored)); + break; + + case OCI_TYPECODE_REF: /* reference */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_REF.\n"); + if ( OCITypeElemParameterizedType(envhp, errhp, + ado, &tdo_stored) != OCI_SUCCESS ) + (void) printf( + "Error -- can not get parameterized types's descriptor.\n"); + (void) printf(" Array elements type code -- %d\n", + OCITypeTypeCode(envhp, errhp, tdo_stored)); + break; + case OCI_TYPECODE_PTR: /* pointer */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_PTR.\n"); + if ( OCITypeElemParameterizedType(envhp, errhp, + ado, &tdo_stored) != OCI_SUCCESS ) + (void) printf( + "Error -- can not get parameterized types's descriptor.\n"); + (void) printf(" Array elements type code -- %d\n", + OCITypeTypeCode(envhp, errhp, tdo_stored)); + break; + + case OCI_TYPECODE_NAMEDCOLLECTION: /* domain type */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_NAMEDCOLLECTION.\n"); + if ( OCITypeElemType( envhp, errhp, ado, &attr_tdo) == OCI_SUCCESS ) + { + switch (OCITypeCollTypeCode(envhp, errhp, attr_tdo)) + { + case OCI_TYPECODE_VARRAY: /* variable array */ + + (void) printf(" SUBTYPE CODE -- OCI_TYPECODE_VARRAY.\n"); + + if (OCITypeCollSize(envhp, errhp, + attr_tdo, &num_elems) != OCI_SUCCESS) + (void) printf( + "Error -- can not get collectio type element count.\n"); + (void) printf("The number of elements are %d.\n", num_elems); + + /* test error code for OCITypeCollElem */ + /* get the ado of the array */ + element = (OCITypeElem *)0; + if (OCITypeCollElem(envhp, errhp, + attr_tdo, &element) != OCI_SUCCESS) + (void) printf( + "Error -- can not get descriptor to an element's descriptor.\n"); + + /* get the type of the array */ + if (ortgcty(envhp, errhp, attr_tdo, &element_type) != OCI_SUCCESS) + (void) printf( + "Error -- can not get element's type descriptor.\n"); + (void) printf(" The type code for array is %d.\n", + OCITypeTypeCode(envhp, errhp, element_type) ); + + if (OCITypeCollExtTypeCode(envhp, errhp, + attr_tdo, &sqtcode) != OCI_SUCCESS) + (void) printf("Error -- can not get element's sql code.\n"); + (void) printf(" The SQT code for array is %d.\n", sqtcode ); + break; + + case OCI_TYPECODE_TABLE: /* multiset */ + + (void) printf(" SUBTYPE CODE -- OCI_TYPECODE_TABLE.\n"); + /* get the type of the multiset */ + if (ortgcty(envhp, errhp, attr_tdo, &table_type) != OCI_SUCCESS) + (void) printf("Error -- can not get the type of a multiset.\n"); + (void) printf(" The type code for the multiset is %d.\n", + OCITypeTypeCode(envhp, errhp, table_type) ); + + break; + } + } + else + (void) printf( + " Error -- OCITypeElemType, test return code OCI_SUCCESS.\n"); + break; + + /* abstract type */ + case OCI_TYPECODE_OBJECT: /* abstract data type */ + if ( OCITypeElemType( envhp, errhp, ado, &attr_tdo) == OCI_SUCCESS ) + { + if ( OCITypeTypeCode(envhp, errhp, attr_tdo)!=OCI_TYPECODE_OBJECT ) + (void) printf(" Error -- expect type code OCI_TYPECODE_OBJECT.\n"); + } + else + (void) printf(" Error -- can not get attribute tdo.\n"); + (void) printf(" TYPE CODE -- OCI_TYPECODE_OBJECT.\n"); + break; + + default: + (void) printf("Error: invalid type code\n"); + break; + } /* end of typecode switch */ + + } + + + /* ------------ GET THE IMMEDIATE METHODS OF A TYPE ------------ */ + + count = OCITypeMethods(envhp, errhp, at_tdo); + + /* ----------------- GET THE MAP FUNCTION ----------------- */ + /* MAP method cannot be created yet */ + if ( OCITypeMethodMap(envhp, errhp, at_tdo, &mdo) == OCI_SUCCESS ) + (void) printf("Error -- can not get the map function.\n"); + if (mdo != (OCITypeMethod *)0) + (void) printf("Map method name -- %s.\n", + OCITypeMethodName(envhp, errhp, mdo, &text_len)); + + /* ----------------- GET THE ORDER FUNCTION ----------------- */ + /* MAP method cannot be created yet */ + if ( OCITypeMethodOrder(envhp, errhp, at_tdo, &mdo) == OCI_SUCCESS ) + (void) printf("Error -- can not get map method's mdo.\n"); + if (mdo != (OCITypeMethod *)0) + (void) printf("Order method name -- %s.\n", + OCITypeMethodName(envhp, errhp, mdo, &text_len)); + + + /* ----------- LOOP THROUGH ALL METHODS IN A TYPE ----------- */ + + (void) printf("Number of methods -- %d\n", count); + for (i = 0; OCITypeMethodNext(envhp, errhp, + iterator, &mdo) != OCI_NO_DATA; i++) + { + if (OCITypeResult(envhp, errhp, mdo, &rdo) != OCI_SUCCESS) + (void) printf("BUG -- OCITypeResult, test return code OCI_SUCCESS.\n"); + + + /* get the typecode of the method's result */ + typecode = OCITypeElemTypeCode(envhp, errhp, rdo); + + meth_name = OCITypeMethodName(envhp, errhp, mdo, &text_len); + (void) printf("\nMethod name -- %s, Type code: %d, Position: %d.\n", + meth_name, typecode, i); + + if (OCITypeMethodByName(envhp, errhp, at_tdo, (CONST text *) meth_name, + (ub4) strlen((const char *) meth_name), + &mdoPtr_array) != OCI_SUCCESS) + (void) printf( + "Error -- OCITypeMethodByName, test return code OCI_SUCCESS.\n"); + + /* Get method's return parameter */ + if (OCITypeResult(envhp, errhp, mdo, &rdo) != OCI_SUCCESS) + (void) printf("Error -- ortgrbp, test return code OCI_SUCCESS.\n"); + + /* find out how many methods exist with this name */ + om_count = OCITypeMethodOverload(envhp, errhp, at_tdo, + (CONST text *) meth_name, + (ub4) strlen((const char *) meth_name)); + (void) printf("Number of overloaded methods for %s -- %d\n", + meth_name, om_count); + + print_method_positions(meth_name, methpos, om_count); + + /* get the method's encapsulation */ + if (OCITypeMethodEncap(envhp, errhp, mdo) != OCI_TYPEENCAP_PUBLIC) + (void) printf("Error -- wrong method's encapsulation.\n"); + + /* ------------ GET THE PARAMETERS IN A METHOD ------------ */ + + /* loop through all parameters in the method */ + pcount = OCITypeMethodParams(envhp, errhp, mdo); + (void) printf("Number of parameter's in method -- %d\n", pcount); + + for (j = 1; j <= pcount; j++) + { + /* get the parameter information by position */ + if (OCITypeParamByPos(envhp, errhp, mdo, j, &pdo) != OCI_SUCCESS) + (void) printf( + "Error -- OCITypeParamByPos, test return code OCI_SUCCESS.\n"); + + /* put the parameter's number */ + (void) printf("Parameter's number -- %d\n.", j); + + /* get the parameter's name */ + pname = OCITypeElemName(envhp, errhp, pdo, &text_len); + (void) printf("Parameter's name -- %s\n.", pname); + + /* get a parameter in a method by name */ + if (OCITypeParamByName(envhp, errhp, mdo, (CONST text *) pname, (ub4) + strlen((const char *) pname), &pdo) != OCI_SUCCESS) + (void) printf( + "Error -- OCITypeParamByName, test return code OCI_SUCCESS.\n"); + + if (OCITypeParamPos(envhp, errhp, mdo, (CONST text *) pname, + (ub4) strlen((const char *)pname), + &pos, &pdo) != OCI_SUCCESS) + (void) printf( + "Error -- OCITypeParamPos, test return code OCI_SUCCESS.\n"); + /* check the position */ + if (pos != j) + (void) printf("Error -- wrong attribute position.\n"); + + /* get the parameter's mode */ + (void) printf( + "Parameter's mode -- %d\n.", OCITypeElemParamMode(envhp, errhp, pdo)); + + /* get the parameter's required flag */ + OCI_TYPEPARAM_IS_REQUIRED(OCITypeElemFlags(envhp, errhp, pdo)) ? + (void) printf("parameter's required flag is TRUE -- %d\n.", + OCITypeElemParamMode(envhp, errhp, pdo)): + (void) printf("parameter's required flag is FALSE -- %d\n.", + OCITypeElemParamMode(envhp, errhp, pdo)); + if ( OCITypeElemType(envhp, errhp, pdo, ¶m_tdo) == OCI_SUCCESS ) + (void) printf(" Parameter type code -- %d\n", + OCITypeTypeCode(envhp, errhp, param_tdo)); + + /* got to verify with Zona if default value is working */ + text_value = OCITypeElemDefaultValue( envhp, errhp, pdo, &text_len); + if (text_len) + (void) printf(" Parameter default value -- %s\n", text_value); + } + + } /* end methods for loop */ + + +} + +/*****************************************************************************/ +int main(int argc, char *argv[]) +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCISession *usrhp; + dvoid *tmp; + int i; + + + if (argc < 4) + { + (void) printf( + "Usage -- cdemort \n"); + return (0); + } + /* initialize the process */ + OCIInitialize((ub4) OCI_THREADED | OCI_OBJECT, + (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)()) 0, (void (*)()) 0 ); + /* initialize the environment handle */ + (void) OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + /* get the error handle */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + /* two server contexts */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp); + /* attach to the server */ + (void) OCIServerAttach( srvhp, errhp, (text *) "", + (sb4) 0, (ub4) OCI_DEFAULT); + /* get the service handle */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp); + + /* set attribute server context in the service context */ + (void) OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp); + /* get the user handle */ + (void) OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, + (ub4)OCI_HTYPE_SESSION, 0, (dvoid **)0); + /* set the user name attribute */ + (void) OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)argv[1], (ub4)strlen(argv[1]), + (ub4)OCI_ATTR_USERNAME, errhp); + /* set the password attribute */ + (void) OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)argv[2], (ub4)strlen(argv[2]), + (ub4)OCI_ATTR_PASSWORD, errhp); + /* Authenticate */ + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, + OCI_CRED_RDBMS, OCI_DEFAULT)); + /* set the user context attribute */ + (void) OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, + (ub4)OCI_ATTR_SESSION, errhp); + /* loop through all the types */ + for (i = 3; i < argc; i++) { + /* dump an adt with all the types */ + (void) printf(" %s\n", argv[i]); + unit_test_type_access(envhp, errhp, svchp, argv[i]); + } + + checkerr(errhp, OCISessionEnd (svchp, errhp, usrhp, OCI_DEFAULT)); + /* dettach the server */ + (void) OCIServerDetach( srvhp, errhp, (ub4) OCI_DEFAULT ); + checkerr(errhp, OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX)); + checkerr(errhp, OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR)); + checkerr(errhp, OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER)); + + return (0); +} + + diff --git a/cdemort.h b/cdemort.h new file mode 100644 index 0000000..00a9e1b --- /dev/null +++ b/cdemort.h @@ -0,0 +1,75 @@ +/* + * $Header: cdemort.h 14-jul-99.12:52:18 mjaeger Exp $ + */ + +/* Copyright (c) 1995, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + NAME + cdemort.h + + DESCRIPTION + This file contains the header information for the cdemort.c + + RELATED DOCUMENTS + None. + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + None. + + PRIVATE FUNCTION(S) + As defined below. + + EXAMPLES + + NOTES + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + echen 11/15/96 - oci beautification + dchatter 07/18/96 - delete spurious .h files + echen 08/07/95 - Creation +*/ + +#ifndef CDEMO_OBJ_ORACLE +#define CDEMO_OBJ_ORACLE + +#ifndef OCI_ORACLE +#include +#endif + + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +#define RUNTEST TRUE +#define USERNAME "internal" +#define SERVER "ORACLE" +#define SCHEMA "SYS" +#define ADDRESS_TYPE_NAME "ADDRESS_OBJECT" +#define RETURN_ON_ERROR(error) if (error) return (error) + +static void unit_test_type_access(/*_ OCIEnv *envhp, OCIError *errhp, + OCISvcCtx *svchp, char *type_name _*/); + +int main(/*_ int argc, char *argv[] _*/); + +#endif /* CDEMO_OBJ_ORACLE */ + diff --git a/cdemosc.c b/cdemosc.c new file mode 100644 index 0000000..e8895ca --- /dev/null +++ b/cdemosc.c @@ -0,0 +1,390 @@ +/* Copyright (c) 2001, Oracle Corporation. All rights reserved. */ + +/* + + NAME + cdemosc.c - OCI demo program for scrollable cursor. + + DESCRIPTION + An example program which reads employee records from table empo. + SQL> describe empo; + Name Null? Type + ------------------------- -------- --------------- + EMPNO NUMBER + ENAME CHAR(5) + ADDR EMPADDR + ECOLL EVARRAY + SQL> describe empaddr; + Name Null? Type + ------------------------- -------- --------------- + STATE CHAR(2) + ZIP NUMBER + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + Dependent Files: + cdemosc.sql - SQL script to be run before execution. + + MODIFIED (MM/DD/YY) + ani 04/30/01 - Merged ani_ocidemo + ani 04/24/01 - Creation + +*/ + +#include +#include +#include + +#ifndef OCI_ORACLE +#include +#endif + +typedef struct address +{ + OCIString * state ; + OCINumber zip; +} address ; + +typedef struct null_address +{ + sb2 null_state ; + sb2 null_zip; +} null_address ; + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +#define MAXROWS 3 +#define MAX_ENAMELEN 20 + +static text *username = (text *) "scott"; +static text *password = (text *) "tiger"; + +/* Define SQL statements to be used in program. */ +static text *selemp = (text *)"SELECT empno, ename, addr, ecoll FROM empo"; + +static sword empno[MAXROWS] ; +static text empname[MAXROWS][MAX_ENAMELEN]; +static address * empaddr [MAXROWS] ; +static null_address * indaddr [MAXROWS] ; +static ub4 rc[MAXROWS] ; +static OCIColl * evarray[MAXROWS] ; +static OCIEnv *envhp; +static OCIError *errhp; +static OCISvcCtx *svchp; +static sword status; +static OCIStmt *stmthp; +static sword status; + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ + +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void checkprint(/*_ OCIError *errhp, sword status, ub4 nrows _*/); +static void cleanup(/*_ void _*/); +static void myprint (/*_ ub4 _*/); +int main(/*_ int argc, char *argv[] _*/); + + +int main(argc, argv) +int argc; +char *argv[]; +{ + + OCISession *authp = (OCISession *) 0; + OCIServer *srvhp; + OCISvcCtx *svchp; + OCIType * addr_tdo ; + OCIType * addr_tdo2 ; + ub4 empaddrsz ; + OCIDefine *defn1p = (OCIDefine *) 0; + OCIDefine *defn2p = (OCIDefine *) 0; + OCIDefine *defn3p = (OCIDefine *) 0; + OCIDefine *defn4p = (OCIDefine *) 0; + OCIDefine *defn5p = (OCIDefine *) 0; + int num ; + + ub4 prefetch = 5 ; + + (void) OCIInitialize((ub4) OCI_DEFAULT | OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 ); + + (void) OCIEnvInit( (OCIEnv **) &envhp, OCI_DEFAULT, (size_t) 0, + (dvoid **) 0 ); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + /* server contexts */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, OCI_HTYPE_SERVER, + (size_t) 0, (dvoid **) 0); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0); + + (void) OCIServerAttach( srvhp, errhp, (text *)"", (sb4) strlen(""), 0); + + /* set attribute server context in the service context */ + (void) OCIAttrSet( (dvoid *) svchp, OCI_HTYPE_SVCCTX, (dvoid *)srvhp, + (ub4) 0, OCI_ATTR_SERVER, (OCIError *) errhp); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **)&authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0); + + (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) username, (ub4) strlen((char *)username), + (ub4) OCI_ATTR_USERNAME, errhp); + + (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *)password), + (ub4) OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin ( svchp, errhp, authp, OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)); + + (void) OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, + (ub4) OCI_ATTR_SESSION, errhp); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)); + + + /**** SCROLLABLE RESULT SET *****/ + + /* Retrieve the employee records */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, selemp, + (ub4) strlen((char *) selemp), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + (void) OCIAttrSet((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT, + (dvoid *) & prefetch, 0, + (ub4) OCI_ATTR_PREFETCH_ROWS, errhp); + + /* bind the input variable */ + checkerr(errhp, OCIDefineByPos(stmthp, &defn1p, errhp, 1, (dvoid *) empno, + (sword) sizeof(sword), SQLT_INT, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp, OCIDefineByPos(stmthp, &defn2p, errhp, 2, (dvoid **) empname, + (sword) MAX_ENAMELEN, SQLT_STR, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, OCI_DEFAULT)); + + checkerr(errhp, OCITypeByName(envhp, errhp, svchp, (const text *) 0, + (ub4) 0, (const text *) "EMPADDR", + (ub4) strlen((const char *) "EMPADDR"), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, + &addr_tdo)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defn3p, errhp, 3, (dvoid *) 0, + (sword) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp, OCIDefineObject(defn3p, errhp, addr_tdo, (dvoid **) empaddr, + (ub4 *) & empaddrsz, (dvoid **) indaddr, (ub4 *) rc)); + + checkerr(errhp, OCITypeByName(envhp, errhp, svchp, (const text *) 0, + (ub4) 0, (const text *) "EVARRAY", + (ub4) strlen((const char *) "EVARRAY"), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, + &addr_tdo2)); + checkerr(errhp, OCIDefineByPos(stmthp, &defn4p, errhp, 4, (dvoid *) 0, + (sword) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp, OCIDefineObject(defn4p, errhp, addr_tdo2, (dvoid **) evarray, + (ub4 *) 0, (dvoid **) 0, (ub4 *) 0)); + + checkprint(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, (ub4) + 0, (CONST OCISnapshot *) + NULL, (OCISnapshot *) NULL, + OCI_STMT_SCROLLABLE_READONLY ),0); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 3, + OCI_FETCH_ABSOLUTE, (sb4) 6, OCI_DEFAULT),3); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 3, + OCI_FETCH_RELATIVE, (sb4) -2, OCI_DEFAULT),3); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 2, + OCI_FETCH_ABSOLUTE, (sb4) 9, OCI_DEFAULT),2); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_LAST, (sb4) 0, OCI_DEFAULT),1); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_FIRST, (sb4) 0, OCI_DEFAULT),1); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_LAST, (sb4) 0, OCI_DEFAULT),1); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_FIRST, (sb4) 0, OCI_DEFAULT),1); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_ABSOLUTE, (sb4) 15, OCI_DEFAULT),1); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 2, + OCI_FETCH_NEXT, (sb4) 0, OCI_DEFAULT),2); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_PRIOR, (sb4) 0, OCI_DEFAULT),1); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 3, + OCI_FETCH_RELATIVE, (sb4) -8, OCI_DEFAULT),3); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 2, + OCI_FETCH_NEXT, (sb4) 0, OCI_DEFAULT),2); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_FIRST, (sb4) 0, OCI_DEFAULT),1); + + /* cancel the statement handle - and free resources on client and server */ + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 0, + OCI_FETCH_NEXT, (sb4) 0, OCI_DEFAULT),0); + + /* this should result in some error */ + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_NEXT, (sb4) 0, OCI_DEFAULT),1); + + /* re-execute in the non-scrollable mode */ + checkprint(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 3, (ub4) + 0, (CONST OCISnapshot *) + NULL, (OCISnapshot *) NULL, + 0),3); + + /* this should result in error */ + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_ABSOLUTE, (sb4) 4, OCI_DEFAULT),1); + cleanup() ; + + return 1; +} + + +/*check fetch status and print rows upon success*/ +void checkprint(errhp, status,nrows) +OCIError *errhp; +sword status; +ub4 nrows; +{ + checkerr(errhp,status); + if (status != OCI_ERROR && status != OCI_NO_DATA) + myprint(nrows); +} + + +/*check status and print error information */ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +/* + * Exit program with an exit code. + */ +void cleanup() +{ + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, OCI_HTYPE_ENV); + return; +} + + +/*void myfflush() +{ + eb1 buf[50]; + + fgets((char *) buf, 50, stdin); +}*/ + + +/*print rows*/ +void myprint (ub4 nrows) +{ + int i, j, num, cp, rc, amount ; + sb4 colsz; + void * elem ; + ub4 sz = sizeof(cp) ; + boolean exist = FALSE; + + checkerr(errhp, OCIAttrGet((CONST void *) stmthp, OCI_HTYPE_STMT, + (void *) & cp, (ub4 *) & sz, + OCI_ATTR_CURRENT_POSITION, errhp)); + checkerr(errhp, OCIAttrGet((CONST void *) stmthp, OCI_HTYPE_STMT, + (void *) & rc, (ub4 *) & sz, + OCI_ATTR_ROW_COUNT, errhp)); + printf("******** Current position, Row Count = %d, %d ******** \n", cp, rc); + + for (i =0 ; i < nrows ; i++ ) + { + OCINumberToInt(errhp, & empaddr[i]->zip, sizeof(num), + OCI_NUMBER_SIGNED, (void *) & num); + printf("\n %d %s %s %d ", empno[i], empname[i], + OCIStringPtr(envhp, empaddr[i]->state), num); + + colsz = OCICollMax (envhp, (OCIColl *) evarray[i]) ; + for (j = 0; j < colsz ; j++) + { + OCICollGetElem (envhp, errhp, (OCIColl *) evarray[i], j, & exist, + (void **) & elem, (void **) 0); + if (!exist) + printf(" *** error - coll, row %d col-elem %d ", i, j); + else { + checkerr(errhp, OCINumberToInt(errhp, (OCINumber *) elem, + sizeof(int), OCI_NUMBER_SIGNED, & num)); + printf("%d ", num); + } + } + printf ("\n"); + } +} + +/* end of file cdemosc.c */ + diff --git a/cdemosc.sql b/cdemosc.sql new file mode 100644 index 0000000..4dc2793 --- /dev/null +++ b/cdemosc.sql @@ -0,0 +1,80 @@ +Rem +Rem $Header: cdemosc.sql 03-may-2001.17:06:41 jchai Exp $ +Rem +Rem cdemosc.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem cdemosc.sql - Demo program for scrollable cursor. +Rem +Rem DESCRIPTION +Rem SQL script to prepare table empo and data in the table. +Rem +Rem NOTES +Rem Neet to run before cdemosc. +Rem +Rem MODIFIED (MM/DD/YY) +Rem jchai 05/03/01 - connect as scott/tiger +Rem ani 04/30/01 - Merged ani_ocidemo +Rem ani 04/24/01 - Created +Rem + +connect scott/tiger; +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +drop table empo +/ +drop type evarray +/ +drop type empaddr +/ + +create or replace type empaddr as object ( + state char(2) , + zip number ) +/ + +create or replace type evarray is VARRAY(2) of number +/ + +create table empo (empno number, + ename char(5), + addr empaddr, + ecoll evarray) +/ + +insert into empo values (1, 'abc1', empaddr('ca', 94061), evarray(13,145)) +/ +insert into empo values (2, 'abc2', empaddr('ca', 94062), evarray(23,245)) +/ +insert into empo values (3, 'abc3', empaddr('ca', 94063), evarray(33,345)) +/ +insert into empo values (4, 'abc4', empaddr('ca', 94064), evarray(43,445)) +/ +insert into empo values (5, 'abc5', empaddr('ca', 94065), evarray(53,545)) +/ +insert into empo values (6, 'abc6', empaddr('ca', 94066), evarray(63,645)) +/ +insert into empo values (7, 'abc7', empaddr('ca', 94067), evarray(73,745)) +/ +insert into empo values (8, 'abc8', empaddr('ca', 94068), evarray(83,85)) +/ +insert into empo values (9, 'abc9', empaddr('ca', 94069), evarray(93,95)) +/ +insert into empo values (10, 'abc10', empaddr('ca', 94060), evarray(103,1045)) +/ +insert into empo values (11, 'abc11', empaddr('ca', 94070), evarray(113,1045)) +/ +insert into empo values (12, 'abc12', empaddr('ca', 94071), evarray(123,1045)) +/ +insert into empo values (13, 'abc13', empaddr('ca', 94072), evarray(133,1045)) +/ +insert into empo values (14, 'abc14', empaddr('ca', 94073), evarray(143,1045)) +/ diff --git a/cdemoses.c b/cdemoses.c new file mode 100644 index 0000000..59f6da6 --- /dev/null +++ b/cdemoses.c @@ -0,0 +1,553 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoses.c 08-dec-2000.12:35:31 lchidamb Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemoses.c - C Demo program to illustrate Session Management + + DESCRIPTION + This program Illustrates the following functionality: + (1) Session Switching + Session Switching allows applications to multiplex several users + over the same connection. This allows apps to multiplex several + sessions over one connection without losing the database privilege + and security features. + + a) Create One Connection + b) Create 10 sessions + c) Switch one session after another followed by SELECT USER FROM DUAL + + (2) Session Migration + Session Migration lets applications move sessions across connections. + With this feature, the application can move sessions around + dynamically based on system load and the application could implement + its own application level user priority scheme. + + a) Create Two Connections + b) Create 10 migratable sessions on first connection + c) Switch one session after another followed by SELECT USER FROM DUAL + On first connection. + b) Migrate sessions to second connection and SEKECT USER FROM DUAL + + NOTES + + IMPORTANT!!!! + TO RUN THIS DEMOS, YOU NEED TO RUN cdemoses.sql + IMPORTANT!!!! + + + MODIFIED (MM/DD/YY) + lchidamb 12/08/00 - lint + lchidamb 12/05/00 - remove DISCARD + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + lchidamb 10/14/98 - Add Migration Demo + lchidamb 10/13/98 - Session Management Demo + lchidamb 10/13/98 - Creation + +*/ + +/*---------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include + +#define EX_FAILURE -1 +#define NUM_USERS 10 +char *user[NUM_USERS] = +{ "user0", + "user1", + "user2", + "user3", + "user4", + "user5", + "user6", + "user7", + "user8", + "user9"}; + +/* this statement is executed by all sessions */ +char stmt[] = "SELECT USER FROM DUAL"; + +/* global username array: keeps track of current user session */ +char username[100]; + +/* length of username */ +ub2 userlen; + +/* indicator for username */ +sb2 userind; + +int main () +{ + sword retval = 0; + ub2 i; + OCIEnv *envhp; + OCIError *errhp; + OCIServer *srvhp; + OCIServer *srvhp1; + OCISession *userhp[10]; + OCISession *primary, *primary1; + OCIStmt *stmhp; + + /* Initialize OCI Process and Initialize Environment and Error handles */ + initialize_main(&envhp, &errhp); + + /* Initialize Server handle */ + initialize_server(envhp, errhp, &srvhp); + + + /************************* SESSION SWITCHING DEMO **************************/ + fprintf(stdout, "----------SESSION SWITCHING DEMO-----------------------\n"); + /* Initialize Users */ + for(i = 0; i < NUM_USERS; i++) + initialize_user(envhp, errhp, srvhp, &userhp[i], user[i]); + + /* Initialize Statement */ + initialize_statement(envhp, errhp, &stmhp); + + /* Switch Sessions and Execute Statements */ + for(i = 0; i < NUM_USERS; i++) + { + fprintf(stdout, "SWITCHING SESSION to %s\n", user[i]); + execute_statement(envhp, errhp, userhp[i], srvhp, stmhp); + } + + /* Switch Sessions and Terminate Users */ + for(i = 0; i < NUM_USERS; i++) + { + fprintf(stdout, "SWITCHING SESSION to %s\n", user[i]); + terminate_user(envhp, errhp, srvhp, userhp[i]); + } + + fprintf(stdout, "\n\n\n"); + /************************* SESSION MIGRATION DEMO **************************/ + fprintf(stdout, "----------SESSION MIGRATION DEMO-----------------------\n"); + /* Initialize Another Server handle */ + initialize_server(envhp, errhp, &srvhp1); + + /* Initialize non-migratable primary session on both servers */ + initialize_user(envhp, errhp, srvhp, &primary, "primary"); + initialize_user(envhp, errhp, srvhp1,&primary1, "primary"); + + + /* Initialize Migratable Users on First Server */ + for(i = 0; i < NUM_USERS; i++) + initialize_migratable_user(envhp, errhp, srvhp, primary, + &userhp[i], user[i]); + + /* Switch Sessions and Execute Statements on First Server */ + for(i = 0; i < NUM_USERS; i++) + { + fprintf(stdout, "SWITCHING SESSION to %s\n", user[i]); + execute_statement(envhp, errhp, userhp[i], srvhp, stmhp); + } + + + /* + * Oops, Imagine first connection is too loaded, lets move all + * users to the second connection and leave the first connection + * for doing some long operation. + */ + + fprintf(stdout, "\n--------MIGRATING ALL SESSIONS to SERVER2------------\n"); + /* Switch Sessions and Execute Statements on Second Server */ + for(i = 0; i < NUM_USERS; i++) + { + fprintf(stdout, "MIGRATING SESSION %s to SERVER2\n", user[i]); + execute_statement(envhp, errhp, userhp[i], srvhp1, stmhp); + } + + /* Terminate Statement */ + terminate_statement(stmhp); + + /* Migrate Sessions Back to Server1 and Terminate Users */ + fprintf(stdout, "\n-------MIGRATING ALL SESSIONS BACK to SERVER1--------\n"); + for(i = 0; i < NUM_USERS; i++) + { + fprintf(stdout, "MIGRATING SESSION %s BACK TO SERVER1\n", user[i]); + terminate_user(envhp, errhp, srvhp, userhp[i]); + } + + fprintf(stdout, "\n------TERMINATING PRIMARY SESSIONS-------------------\n"); + terminate_user(envhp, errhp, srvhp, primary); + terminate_user(envhp, errhp, srvhp1, primary1); + + /* Terminate Servers */ + terminate_server(errhp, srvhp); + terminate_server(errhp, srvhp1); + + /* Terminate Main */ + terminate_main(envhp, errhp); + return 0; +} + + +/* initialize_user */ +void initialize_user(envhp, errhp, srvhp, userhpp, name) +OCIEnv *envhp; +OCIError *errhp; +OCIServer *srvhp; +OCISession **userhpp; +char *name; +{ + OCISvcCtx *svchp; + + fprintf (stdout, "Authentication for %s is progress...0\n", name); + + /* Temporary Service Context */ + if (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for service handle..."); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + if (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) userhpp, + (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for user handle..."); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + + + /* Set the server handle in service handle */ + if (OCIAttrSet (svchp, OCI_HTYPE_SVCCTX, srvhp, 0, + OCI_ATTR_SERVER, errhp) != OCI_SUCCESS) + error_report(errhp, "initialize_user - OCIAttrSet"); + + /* set the username/password in user handle */ + if (OCIAttrSet(*userhpp, OCI_HTYPE_SESSION, name, strlen(name), + OCI_ATTR_USERNAME, errhp) != OCI_SUCCESS) + error_report(errhp, "initialize_user - OCIAttrSet"); + + if (OCIAttrSet(*userhpp, OCI_HTYPE_SESSION, name, strlen(name), + OCI_ATTR_PASSWORD, errhp) != OCI_SUCCESS) + error_report(errhp, "initialize_user - OCIAttrSet"); + + /* Authenticate */ + if (OCISessionBegin (svchp, errhp, *userhpp, + OCI_CRED_RDBMS, OCI_DEFAULT) != OCI_SUCCESS) + error_report(errhp, "initialize_user - ocisauth"); + + /* Free Temporary Service Context */ + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + + fprintf (stdout, "Authentication for %s successful.\n", name); +} + + +/* initialize_migratable_user */ +void initialize_migratable_user(envhp, errhp, srvhp, primary, userhpp, name) +OCIEnv *envhp; +OCIError *errhp; +OCIServer *srvhp; +OCISession *primary; +OCISession **userhpp; +char *name; +{ + OCISvcCtx *svchp; + + fprintf (stdout, "Authentication for %s is progress...0\n", name); + + /* Temporary Service Context */ + if (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for service handle..."); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + /* Set the Primary Session handle in the service handle */ + if (OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, primary, 0, + OCI_ATTR_SESSION, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + + /* Set the server handle in service handle */ + if (OCIAttrSet (svchp, OCI_HTYPE_SVCCTX, srvhp, 0, + OCI_ATTR_SERVER, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + + if (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) userhpp, + (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for user handle..."); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + /* set the username/password in user handle */ + if (OCIAttrSet(*userhpp, OCI_HTYPE_SESSION, name, strlen(name), + OCI_ATTR_USERNAME, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + + if (OCIAttrSet(*userhpp, OCI_HTYPE_SESSION, name, strlen(name), + OCI_ATTR_PASSWORD, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + + /* Authenticate */ + if (OCISessionBegin (svchp, errhp, *userhpp, + OCI_CRED_RDBMS, OCI_MIGRATE) != OCI_SUCCESS) + error_report(errhp, "conn2serv - ocisauth"); + + /* Free Temporary Service Context */ + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + + fprintf (stdout, "Authentication for %s successful.\n", name); +} + +/* terminate_user */ +void terminate_user(envhp, errhp, srvhp, userhp) +OCIEnv *envhp; +OCIError *errhp; +OCIServer *srvhp; +OCISession *userhp; +{ + OCISvcCtx *svchp; + /* Temporary Service Context */ + if (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for service handle..."); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + fprintf(stdout, "Logging off...\n"); + + /*****************************************************************/ + /**************** SWITCH SESSIONS BEGIN **************************/ + /* Set the server handle in service handle */ + if (OCIAttrSet (svchp, OCI_HTYPE_SVCCTX, srvhp, 0, + OCI_ATTR_SERVER, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + + /* Set the Authentication handle in the service handle */ + if (OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, userhp, 0, + OCI_ATTR_SESSION, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + /**************** SWITCH SESSIONS END ****************************/ + /*****************************************************************/ + if (OCISessionEnd(svchp, errhp, userhp, (ub4) 0)) + { + error_report(errhp, (CONST text *)"logout: ologof"); + } + + /* Free Temporary Service Context */ + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + fprintf(stdout, "Logged off.\n"); +} + +/* initialize_main */ +void initialize_main(envhpp, errhpp) +OCIEnv **envhpp; +OCIError **errhpp; +{ + int i; + + if (OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)())0, (void (*)()) 0 ) != OCI_SUCCESS) + { + fprintf(stdout, "Fail to OCIInitialize..."); + exit(EX_FAILURE); + } + + if (OCIEnvInit( (OCIEnv **) envhpp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 ) != OCI_SUCCESS) + { + fprintf(stdout, "Fail to OCIEnvInit for service handle..."); + exit(EX_FAILURE); + } + + /* Get Error Handle */ + if (OCIHandleAlloc( (dvoid *) *envhpp, (dvoid **) errhpp, + (ub4) OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS) + { + fprintf(stdout, "Fail to OCIHandleAlloc for error handle..."); + exit(EX_FAILURE); + } + return; +} + +/* terminate_main*/ +void terminate_main(envhp, errhp) +OCIEnv *envhp; +OCIError *errhp; +{ + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + (void) OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV); +} + + +/* initialize_server */ +void initialize_server(envhp, errhp, srvhpp) +OCIEnv *envhp; +OCIError *errhp; +OCIServer **srvhpp; +{ + if (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) srvhpp, + (ub4) OCI_HTYPE_SERVER, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for server handle..."); + exit(EX_FAILURE); + } + + /* Initialize Server Handle */ + if (OCIServerAttach(*srvhpp, errhp, (text *)"", 0, 0) != OCI_SUCCESS ) + error_report(errhp, "conn2serv - OCIServerAttach"); +} + +/* terminate_server */ +void terminate_server(errhp, srvhp) +OCIError *errhp; +OCIServer *srvhp; +{ + (void) OCIServerDetach(srvhp, errhp, OCI_DEFAULT ); + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); +} + + +/* initialize_statement */ +void initialize_statement(envhp, errhp, stmhpp) +OCIEnv *envhp; +OCIError *errhp; +OCIStmt **stmhpp; +{ + OCIDefine *dfnhp = (OCIDefine *)NULL; + + /* Get statement handles */ + if (OCIHandleAlloc( (dvoid *)envhp, (dvoid **) stmhpp, + (ub4) OCI_HTYPE_STMT, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for statement handle"); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + if (OCIStmtPrepare(*stmhpp, errhp, (text *)stmt, + (ub4)strlen(stmt), + (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT)) + { + fprintf(stdout, "Fail to OCIHandleAlloc for statement handle"); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + /* OCIDefineByPos */ + if (OCIDefineByPos(*stmhpp, &dfnhp, errhp, (ub4)1, + (dvoid *)username, (sb4)sizeof(username), SQLT_CHR, + ( dvoid *)&userind, &userlen, (ub2 *)NULL, + (ub4)OCI_DEFAULT)) + { + fprintf(stdout, "Fail to OCIHandleAlloc for statement handle"); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + fprintf(stdout, ""); +} + +/* terminate_statement */ +void terminate_statement(stmhp) +OCIStmt *stmhp; +{ + (void) OCIHandleFree((dvoid *) stmhp, (ub4) OCI_HTYPE_STMT); +} + +/* error_report */ +void error_report(errhp, op) +OCIError *errhp; +CONST text *op; +{ + text msgbuf[2000]; + sb4 errcode = 0; + + fprintf(stdout,"ORACLE error during %s\n", op); + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + fprintf(stdout,"ERROR CODE = %d\n", errcode); + fprintf(stdout,"%s\n", msgbuf); + exit(EX_FAILURE); +} + + +void execute_statement(envhp, errhp, userhp, srvhp, stmhp) +OCIEnv *envhp; +OCIError *errhp; +OCISession *userhp; +OCIServer *srvhp; +OCIStmt *stmhp; +{ + OCISvcCtx *svchp; + sword retval; + + /* Temporary Service Context */ + if (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for service handle..."); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + /*****************************************************************/ + /**************** SWITCH SESSIONS BEGIN **************************/ + /* Set the server handle in service handle */ + if (OCIAttrSet (svchp, OCI_HTYPE_SVCCTX, srvhp, 0, + OCI_ATTR_SERVER, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + + /* Set the Authentication handle in the service handle */ + if (OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, userhp, 0, + OCI_ATTR_SESSION, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + /**************** SWITCH SESSIONS END ****************************/ + /*****************************************************************/ + + + /* Now attempt to select user from dual!!!!! */ + fprintf(stdout, "SELECT USER FROM DUAL\n"); + + retval = OCIStmtExecute(svchp, stmhp, errhp, (ub4)1, (ub4)0, + (OCISnapshot*)0, (OCISnapshot*)0, + (ub4)OCI_DEFAULT); + + if (retval == OCI_SUCCESS) + { + fprintf(stdout, "User name of current session: %.*s\n", + userlen, username); + memset((void *)username, 0, sizeof(username)); + } + else + { + error_report(errhp, (text *)"OCIStmtExecute"); + return; + } + + /* Free Temporary Service Context */ + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); +} + +/* end of file cdemoses.c */ + diff --git a/cdemoses.h b/cdemoses.h new file mode 100644 index 0000000..b0f3834 --- /dev/null +++ b/cdemoses.h @@ -0,0 +1,100 @@ +/* + * $Header: cdemoses.h 05-dec-2000.11:47:17 lchidamb Exp $ + */ + +/* Copyright (c) 1998, 2000 Oracle Corporation. All rights reserved. +*/ + +/* NOTE: See 'header_template.doc' in the 'doc' dve under the 'forms' + directory for the header file template that includes instructions. +*/ + +/* + NAME + cdemoses.h - C Demo for Session Management + + DESCRIPTION + This program Illustrates the following functionality: + (1) Session Switching + Session Switching allows applications to multiplex several users + over the same connection. This allows apps to multiplex several + sessions over one connection without losing the database privilege + and security features. + + (2) Session Migration + Session Migration lets applications move sessions across connections. + With this feature, the application can move sessions around + dynamically based on system load and the application could implement + its own application level user priority scheme. + + NOTES + + MODIFIED (MM/DD/YY) + lchidamb 12/05/00 - remove s.h include + emendez 09/13/00 - fix top 5 olint errors + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + lchidamb 10/14/98 - prototype changes + lchidamb 10/13/98 - session management demo header + lchidamb 10/13/98 - Creation + +*/ + + +#ifndef cdemoses_ORACLE +# define cdemoses_ORACLE + + + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ + +void initialize_main(/*_ OCIEnv **envhpp, OCIError **errhpp _*/); + +void terminate_main(/*_ OCIEnv *envhp, OCIError *errhp _*/); + +void initialize_server(/*_ OCIEnv *envhp, OCIError *errhp, + OCIServer **srvhpp _*/); + +void terminate_server(/*_ OCIError *errhp, OCIServer *srvhp _*/); + +void initialize_user(/*_ OCIEnv *envhp, OCIError *errhp, + OCIServer *srvhp, OCISession **userhpp, + char *name _*/); + +void initialize_migratable_user(/*_ OCIEnv *envhp, OCIError *errhp, + OCIServer *srvhp, OCISession *primary, + OCISession **userhpp, + char *name _*/); + +void terminate_user(/*_ OCIEnv *envhp, OCIError *errhp, + OCIServer *srvhp, OCISession *userhp _*/); + +void initialize_statement(/*_ OCIEnv *envhp, OCIError *errhp, + OCIStmt **stmhpp _*/); + +void terminate_statement(/*_ OCIStmt *stmhp _*/); + +void error_report(/*_ OCIError *errhp, CONST text *op _*/); + +void execute_statement(/*_ OCIEnv *envhp, OCIError *errhp, + OCISession *userhp, OCIServer *srvhp, + OCIStmt *stmhp _*/); + + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ + + +#endif /* cdemoses_ORACLE */ diff --git a/cdemoses.sql b/cdemoses.sql new file mode 100644 index 0000000..624c118 --- /dev/null +++ b/cdemoses.sql @@ -0,0 +1,51 @@ +rem +rem $Header: cdemoses.sql 14-nov-00.18:39:03 hdnguyen Exp $ +rem +rem cdemoses.sql +rem +rem Copyright (c) 1998, 1999,, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemoses.sql - +rem +rem DESCRIPTION +rem +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem hdnguyen 11/14/00 - fixed connect internal +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem lchidamb 10/14/98 - Add Primary User +rem lchidamb 10/13/98 - SQL script for Session management demo +rem lchidamb 10/13/98 - Created +rem +connect / as sysdba; +drop user user0 cascade; +drop user user1 cascade; +drop user user2 cascade; +drop user user3 cascade; +drop user user4 cascade; +drop user user5 cascade; +drop user user6 cascade; +drop user user7 cascade; +drop user user8 cascade; +drop user user9 cascade; + +drop user primary cascade; + +grant connect, resource to user0 identified by user0; +grant connect, resource to user1 identified by user1; +grant connect, resource to user2 identified by user2; +grant connect, resource to user3 identified by user3; +grant connect, resource to user4 identified by user4; +grant connect, resource to user5 identified by user5; +grant connect, resource to user6 identified by user6; +grant connect, resource to user7 identified by user7; +grant connect, resource to user8 identified by user8; +grant connect, resource to user9 identified by user9; + + +grant connect, resource to primary identified by primary; + diff --git a/cdemosp.c b/cdemosp.c new file mode 100644 index 0000000..efce90a --- /dev/null +++ b/cdemosp.c @@ -0,0 +1,255 @@ +/* Copyright (c) 2001, 2002, Oracle Corporation. All rights reserved. */ +/* + + NAME + cdemosp.c - Basic OCI Session Pooling functionality + + DESCRIPTION + + + This program invokes multiple threads to insert MAXTHREAD records + into EMPLOYEES table. + This program assumes that sample HR schema is setup. + + MODIFIED (MM/DD/YY) + msowdaga 04/30/08 - Fix bug 6236196, multiple threads should not share + single error handle + sudsrini 12/26/02 - Use different empnos to insert, than 1-10 + jchai 01/28/02 - Merged jchai_change_oci_sp_sc_cp_names + sudsrini 01/08/02 - Merged sudsrini_enable_sp_sc_suite + sudsrini 12/30/01 - Lint Fix + abande 12/07/01 - Creation + +*/ + +#ifndef OCISP_ORACLE +# include +#endif + +/* Maximum Number of threads */ +#define MAXTHREAD 10 +static ub4 sessMin = 3; +static ub4 sessMax = 8; +static ub4 sessIncr = 5; + +static OCIError *errhp; +static OCIEnv *envhp; +static OCISPool *poolhp=(OCISPool *) 0; +static int employeeNum[MAXTHREAD]; + +static OraText *poolName; +static ub4 poolNameLen; +static CONST OraText *database = (text *)""; +static CONST OraText *appusername =(text *)"hr"; +static CONST OraText *apppassword =(text *)"hr"; + +/* Values to be inserted into EMP table */ +static char firstname[10][10]={"A","B","C","D","E","F","G","H","I","J"}; +static char lastname[10][10]={"A","B","C","D","E","F","G","H","I","J"}; +static char email[10][20]={"A@oracle.com","B@oracle.com","C@oracle.com", + "D@oracle.com","E@oracle.com","F@oracle.com", + "G@oracle.com","H@oracle.com","I@oracle.com", + "J@oracle.com"}; + +static char ejob[10][11]={"FI_ACCOUNT","AC_ACCOUNT","SA_MAN","PU_MAN", + "PU_CLERK","IT_PROG","MK_REP","AD_VP","AC_MGR", + "HR_REP"}; +static float esal[10]={10000.00, + 5000.00, + 8000.00, + 6000.00, + 10000.00, + 8000.00, + 6000.00, + 6000.00, + 5000.00, + 5000.00}; + +static char hiredate[10][10]={"07-JUN-94","08-JAN-94","18-JUL-97", + "21-FEB-96","02-JUL-96","13-AUG-99", + "28-DEC-98","27-SEP-96","01-JUL-99", "01-AUG-97"}; + +static unsigned int edept[10] = {10,20,10,20,30,10,30,20,10,20}; + +static void checkerr (OCIError *errhp, sword status); +static void threadFunction (dvoid *arg); + +int main(void) +{ + int i = 0; + sword lstat; + int timeout =1; + OCIEnvCreate (&envhp, OCI_THREADED, (dvoid *)0, NULL, + NULL, NULL, 0, (dvoid *)0); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &poolhp, OCI_HTYPE_SPOOL, + (size_t) 0, (dvoid **) 0); + + /* Create the session pool */ + checkerr(errhp, OCIAttrSet((dvoid *) poolhp, + (ub4) OCI_HTYPE_SPOOL, (dvoid *) &timeout, (ub4)0, + OCI_ATTR_SPOOL_TIMEOUT, errhp)); + + if (lstat = OCISessionPoolCreate(envhp, errhp,poolhp, (OraText **)&poolName, + (ub4 *)&poolNameLen, database, + (ub4)strlen((const signed char *)database), + sessMin, sessMax, sessIncr, + (OraText *)appusername, + (ub4)strlen((const signed char *)appusername), + (OraText *)apppassword, + (ub4)strlen((const signed char *)apppassword), + OCI_DEFAULT)) + { + checkerr(errhp,lstat); + } + + printf("Session Pool Created \n"); + + /* Multiple threads using the session pool */ + { + OCIThreadId *thrid[MAXTHREAD]; + OCIThreadHandle *thrhp[MAXTHREAD]; + + OCIThreadProcessInit (); + checkerr (errhp, OCIThreadInit (envhp, errhp)); + for (i = 0; i < MAXTHREAD; ++i) + { + checkerr (errhp, OCIThreadIdInit (envhp, errhp, &thrid[i])); + checkerr (errhp, OCIThreadHndInit (envhp, errhp, &thrhp[i])); + } + for (i = 0; i < MAXTHREAD; ++i) + { + employeeNum[i]=i; + /* Inserting into EMP table */ + checkerr (errhp, OCIThreadCreate (envhp, errhp, threadFunction, + (dvoid *) &employeeNum[i], thrid[i], thrhp[i])); + } + for (i = 0; i < MAXTHREAD; ++i) + { + checkerr (errhp, OCIThreadJoin (envhp, errhp, thrhp[i])); + checkerr (errhp, OCIThreadClose (envhp, errhp, thrhp[i])); + checkerr (errhp, OCIThreadIdDestroy (envhp, errhp, &(thrid[i]))); + checkerr (errhp, OCIThreadHndDestroy (envhp, errhp, &(thrhp[i]))); + } + checkerr (errhp, OCIThreadTerm (envhp, errhp)); + } /* ALL THE THREADS ARE COMPLETE */ + lstat = OCISessionPoolDestroy(poolhp, errhp, OCI_DEFAULT); + + printf("Session Pool Destroyed \n"); + + if (lstat != OCI_SUCCESS) + checkerr(errhp, lstat); + + checkerr(errhp, OCIHandleFree((dvoid *)poolhp, OCI_HTYPE_SPOOL)); + + checkerr(errhp, OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR)); + return 0; + +} /* end of main () */ + +/* Inserts records into EMP table */ +static void threadFunction (dvoid *arg) +{ + int empno = *(int *)arg; + OCISvcCtx *svchp = (OCISvcCtx *) 0; + text insertst1[256]; + OCIStmt *stmthp = (OCIStmt *)0; + OCIError *errhp2 = (OCIError *) 0; + OCIAuthInfo *authp = (OCIAuthInfo *)0; + sword lstat; + text name[10]; + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp2, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + lstat = OCIHandleAlloc((dvoid *) envhp, + (dvoid **)&authp, (ub4) OCI_HTYPE_AUTHINFO, + (size_t) 0, (dvoid **) 0); + if (lstat) + checkerr(errhp2, lstat); + + checkerr(errhp2, OCIAttrSet((dvoid *) authp,(ub4) OCI_HTYPE_AUTHINFO, + (dvoid *) appusername, (ub4) strlen((char *)appusername), + (ub4) OCI_ATTR_USERNAME, errhp2)); + + checkerr(errhp2,OCIAttrSet((dvoid *) authp,(ub4) OCI_HTYPE_AUTHINFO, + (dvoid *) apppassword, (ub4) strlen((char *)apppassword), + (ub4) OCI_ATTR_PASSWORD, errhp2)); + + if (lstat = OCISessionGet(envhp, errhp2, &svchp, authp, + (OraText *)poolName, (ub4)strlen((char *)poolName), NULL, + 0, NULL, NULL, NULL, OCI_SESSGET_SPOOL)) + { + checkerr(errhp2,lstat); + } + + (void) sprintf(insertst1,"INSERT INTO EMPLOYEES (employee_id, first_name,\ + last_name, email, hire_date, job_id, salary, department_id)\ + values (%d, '%s', '%s', '%s', '%s', '%s',%7.2f, %d )", + empno+2345,firstname[empno],lastname[empno], email[empno], + hiredate[empno], ejob[empno], esal[empno], edept[empno]); + + OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + checkerr(errhp2, OCIStmtPrepare (stmthp, errhp2, (CONST OraText *)insertst1, + (ub4)strlen((const signed char *)insertst1), + OCI_NTV_SYNTAX, OCI_DEFAULT)); + + checkerr(errhp2, OCIStmtExecute (svchp, stmthp, errhp2, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, + OCI_DEFAULT )); + + checkerr(errhp2, OCITransCommit(svchp,errhp2,(ub4)0)); + + printf("Insert complete \n"); + + checkerr(errhp2, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + checkerr(errhp2, OCISessionRelease(svchp, errhp2, NULL, 0, OCI_DEFAULT)); + OCIHandleFree((dvoid *)authp, OCI_HTYPE_AUTHINFO); + OCIHandleFree((dvoid *)errhp2, OCI_HTYPE_ERROR); + +} /* end of threadFunction (dvoid *) */ + +/* This function prints the error */ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} diff --git a/cdemosp.h b/cdemosp.h new file mode 100644 index 0000000..4216252 --- /dev/null +++ b/cdemosp.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2002, Oracle Corporation. All rights reserved. */ + +/* + NAME + cdemosp.h - OCI Session Pool demo program header + + + MODIFIED (MM/DD/YY) + jchai 01/28/02 - Merged jchai_change_oci_sp_sc_cp_names + sudsrini 01/08/02 - Merged sudsrini_enable_sp_sc_suite + sudsrini 01/03/02 - Creation + +*/ + +#ifndef ORATYPES +# include +#endif + +#ifndef OCI_ORACLE +# include +#endif + +#include +#include +#include + +#ifndef OCISP_ORACLE +# define OCISP_ORACLE + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + EXPORT FUNCTIONS + ---------------------------------------------------------------------------*/ + +int main (void); + +/*--------------------------------------------------------------------------- + INTERNAL FUNCTIONS + ---------------------------------------------------------------------------*/ + + +#endif /* OCISP_ORACLE */ diff --git a/cdemostc.c b/cdemostc.c new file mode 100644 index 0000000..9834456 --- /dev/null +++ b/cdemostc.c @@ -0,0 +1,206 @@ +/* Copyright (c) 2001, 2002, Oracle Corporation. All rights reserved. */ +/* + NAME + cdemostc.c- OCI Statement caching functionality - basic demo + + DESCRIPTION + This program assumes that sample HR schema is setup. + Does the following steps: + o prepare a statement + o tag it + o retag the same statement and + o retreive the statement from the cache. + + MODIFIED (MM/DD/YY) + sprabhak 12/10/02 - Changed the mode to statement cache + sudsrini 01/30/02 - Rename ocisc -> cdemostc + gkirsur 01/25/02 - Merged gkirsur_stcache_tests + sudsrini 01/24/02 - Removed argc and argv as its not being used + sprabhak 01/22/02 -Incorporated review comments + sprabhak 12/15/01 - Modified + schandir 12/06/01 - Creation + +*/ +#ifndef OCISC_ORACLE +# include +#endif + +static OCIError *errhp; +static OCIEnv *envhp; +static OCIServer *svrhp = (OCIServer *)0; +static OCISession *sesnhp = (OCISession *)0; +static OCISvcCtx *svchp = (OCISvcCtx *)0; +static OCIStmt *stmthp = (OCIStmt *)0; + +static CONST OraText *database = (OraText *)""; +static CONST OraText *username = (OraText *)"hr"; +static CONST OraText *password = (OraText *)"hr"; + + +int main(void) +{ + int i = 0; + sword lstat; + + OCIEnvCreate ((OCIEnv **)&envhp, (ub4)OCI_THREADED, (dvoid *)0, + (dvoid * (*) (dvoid *, size_t))0, (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *))0, (size_t)0, (dvoid **)0); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + lstat = OCILogon2(envhp, errhp, &svchp, username + , (ub4)strlen ((char *)username),password + , (ub4)strlen ((char *)password), database + , (ub4)strlen((char *)database),OCI_LOGON2_STMTCACHE); + + if (lstat) + checkerr(errhp, lstat); + + queryRows(svchp); + + /* close connection */ + lstat = OCILogoff(svchp, errhp); + if (lstat) + checkerr(errhp, lstat); + + checkerr(errhp, OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR)); + + return 0; +} /* end of main () */ + + +/* Displays the contents of EMP table */ +static void queryRows(OCISvcCtx *svchp) +{ + sword status = 0; + static text *upd=(text *) + "update employees set salary = 20000 WHERE employee_id = 10"; + int i; + static CONST text *tag = (text *)"tagA"; + static CONST text *tag1 =(text *)"tagB"; + + /* Calling OCIStmtPrepare2 with a SQLtext specified */ + + status= OCIStmtPrepare2 ((OCISvcCtx *)svchp,(OCIStmt **)&stmthp, + (OCIError *)errhp, (text *)upd, (ub4)strlen((char *)upd), + NULL,0,OCI_NTV_SYNTAX,OCI_DEFAULT); + + if (status != OCI_SUCCESS ) + { + printf("OCIStmtPrepare2 Failure...\n"); + checkerr(errhp, status); + } + else + { + printf("OCIStmtPrepare2 Success...\n"); + } + + /*Tag the statement prepared*/ + status=OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,tag , + (ub4)strlen((char *)tag),OCI_DEFAULT); + + if ( status != OCI_SUCCESS ) + { + printf("OCIStmtRelease Failure...\n"); + checkerr(errhp, status); + } + else + { + printf("OCIStmtRelease Success...\n"); + } + status= OCIStmtPrepare2 ((OCISvcCtx *)svchp,(OCIStmt **)&stmthp, + (OCIError *)errhp, (text *)upd, (ub4)strlen((char *)upd), tag, + (ub4)strlen((char *)tag), OCI_NTV_SYNTAX, OCI_DEFAULT); + + if ( status != OCI_SUCCESS ) + { + printf("OCIStmtPrepare2 Failure...\n"); + checkerr(errhp, status); + } + else + { + printf("OCIStmtPrepare2 Success...\n"); + } + + /*Retag the statement with a different tag*/ + status=OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,tag1, + (ub4)strlen((char *)tag1), OCI_DEFAULT); + if ( status != OCI_SUCCESS ) + { + printf("OCIStmtRelease Failure...\n"); + checkerr(errhp, status); + } + else + { + printf("OCIStmtRelease Success...\n"); + } + /*Trying to get the statement with the tag */ + status= OCIStmtPrepare2 ((OCISvcCtx *)svchp,(OCIStmt **)&stmthp, + (OCIError *)errhp, (text *)upd, (ub4)strlen((char *)upd), tag1, + (ub4)strlen((char *)tag1), OCI_NTV_SYNTAX, OCI_DEFAULT); + + if ( status != OCI_SUCCESS ) + { + printf("OCIStmtPrepare2 Failure...\n"); + checkerr(errhp, status); + } + else + { + printf("OCIStmtPrepare2 Success...\n"); + } + /*Now releasing the stmt back to the cache*/ + status=OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,tag1, + (ub4)strlen((char *)tag1), OCI_DEFAULT); + if ( status != OCI_SUCCESS ) + { + printf("OCIStmtRelease Failure...\n"); + checkerr(errhp, status); + } + else + { + printf("OCIStmtRelease Success...\n"); + } + + +} /* end of queryRows() */ + + +/* This function prints the error */ +void checkerr(OCIError *errhp,sword status) +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + + default: + break; + } +} + diff --git a/cdemostc.h b/cdemostc.h new file mode 100644 index 0000000..bc010ee --- /dev/null +++ b/cdemostc.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2002, Oracle Corporation. All rights reserved. */ + +/* + NAME + cdemostc.h - OCI Statement caching + + + MODIFIED (MM/DD/YY) + sudsrini 01/30/02 - Rename ocisc -> cdemostc + gkirsur 01/25/02 - Merged gkirsur_stcache_tests + sudsrini 01/24/02 - Removed argc and argv from main definition + sprabhak 01/22/02 - Incorporated Review comments + sprabhak 01/10/02 - Creation + +*/ + +#ifndef ORATYPES +# include +#endif + +#ifndef OCI_ORACLE +# include +#endif + +#include +#include +#include + +#ifndef OCISC_ORACLE +# define OCISC_ORACLE + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + EXPORT FUNCTIONS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + INTERNAL FUNCTIONS + ---------------------------------------------------------------------------*/ + +int main(void); +static void checkerr (OCIError *errhp, sword status); +static void queryRows(OCISvcCtx *svchp); + +#endif /* OCISC_ORACLE */ diff --git a/cdemosyev.c b/cdemosyev.c new file mode 100644 index 0000000..e09d235 --- /dev/null +++ b/cdemosyev.c @@ -0,0 +1,402 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemosyev.c 26-jan-00.08:39:37 mrhodes Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) Oracle Corporation 1998, 1999, 2000. All Rights Reserved. */ + +/* + + NAME + cdemosyev.c - C DEMO for registration for SYstem EVents + + DESCRIPTION + This program demonstrates registration for predefined subscriptions. + At time of registration a callback function is specified which is + invoked when the client needs to be notified. + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + should run cdemosyev.sql before running this program + + MODIFIED (MM/DD/YY) + mrhodes 01/26/00 - adjust ifdef + mpjoshi 07/30/99 - resolve merge conflict + mpjoshi 07/28/99 - make 'sleep' call nt compatible + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + sasuri 11/23/98 - add shutdown notification + sasuri 06/16/98 - system event demo files + sasuri 06/16/98 - Creation + +*/ + +/* for WINDOWS compatibility of 'sleep' call */ +#if defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32) +#include +#define sleep(x) Sleep(1000*(x)) +#endif + +#include +#include +#include +#include +#include + +static text *username = (text *) "PUBSUB"; +static text *password = (text *) "PUBSUB"; +static int count = 0; +ub4 namespace = OCI_SUBSCR_NAMESPACE_AQ; + +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCIError *errhp; +static OCISvcCtx *svchp; + +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void cleanup(/*_ void _*/); +static void myfflush(/*_ void _*/); +void initSubscriptionHn (); +int main(); + +static sword status; + +/* define all callback functions */ + +/* callback function for notification of server error events */ + +ub4 notifyDropSch(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + printf("Notification : Drop on Schema\n"); + return (0); +} + +ub4 notifyError(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + printf("Notification : Error Event\n"); + return (0); +} + +/* for startup */ + +ub4 notifyStartup(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + printf("Notification : Startup of Database\n"); + return (0); +} + + +/* for shutdown */ + +ub4 notifyShutdown(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + count++; + printf("Notification : Shutdown of Database\n"); + return (0); +} + + +ub4 notifyLogon(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + printf("Notification : Logon on Database\n"); + return (0); +} + +ub4 notifySnoop(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + printf("Notification : User EVENT Logged on\n"); + return (0); +} + + +ub4 notifyLogoff(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + printf("Notification : Logoff on Database\n"); + return (0); +} + + +ub4 notifyCreateSch(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + printf("Notification : Create on Schema\n"); + return (0); +} + +int main() +{ + OCISession *authp = (OCISession *) 0; + OCISubscription *subscrhpErr = (OCISubscription *)0; + OCISubscription *subscrhpStartup = (OCISubscription *)0; + OCISubscription *subscrhpShutdown = (OCISubscription *)0; + OCISubscription *subscrhpLogon = (OCISubscription *)0; + OCISubscription *subscrhpLogoff = (OCISubscription *)0; + OCISubscription *subscrhpCreate = (OCISubscription *)0; + OCISubscription *subscrhpDrop = (OCISubscription *)0; + OCISubscription *subscrhpSnoop = (OCISubscription *)0; + + printf("Initializing OCI Process\n"); + + (void) OCIInitialize((ub4) OCI_EVENTS|OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 ); + + printf("Initialization successful\n"); + + printf("Initializing OCI Env\n"); + (void) OCIEnvInit( (OCIEnv **) &envhp, OCI_DEFAULT, (size_t) 0, + (dvoid **) 0 ); + printf("Initialization successful\n"); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + + (size_t) 0, (dvoid **) 0); + + /* Set server contexts */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0); + + printf("connecting to server\n"); + (void) OCIServerAttach( srvhp, errhp, (text *)"", strlen(""), 0); + printf("connect successful\n"); + + /* set attribute server context in the service context */ + (void) OCIAttrSet( (dvoid *) svchp, OCI_HTYPE_SVCCTX, (dvoid *)srvhp, + (ub4) 0, OCI_ATTR_SERVER, (OCIError *) errhp); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **)&authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0); + + (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) username, (ub4) strlen((char *)username), + (ub4) OCI_ATTR_USERNAME, errhp); + + (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *)password), + (ub4) OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin ( svchp, errhp, authp, OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)); + + (void) OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, + (ub4) OCI_ATTR_SESSION, errhp); + + + /* Registration Code */ + + /* each call to initSubscriptionHn allocates + and initialises a registration handle */ + + initSubscriptionHn( &subscrhpErr, + "PUBSUB.ERROR:ADMIN", + (dvoid*)notifyError); + + initSubscriptionHn( &subscrhpStartup, + "PUBSUB.STARTUP:ADMIN", + (dvoid*)notifyStartup); + + initSubscriptionHn( &subscrhpShutdown, + "PUBSUB.SHUTDOWN:ADMIN", + (dvoid*)notifyShutdown); + + initSubscriptionHn( &subscrhpLogon, + "PUBSUB.LOGON:ADMIN", + (dvoid*)notifyLogon); + + initSubscriptionHn( &subscrhpLogoff, + "PUBSUB.LOGOFF:ADMIN", + (dvoid*)notifyLogoff); + + initSubscriptionHn( &subscrhpCreate, + "PUBSUB.CREATE_SCH:ADMIN", + (dvoid*)notifyCreateSch); + + initSubscriptionHn( &subscrhpDrop, + "PUBSUB.DROP_SCH:ADMIN", + (dvoid*)notifyDropSch); + + initSubscriptionHn( &subscrhpSnoop, + "PUBSUB.LOGON:SNOOP", + (dvoid*)notifySnoop); + + /* end session */ + checkerr(errhp, OCISessionEnd ( svchp, errhp, authp, (ub4) OCI_DEFAULT)); + + /* detach from server */ + OCIServerDetach( srvhp, errhp, OCI_DEFAULT); + + while (count != 2) + sleep(1); +} + + +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, + &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +/* + * Exit program with an exit code. + */ +void cleanup() +{ + if (errhp) + (void) OCIServerDetach( srvhp, errhp, OCI_DEFAULT ); + if (srvhp) + checkerr(errhp, OCIHandleFree((dvoid *) srvhp, OCI_HTYPE_SERVER)); + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, OCI_HTYPE_SVCCTX); + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + return; +} + + +void myfflush() +{ + eb1 buf[50]; + + fgets((char *) buf, 50, stdin); +} + + +void initSubscriptionHn (subscrhp, +subscriptionName, +func) + +OCISubscription **subscrhp; +char* subscriptionName; +dvoid * func; +{ + + /* allocate subscription handle */ + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **)subscrhp, + (ub4) OCI_HTYPE_SUBSCRIPTION, + (size_t) 0, (dvoid **) 0); + /* set subscription name in handle */ + + (void) OCIAttrSet((dvoid *) *subscrhp, (ub4) OCI_HTYPE_SUBSCRIPTION, + (dvoid *) subscriptionName, + (ub4) strlen((char *)subscriptionName), + (ub4) OCI_ATTR_SUBSCR_NAME, errhp); + + /* set callback function in handle */ + + (void) OCIAttrSet((dvoid *) *subscrhp, (ub4) OCI_HTYPE_SUBSCRIPTION, + (dvoid *) func, (ub4) 0, + (ub4) OCI_ATTR_SUBSCR_CALLBACK, errhp); + + (void) OCIAttrSet((dvoid *) *subscrhp, (ub4) OCI_HTYPE_SUBSCRIPTION, + (dvoid *) 0, (ub4) 0, + (ub4) OCI_ATTR_SUBSCR_CTX, errhp); + + + /* set namespace in handle */ + + (void) OCIAttrSet((dvoid *) *subscrhp, (ub4) OCI_HTYPE_SUBSCRIPTION, + (dvoid *) &namespace, (ub4) 0, + (ub4) OCI_ATTR_SUBSCR_NAMESPACE, errhp); + printf("Begining Registration for subscription %s\n", subscriptionName); + checkerr(errhp, OCISubscriptionRegister(svchp, subscrhp, 1, errhp, + + OCI_DEFAULT)); + printf("done\n"); +} + +/* end of file cdemosyev.c */ diff --git a/cdemosyev.sql b/cdemosyev.sql new file mode 100644 index 0000000..75cdc7d --- /dev/null +++ b/cdemosyev.sql @@ -0,0 +1,339 @@ +rem +rem $Header: cdemosyev.sql 14-nov-00.18:39:09 hdnguyen Exp $ +rem +rem cdemosyev.sql +rem +rem Copyright (c) 1998, 1999,, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemosyev.sql - C DEMO for SYstem EVents +rem +rem DESCRIPTION +rem This Demo script creates users and schema objects necessary +rem for setting up system event triggers and subscriptions using +rem Advanced Queues (AQ). +rem The following are created: +rem triggers which fire on the events +rem queue table, used by persistent queues for storage +rem queues to which triggers enqueue messages +rem subscriptions to queues +rem +rem +rem NOTES +rem This file should be executed before running the OCI registration +rem Script cdemosyev.c, followed by cdemosyex.sql + +rem This script will setup the users and schema objects required for +rem creating subscriptions. After executing this file, cdemosyev.c +rem should be executed. On execution the user should see, on the +rem standard output, messages indicating successful registration for +rem various subscriptions. During the registration process the user +rem specifies a callback function which is invoked when the user needs +rem to be notified. +rem The script cdemosyex performs a set of actions for each of which the +rem corresponding callback function is invoked at the user end. + +rem MODIFIED (MM/DD/YY) +rem hdnguyen 11/14/00 - fixed connect internal +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem sasuri 11/23/98 - add shutdown notification +rem sasuri 06/16/98 - system event demo files +rem sasuri 06/16/98 - Created +rem + +connect / as sysdba; +set serveroutput on +set echo on + +rem --------------------------------------------------------------------------- +rem +rem Set up a user with appropriate privileges +rem +rem --------------------------------------------------------------------------- + +create user event identified by event; +grant dba to event; + +create user pubsub identified by pubsub; +grant connect, resource, dba to pubsub; +grant AQ_ADMINISTRATOR_ROLE, AQ_USER_ROLE to pubsub; +grant select_catalog_role to pubsub; +grant execute on dbms_aq to pubsub; +execute dbms_aqadm.grant_type_access('pubsub'); +execute dbms_aqadm.grant_system_privilege('ENQUEUE_ANY','pubsub',FALSE); +execute dbms_aqadm.grant_system_privilege('DEQUEUE_ANY','pubsub',FALSE); +connect pubsub/pubsub; + +rem --------------------------------------------------------------------------- +rem +rem create queue tables for persistent multiple consumers +rem +rem --------------------------------------------------------------------------- + +connect pubsub/pubsub; + +rem Create or replace a queue table +begin +DBMS_AQADM.CREATE_QUEUE_TABLE( + QUEUE_TABLE=>'pubsub.raw_msg_table', + MULTIPLE_CONSUMERS => TRUE, + QUEUE_PAYLOAD_TYPE =>'RAW', + COMPATIBLE => '8.1.3'); +end; +/ + +rem --------------------------------------------------------------------------- +rem +rem Create various persistent queues for publishing messages +rem +rem --------------------------------------------------------------------------- + +rem Create a queue for error events +begin +DBMS_AQADM.CREATE_QUEUE(QUEUE_NAME=>'pubsub.error', + QUEUE_TABLE=>'pubsub.raw_msg_table', + COMMENT=>'Q for error triggers'); +end; +/ + +rem Create a queue for startup +begin +DBMS_AQADM.CREATE_QUEUE(QUEUE_NAME=>'pubsub.startup', + QUEUE_TABLE=>'pubsub.raw_msg_table', + COMMENT=>'Q for startup triggers'); +end; +/ + +rem Create a queue for shutdown +begin +DBMS_AQADM.CREATE_QUEUE(QUEUE_NAME=>'pubsub.shutdown', + QUEUE_TABLE=>'pubsub.raw_msg_table', + COMMENT=>'Q for shutdown triggers'); +end; +/ + +rem Create a queue for logon events +begin +DBMS_AQADM.CREATE_QUEUE(QUEUE_NAME=>'pubsub.logon', + QUEUE_TABLE=>'pubsub.raw_msg_table', + COMMENT=>'Q for logon triggers'); +end; +/ + +rem Create a queue for logoff events +begin +DBMS_AQADM.CREATE_QUEUE(QUEUE_NAME=>'pubsub.logoff', + QUEUE_TABLE=>'pubsub.raw_msg_table', + COMMENT=>'Q for logoff triggers'); +end; +/ + +rem --------- Create non-persistent queues ----------------------- + +rem Create a queue for create on schema events +begin +DBMS_AQADM.CREATE_NP_QUEUE(QUEUE_NAME=>'pubsub.create_sch', + MULTIPLE_CONSUMERS => TRUE); +end; +/ + +begin +DBMS_AQADM.CREATE_NP_QUEUE(QUEUE_NAME=>'pubsub.drop_sch', + MULTIPLE_CONSUMERS => TRUE); +end; +/ + +rem --------------------------------------------------------------------------- +rem +rem Start all queues +rem +rem --------------------------------------------------------------------------- + + +begin +DBMS_AQADM.START_QUEUE('pubsub.error'); +DBMS_AQADM.START_QUEUE('pubsub.startup'); +DBMS_AQADM.START_QUEUE('pubsub.shutdown'); +DBMS_AQADM.START_QUEUE('pubsub.logon'); +DBMS_AQADM.START_QUEUE('pubsub.logoff'); +DBMS_AQADM.START_QUEUE('pubsub.create_sch'); +DBMS_AQADM.START_QUEUE ('pubsub.drop_sch'); + +end; +/ + +rem --------------------------------------------------------------------------- +rem +rem define new_enqueue/new_np_enqueue for convenience +rem +rem --------------------------------------------------------------------------- + + +create or replace procedure new_enqueue(queue_name in varchar2, + payload in raw , + correlation in varchar2 := NULL, + exception_queue in varchar2 := NULL) +as + +enq_ct dbms_aq.enqueue_options_t; +msg_prop dbms_aq.message_properties_t; +enq_msgid raw(16); +userdata raw(1000); + +begin + msg_prop.exception_queue := exception_queue; + msg_prop.correlation := correlation; + userdata := payload; + + DBMS_AQ.ENQUEUE(queue_name, enq_ct, msg_prop, userdata, enq_msgid); +end; +/ +grant execute on new_enqueue to public; + +create or replace procedure new_np_enqueue(queue varchar2, + id integer, + correlation varchar2) +as + +msgprop dbms_aq.message_properties_t; +enqopt dbms_aq.enqueue_options_t; +enq_msgid raw(16); +payload raw(10); + +begin + payload := hextoraw('123'); + enqopt.visibility:=dbms_aq.IMMEDIATE; + msgprop.correlation:=correlation; + DBMS_AQ.ENQUEUE( queue, enqopt, msgprop, payload, enq_msgid); +end; +/ + +grant execute on new_np_enqueue to public; + +rem --------------------------------------------------------------------------- +rem +rem create subscriptions to all event-publications for agent 'ADMIN' +rem +rem --------------------------------------------------------------------------- + + + +DECLARE + +subscriber sys.aq$_agent; + +begin + +subscriber := sys.aq$_agent('admin', null, null); + +dbms_aqadm.add_subscriber(queue_name => 'pubsub.error', + subscriber => subscriber); + +dbms_aqadm.add_subscriber(queue_name => 'pubsub.startup', + subscriber => subscriber); + +dbms_aqadm.add_subscriber(queue_name => 'pubsub.shutdown', + subscriber => subscriber); + +dbms_aqadm.add_subscriber(queue_name => 'pubsub.logoff', + subscriber => subscriber); + +dbms_aqadm.add_subscriber(queue_name => 'pubsub.logon', + subscriber => subscriber); + +dbms_aqadm.add_subscriber(queue_name => 'pubsub.create_sch', + subscriber => subscriber); + +dbms_aqadm.add_subscriber(queue_name => 'pubsub.drop_sch', + subscriber => subscriber); +end; +/ + +rem --------------------------------------------------------------------------- +rem +rem add subscriber with rule based on curent user name, using correlation_id +rem +rem --------------------------------------------------------------------------- + +declare +subscriber sys.aq$_agent; +begin +subscriber := sys.aq$_agent('SNOOP', null, null); +dbms_aqadm.add_subscriber(queue_name => 'pubsub.logon', + subscriber => subscriber, + rule => 'CORRID = ''EVENT'' '); +end; +/ + +rem --------------------------------------------------------------------------- +rem +rem now create triggers on various events +rem +rem --------------------------------------------------------------------------- + + +rem create trigger on after server errors +create or replace trigger systrig0 + AFTER SERVERERROR + ON DATABASE + begin + new_enqueue('pubsub.error', hextoraw('9999')); + end; +/ + +rem create trigger on after startup +create or replace trigger systrig1 + AFTER STARTUP + ON DATABASE + begin + new_enqueue('pubsub.startup', hextoraw('9999')); + end; +/ + +rem create trigger on after shutdown +create or replace trigger systrig2 + BEFORE SHUTDOWN + ON DATABASE + begin + new_enqueue('pubsub.shutdown', hextoraw('9999')); + end; +/ + +rem create trigger on after logon +create or replace trigger systrig3 + AFTER LOGON + ON DATABASE + begin + new_enqueue('pubsub.logon', hextoraw('9999'), dbms_standard.login_user); + end; +/ + +rem create trigger on before logoff +create or replace trigger systrig4 + BEFORE LOGOFF + ON DATABASE + begin + new_enqueue('pubsub.logoff', hextoraw('9999')); + end; +/ + +rem create trigger on after create on sch +create or replace trigger systrig5 + AFTER CREATE + ON SCHEMA + begin + new_np_enqueue('pubsub.create_sch', 1, 'non persistent'); + end; +/ + +rem create trigger on after drop on sch + +create or replace trigger systrig6 + AFTER DROP + ON SCHEMA + begin + new_np_enqueue('pubsub.drop_sch', 1, 'non persistent'); + end; +/ + +disconnect diff --git a/cdemosyex.sql b/cdemosyex.sql new file mode 100644 index 0000000..72e86c0 --- /dev/null +++ b/cdemosyex.sql @@ -0,0 +1,43 @@ +rem +rem $Header: cdemosyex.sql 14-nov-00.18:39:15 hdnguyen Exp $ +rem +rem cdemosyex.sql +rem +rem Copyright (c) 1998, 1999,, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemosyex.sql - C DEMO for executing SYstem EVents +rem +rem DESCRIPTION +rem This SQL script causes the triggers, defined in cdemosyev.sql, +rem to fire. This results in enqueueing of message(s) into queue(s). +rem If there are subscription defined on the queue that are satisfied, +rem a list of recipients are computed. All registered recipients are +rem notified by invoking callback functions. +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem hdnguyen 11/14/00 - fixed connect internal +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem sasuri 11/23/98 - add shutdown notification +rem sasuri 06/16/98 - system event demo files +rem sasuri 06/16/98 - Created +rem + +connect event/event +drop table foo; +create table foo(n number); +drop table foo; +connect foo/bar +connect pubsub/pubsub +drop table foo; +create table foo(n number); +drop table foo; +disconnect +connect / as sysdba +shutdown +connect / as sysdba +startup +shutdown diff --git a/cdemothr.c b/cdemothr.c new file mode 100644 index 0000000..016d374 --- /dev/null +++ b/cdemothr.c @@ -0,0 +1,587 @@ +/* Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemothr.c - C Demo for ociTHRead + + DESCRIPTION + This file demonstrates an example of using the OCIThread package + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + msowdaga 04/30/08 - Fix bug 6236196, multiple threads should not share + single error handle + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + tsaulys 10/14/98 - minor changes + nramakri 12/17/97 - Creation + +*/ + +#include +#include +#include +#include +#include + +static OCIEnv *envhp; +static OCIError *errhp; + +static void ThrKeyDestroy(/*_ dvoid *arg _*/); +static void ThrFunc(/*_ dvoid *arg _*/); +static int ThrMain(/*_ void _*/); +static sword checkerr(/*_ OCIError *errhp, sword status _*/); +int main(/*_ int argc, char *argv[] _*/); + +int main(argc, argv) +int argc; +char *argv[]; +{ + int status = 0; + + (void) OCIInitialize((ub4) OCI_THREADED, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 ); + + (void) OCIEnvInit( (OCIEnv **) &envhp, OCI_DEFAULT, (size_t) 0, + (dvoid **) 0 ); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + status = ThrMain(); + + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + + return status; +} + +sword checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + default: + break; + } + return status; +} + +/*--------------------------- ThrKeyDestroy() --------------------------*/ + +/* + NAME + ThrKeyDestroy - Thread Key Destructor Function + + DESCRIPTION + This is the destructor function used with the 'key_' element of the + 'CDemoThrCtx' data type. See 'thrdemo.h' for info on the + datatype. + + PARAMETERS + void ThrKeyDestroy(dvoid *arg) + + arg This will be the key's value for the thread that just + terminated. + + RETURNS + Nothing. + + NOTES + This sends a diagnostic message to 'stdout' if it is called with a NULL + arg. + + Otherwise, it sets the 'ub1' pointed to by 'arg' to FALSE. +*/ + +static void ThrKeyDestroy(arg) +dvoid *arg; +{ + ub1 *loc = (ub1 *) arg; + + if (arg == (dvoid *)NULL) + { + printf("Key destructor called with NULL argument.\n"); + } + else + *loc = FALSE; + + return; +} + +/*----------------------------- ThrFunc() ------------------------------*/ + +/* + NAME + ThrFunc - Thread Function + + DESCRIPTION + This is the function that gets spawned as a separate thread by + 'ThrMain()'. + + PARAMETERS + void ThrFunc(dvoid *arg) + + arg This should point to the 'CDemoThrCtx' being used + + RETURNS + Nothing. + + NOTES + This sends a diagnostic message to 'stdout' if something unexpected + happens. + +*/ + +static void ThrFunc(arg) +dvoid *arg; +{ + CDemoThrCtx *tdctx = (CDemoThrCtx *) arg; + OCIError *errhp2 = (OCIError *) 0; + OCIThreadId *ourID; /* This eventually gets this thread's ID. */ + sword ourTNum; /* Eventually, this gets our thread number. */ + uword i; /* Loop counter. */ + uword flag; /* Boolean flag. */ + dvoid *keyval; /* Used to retrieve values from a key. */ + boolean result1, result2; + + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp2, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + /* ***** INITIALIZATION ***** */ + + if (checkerr(errhp2, OCIThreadIdInit(envhp, errhp2, &ourID)) != OCI_SUCCESS) + goto exit0; + + /* ***** THREAD ID MANIPULATION ***** */ + + if (checkerr(errhp2, OCIThreadIdGet(envhp, errhp2, ourID)) != OCI_SUCCESS) + goto exit1; + + /* Make sure the ID we just got is not NULL, and is not the same as the */ + /* ID for the main thread. */ + + (void) checkerr(errhp2, OCIThreadIdNull(envhp, errhp2, ourID, &result1)); + (void) checkerr(errhp2, OCIThreadIdSame(envhp, errhp2, ourID, + tdctx->mainTID_CDemoThrCtx, &result2)); + if ((result1 == TRUE) || + (result2 == ((OCIThreadIsMulti() == TRUE) ? TRUE : FALSE))) + { + printf("A spawned thread's ID doesn't seem to be valid.\n"); + } + + /* ***** DETERMINE THREAD NUMBER ***** */ + + ourTNum = -1; + + /* We need to search the 'tdctx->tidAr[]' array. First, we must acquire */ + /* its mutex. */ + (void) checkerr(errhp2, OCIThreadMutexAcquire(envhp, errhp2, + tdctx->tidArMx_CDemoThrCtx)); + + /* Search 'tdctx->tidAr[]'. */ + for (i = 0; i < CDEMOTHR_NUMTHREADS; i++) + { + (void) checkerr(errhp2, OCIThreadIdSame(envhp, errhp2, ourID, + tdctx->tidAr_CDemoThrCtx[i], &result1)); + if (result1 == TRUE) + { + ourTNum = (sword) i; + break; + } + } + + /* We are done with the array. We can release its mutex. */ + (void) checkerr(errhp2, OCIThreadMutexRelease(envhp, errhp2, + tdctx->tidArMx_CDemoThrCtx)); + + if (ourTNum == -1) + { + /* We couldn't find our thread ID. */ + printf("A thread's ID was not in the ID array.\n"); + + /* There is nothing more we can do. We should just terminate. */ + goto exit1; + } + + /* ***** SAVE OUR THREAD NUMBER IN THE NUMBER ARRAY ***** */ + + /* We can indicate everything is OK by putting our thread number in the */ + /* array of thread numbers. */ + (tdctx->tnumAr_CDemoThrCtx)[ourTNum] = ourTNum; + + /* ***** USING KEYS ***** */ + + /* With 'tdctx->key_', we will check that the initial value is NULL, and */ + /* that we can set and retrieve values correctly. */ + + if (checkerr(errhp2, OCIThreadKeyGet(envhp, errhp2, tdctx->key_CDemoThrCtx, + &keyval)) != OCI_SUCCESS) + { + printf("Could not retrieve initial value from key.\n"); + } + + if (keyval != (dvoid *)NULL) + { + printf("Initial value of the key is not NULL.\n"); + } + + if (checkerr(errhp2, OCIThreadKeySet(envhp, errhp2, tdctx->key_CDemoThrCtx, + (dvoid *) &ourTNum)) + != OCI_SUCCESS) + { + printf("Could not set the value of key.\n"); + } + + if (checkerr(errhp2, OCIThreadKeyGet(envhp, errhp2, tdctx->key_CDemoThrCtx, + &keyval)) != OCI_SUCCESS) + { + printf("Could not retrieve value of key after it was set.\n"); + } + + if (keyval != (dvoid *) &ourTNum) + { + printf("Incorrect value from key after setting it.\n"); + } + + /* For 'tdctx->key_', we will now set the value in the key to point to */ + /* our element in 'tdctx->key_'. Then, some threads will reset the value */ + /* to NULL and clear the element in 'tdctx->key_' to FALSE. */ + + if (checkerr(errhp2, OCIThreadKeySet(envhp, errhp2, tdctx->key_CDemoThrCtx, + (dvoid *)&(tdctx->keyAr_CDemoThrCtx[ourTNum]))) + != OCI_SUCCESS) + { + printf("Could not set value in key.\n"); + } + + if (ourTNum < (CDEMOTHR_NUMTHREADS/2)) + { + if (checkerr(errhp2, OCIThreadKeySet(envhp, errhp2, tdctx->key_CDemoThrCtx, + (dvoid *)NULL)) != OCI_SUCCESS) + { + printf("Could not set value in key to NULL.\n"); + } + tdctx->keyAr_CDemoThrCtx[ourTNum] = FALSE; + } + + /* ***** TERMINATION ***** */ + + /* This is the exit point. This terminates the OCITHREAD context (if it */ + /* is not NULL), and returns. */ + + exit1: + (void) checkerr(errhp2, OCIThreadIdDestroy(envhp, errhp2, &ourID)); + + exit0: + OCIHandleFree((dvoid *)errhp2, OCI_HTYPE_ERROR); + return; +} + +static int ThrMain() +{ + + CDemoThrCtx tdctx; + OCIThreadId *tidArray[CDEMOTHR_NUMTHREADS]; + OCIThreadHandle *tHndArray[CDEMOTHR_NUMTHREADS]; + + uword i; /* Loop counter. */ + dvoid *keyval; /* Used to retrieve values for a key. */ + uword tJoins; /* Number of threads we join with. */ + eword demoStat; /* Set to TRUE if the test succeeded. */ + boolean result; /* For Boolean tests */ + + demoStat = TRUE; + tJoins = 0; + + /* ***** INITIALIZATION ***** */ + + /* In a multi-threaded application, 'OCIThreadProcessInit()' must be + called before anything else. In addition, the call must not be + concurrent with any other OCIThread calls. Therefore, we will make the + call here, before we spawn any threads. + */ + printf("Initializing OCIThread. \n"); + OCIThreadProcessInit(); + + if (checkerr(errhp, OCIThreadInit(envhp, errhp)) != OCI_SUCCESS) + { + demoStat = FALSE; + goto exit0; + } + + printf("Initializing the thread ID structure. \n"); + if (checkerr(errhp, OCIThreadIdInit(envhp, errhp, + &(tdctx.mainTID_CDemoThrCtx))) + != OCI_SUCCESS) + { + demoStat = FALSE; + goto exit1; + } + + /* + * Setup what we need to in 'tdctx'. + */ + + /* Put our thread ID in. */ + printf("Retrieving the current thread ID. \n"); + if (checkerr(errhp, OCIThreadIdGet(envhp, errhp, tdctx.mainTID_CDemoThrCtx)) + != OCI_SUCCESS) + { + demoStat = FALSE; + goto exit0; + } + + /* Initialize the mutex protecting the thread array. */ + printf("Intializing the mutex protecting the thread array. \n"); + if (checkerr(errhp, OCIThreadMutexInit(envhp, errhp, + &(tdctx.tidArMx_CDemoThrCtx))) + != OCI_SUCCESS) + { + demoStat = FALSE; + goto exit2; + } + + printf("Initializing all thread IDs and thread handles. \n"); + for (i = 0; i < CDEMOTHR_NUMTHREADS; i++) + { + if (checkerr(errhp, OCIThreadIdInit(envhp, errhp, &(tidArray[i]))) + != OCI_SUCCESS) + { + demoStat = FALSE; + goto exit2; + } + + if (checkerr(errhp, OCIThreadHndInit(envhp, errhp, + &(tHndArray[i]))) != OCI_SUCCESS) + { + demoStat = FALSE; + goto exit2; + } + + if (checkerr(errhp, OCIThreadIdInit(envhp, errhp, + &((tdctx.tidAr_CDemoThrCtx)[i]))) + != OCI_SUCCESS) + { + demoStat = FALSE; + goto exit2; + } + } + + /* Set the thread ID arrays (both 'tidArray' and the one in 'tdctx') to hold + only NULL thread IDs. Clear the thread number array in 'tdctx'. + */ + printf("Setting all thread IDs and thread handles to NULL. \n"); + for (i = 0; i < CDEMOTHR_NUMTHREADS; i++) + { + (void) checkerr(errhp, OCIThreadIdSetNull(envhp, errhp, tidArray[i])); + (void) checkerr(errhp, OCIThreadIdSetNull(envhp, errhp, + (tdctx.tidAr_CDemoThrCtx)[i])); + (tdctx.tnumAr_CDemoThrCtx)[i] = -1; + } + + /* Initialize 'tdctx.key_' and its array. This key will have + 'ThrKeyDestroy()' as its destructor function. + */ + printf("Initializing the thread key. \n"); + if (OCIThreadIsMulti() == TRUE) + { + (void) checkerr(errhp, OCIThreadKeyInit(envhp, errhp, + &(tdctx.key_CDemoThrCtx), + (OCIThreadKeyDestFunc)ThrKeyDestroy)); + } + else + { + (void) checkerr(errhp, OCIThreadKeyInit(envhp, errhp, + &(tdctx.key_CDemoThrCtx), NULL)); + + } + + printf("Setting the value for the thread key for each thread. \n"); + for (i = 0; i < CDEMOTHR_NUMTHREADS; i++) + { + tdctx.keyAr_CDemoThrCtx[i] = TRUE; + } + + /* ***** SPAWN OTHER THREADS ***** */ + + /* Acquire the mutex protecting the thread ID array in 'tdctx'. We will */ + /* release it once the array has been filled. */ + (void) checkerr(errhp, OCIThreadMutexAcquire(envhp, errhp, + tdctx.tidArMx_CDemoThrCtx)); + + /* Spawn all the threads. */ + printf("Spawning all threads. \n"); + for (i = 0; i < CDEMOTHR_NUMTHREADS; i++) + { + if (OCIThreadIsMulti() == TRUE) /* Multi-threaded environment */ + { + if (checkerr(errhp, OCIThreadCreate(envhp, errhp, ThrFunc, + (dvoid *) &tdctx, + tidArray[i], tHndArray[i])) + != OCI_SUCCESS) + { + demoStat = FALSE; + } + } + else + { + ThrFunc((dvoid *)&tdctx); + } + + /* Put the thread ID for the new thread in the array in 'tdctx'. */ + (void) checkerr(errhp, OCIThreadIdSet(envhp, errhp, + (tdctx.tidAr_CDemoThrCtx)[i], + tidArray[i])); + } + + /* All the threads are spawned; so 'tdctx.tidAr_CDemoThrCtx[]' is full. + We can release the mutex protecting it. + */ + (void) checkerr(errhp, OCIThreadMutexRelease(envhp, errhp, + tdctx.tidArMx_CDemoThrCtx)); + + printf("Waiting for all threads to finish. \n"); + if (OCIThreadIsMulti() == TRUE) + { + /* ***** WAIT FOR OTHER THREADS TO FINISH ***** */ + /* Wait for each thread in turn, and make sure that it put its number */ + /* in the thread number array. */ + + for (i=0; i + + PRIVATE FUNCTION(S) + + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + nramakri 12/17/97 - Creation + +*/ + +#ifndef CDEMOTHR_ORACLE +#define CDEMOTHR_ORACLE + +#include + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------- CDEMOTHR_NUMTHREADS ---------------------------*/ +/*** + Constant for the number of threads that will be spawned in demo in + a multi-threaded environment +***/ +#define CDEMOTHR_NUMTHREADS 32 + +/*-------------------------------- CDemoThrCtx---------------------------*/ +/* + CDemoThrCtx - C Demo Thread Context + + One instance of this structure is created and shared among all the threads + that are created in the demo ('CDemoThr()'). +*/ + +struct CDemoThrCtx +{ + OCIThreadId *mainTID_CDemoThrCtx; /* ID for the main thread */ + /* All of the spawned threads do a check to make sure that their thread */ + /* ID is different from that of the main thread. */ + + OCIThreadMutex *tidArMx_CDemoThrCtx; /* Mutex for 'tidAr_' */ + + /* Array of thread IDs */ + OCIThreadId *tidAr_CDemoThrCtx[CDEMOTHR_NUMTHREADS]; + /* As threads are spawned, the array is filled up with their IDs. The */ + /* mutex must be held in order for it be safe to access the array. */ + + sword tnumAr_CDemoThrCtx[CDEMOTHR_NUMTHREADS]; /* Array of thread #'s */ + /* A thread whose ID is in position 'i' in 'tidAr_' will put 'i' in */ + /* position 'i' of this array. The main thread checks this to ensure */ + /* that everything went OK. */ + + OCIThreadKey *key_CDemoThrCtx; /* Thread key */ + ub1 keyAr_CDemoThrCtx[CDEMOTHR_NUMTHREADS]; /* Values for thread key */ +}; +typedef struct CDemoThrCtx CDemoThrCtx; + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ + +#endif /* CDEMOTHR_ORACLE */ diff --git a/cdemoucb.c b/cdemoucb.c new file mode 100644 index 0000000..a6ef649 --- /dev/null +++ b/cdemoucb.c @@ -0,0 +1,621 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoucb.c 14-jul-99.13:18:11 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemoucb.c - User callback demo program + + DESCRIPTION + This program demonstrates using user callbacks. Both static + and dynamic callbacks are demonstrated. Passing of + arguments to callback routine is also demostrated. + + The program executes a create table command. Callback + routine is registered for OCIStmtPrepare(), in the comments + below OCIStmtPrepare() is mentioned but same applies to all + calls for which callbacks can be registered. + + To use dynamic callback file cdemoucbl.c needs to be linked + into a shared library using the make file provided, see + comments in cdemoucbl.c for more details. + + If environment variable ORA_OCI_UCBPKG is set then routine + OCIEnvCallback in cdemoucbl.c is called, which registers + the callback function for OCIStmtPrepare(). + + All arguments of routine OCIStmtPrepare are also passed to + callback routines, this is verified by doing a va_start + and then acquiring and printing sqlstmt passed to + OCIStmtPrepare(). + + Callback "chaining" is demonstrated as follows: If + ORA_OCI_UCBPKG is set then the dynamic callbacks are + registered first for OCIStmtPrepare. Calling the function + OCIUserCallbackGet returns pointers to the registered + callbacks. These pointers are saved and then static callback + functions are registered for OCIStmtPrepare. Since + registering another entry and exit callback functions for + OCIStmtPrepare will overwrite the previously registered + dynamic callback functions, so the saved pointers are used to + make calls to the dynamic functions. + + Note that the last argument to user callbacks is an arglist. + Therefore, for callback chaining, a wrapper function is needed + to simulate a function with variable number of parameters. + The wrapper function takes all the parameters that have been + passed to the static callback. Since, it is a function with + variable number of parametes, it can create the arglist that is + to be passed to the dynamic callback. This is demonstrated + in the entry callback function. + + In the special case where the static callback does not need the + parameters passed to it, the static callback can simply + pass the arglist directly to the dynamic callback. This is + demonstrated in the exit callback function. + + This program will also work in "static-only" mode. In this + case dynamic callback function will not get registered and + this program will know that after call to + OCIUserCallbackGet and will not attempt to call the + dynamic callback function. + + PUBLIC FUNCTION(S) + + PRIVATE FUNCTION(S) + + RETURNS + + NOTES + + MODIFIED (MM/DD/YY) + slari 08/30/99 - add OCIUcb * + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + slari 11/22/98 - add wrapper for chained callback + slari 11/21/98 - conform to new OCIUserCallback with arglist + svedala 10/13/98 - Creation + +*/ + +#include +#include +#include +#include +#include + +static text *username = (text *) "CDEMOUCB"; +static text *password = (text *) "CDEMOUCB"; + +static text *crstmt = (text *) "CREATE TABLE TAB1 (COL1 VARCHAR2(40))"; + +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCIError *errhp; +static OCISvcCtx *svchp; +static OCIStmt *stmthp; +static OCISession *authp = (OCISession *) 0; + +struct stat_ctx_struct +{ + OCIUserCallback *entry_funcptr; + dvoid *entry_ctxptr; + OCIUserCallback *exit_funcptr; + dvoid *exit_ctxptr; +}; + +typedef struct stat_ctx_struct stat_ctx_struct; + +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void cleanup(/*_ void _*/); + +sword stmtprep_entry_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +sword stmtprep_exit_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +sword stmtprep_wrapper_cbk_fn (OCIUserCallback *funcptr, dvoid *ctxp, dvoid + *hndlp, ub4 type, ub4 fcode, ub4 when, + sword returnCode, sb4 *errnop, ...); + + +int main(/*_ int argc, char *argv[] _*/); + +static sword status; + +int main(argc, argv) +int argc; +char *argv[]; +{ + + static ub4 pos; + ub4 attrval; + ub4 attrsiz; + text errbuf[512]; + sb4 errcode = 0; + text sversion[512]; + + stat_ctx_struct *static_context; + + OCIUserCallback dyn_entry_funcptr; + dvoid *dyn_entry_ctxptr; + + OCIUserCallback dyn_exit_funcptr; + dvoid *dyn_exit_ctxptr; + + (void) printf("Initializing and Connecting\n\n"); + + if (init_handles()) + { + (void) printf("FAILED: init_handles()\n"); + return OCI_ERROR; + } + + if (log_on()) + { + (void) printf("FAILED: log_on()\n"); + return OCI_ERROR; + } + + if (status = OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + + /* Call OCIUserCallbackGet() to check if an entry callback */ + /* is registered for OCIStmtPrepare. If a callback was */ + /* registered dynamically its pointer will be returned. */ + + if (status = OCIUserCallbackGet(envhp, OCI_HTYPE_ENV, errhp, + OCI_FNCODE_STMTPREPARE, OCI_UCBTYPE_ENTRY, + &dyn_entry_funcptr, &dyn_entry_ctxptr, + (OCIUcb *)0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + + /* Call OCIUserCallbackGet() to check if an exit callback */ + /* is registered for OCIStmtPrepare. If a callback was */ + /* registered dynamically its pointer will be returned. */ + + if (status = OCIUserCallbackGet(envhp, OCI_HTYPE_ENV, errhp, + OCI_FNCODE_STMTPREPARE, OCI_UCBTYPE_EXIT, + &dyn_exit_funcptr, &dyn_exit_ctxptr, + (OCIUcb *)0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + /* Allocate a structure for context to be passed */ + /* to static callback function. */ + + static_context = (stat_ctx_struct *) malloc(sizeof(stat_ctx_struct)); + + + /* Save the pointer to dynamic callback routine and the */ + /* context associated with dynamic callback function */ + + if ((OCIUserCallback) *dyn_entry_funcptr) + { + static_context->entry_funcptr = &dyn_entry_funcptr; + static_context->entry_ctxptr = dyn_entry_ctxptr; + } + else + { + static_context->entry_funcptr = 0; + static_context->entry_ctxptr = 0; + } + + + if ((OCIUserCallback) *dyn_exit_funcptr) + { + static_context->exit_funcptr = &dyn_exit_funcptr; + static_context->exit_ctxptr = dyn_exit_ctxptr; + } + else + { + static_context->exit_funcptr = 0; + static_context->exit_ctxptr = 0; + } + + /* Register the static callback routine "stmtprep_entry_statcbk_fn" */ + /* for OCIStmtPrepare, entry-time. This will overwrite the */ + /* of entry dynamic callback if one was registered */ + + if (OCIUserCallbackRegister(envhp, OCI_HTYPE_ENV, errhp, + stmtprep_entry_statcbk_fn, static_context, + OCI_FNCODE_STMTPREPARE, OCI_UCBTYPE_ENTRY, + (OCIUcb *)0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + + /* Register the exit static callback function for OCIStmtPrepare */ + + if (OCIUserCallbackRegister(envhp, OCI_HTYPE_ENV, errhp, + stmtprep_exit_statcbk_fn, static_context, + OCI_FNCODE_STMTPREPARE, OCI_UCBTYPE_EXIT, + (OCIUcb *)0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + if (status = OCIStmtPrepare(stmthp, errhp, crstmt, + (ub4) strlen((char *) crstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + if ((status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT)) + && (status != OCI_NO_DATA)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + if (status = OCITransCommit(svchp, errhp, 0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + + if (status = OCISessionEnd(svchp, errhp, authp, (ub4) 0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + (void) printf("\nDetach and deallocate handles\n"); + + if (status = OCIServerDetach( srvhp, errhp, OCI_DEFAULT)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + cleanup(); +} + + +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +/* ----------------------------------------------------------------- */ +/* initialize environment, allocate handles, etc. */ +/* ----------------------------------------------------------------- */ + +sb4 init_handles() +{ + if (OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + /* initialize environment handle */ + if (OCIEnvInit((OCIEnv **) &envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* attach to the server and log on */ +/* ----------------------------------------------------------------- */ + +sb4 log_on() +{ + text *uid = (text *)"CDEMOUCB"; + text *pwd = (text *)"CDEMOUCB"; + text *cstring = (text *) ""; + + /* attach to the server */ + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *)uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *)pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* set the server attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* log on */ + if (OCISessionBegin(svchp, errhp, authp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionBegin()\n"); + return OCI_ERROR; + } + + /* set the session attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *) authp, + (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; + +} + + +/* ----------------------------------------------------------------- */ +/* Exit program with an exit code. */ +/* ----------------------------------------------------------------- */ +void cleanup() +{ + sword status; + + if (stmthp) + { + if (status = OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)) + { + (void) printf("Status = %d\n", status); + checkerr(errhp, status); + } + } + + if (srvhp) + { + if (status = OCIHandleFree((dvoid *) srvhp, OCI_HTYPE_SERVER)) + { + (void) printf("Status = %d\n", status); + checkerr(errhp, status); + } + } + + if (errhp) + { + (void) OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + } + return; +} + + + +/* ----------------------------------------------------------------- */ +/* Entry callback function for OCIStmtPrepare. This function is */ +/* statically registered (i.e. from within this file). Since, it */ +/* uses (via va_arg) the parametes passed to it, it calls a wrapper */ +/* function that recreates the arglist to be passed to the dynamic */ +/* callback. */ +/* ----------------------------------------------------------------- */ +sword stmtprep_entry_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + stat_ctx_struct *loc_ctx; + OCIStmt *stmthp; + OCIError *errhp; + text *sqlstmt; + ub4 stmtlen; + ub4 language; + ub4 mode; + sword retCode = OCI_CONTINUE; + + + /* Retrieve all arguments of OCIStmtPrepare and save */ + /* them so they can be passed on to dynamic-registered */ + /* callback if one was registered */ + + stmthp = va_arg(arglist, OCIStmt *); + errhp = va_arg(arglist, OCIError *); + sqlstmt = va_arg(arglist, text *); + stmtlen = va_arg(arglist, ub4); + language = va_arg(arglist, ub4); + mode = va_arg(arglist, ub4); + + printf("In static entry callback routine for OCIStmtPrepare:\n"); + printf("sql_stmt = [%s]\n\n", sqlstmt); + + + /* If dynamic callback was registered, then make a */ + /* call to the dynamic routine. */ + + loc_ctx = ctxp; + + if (loc_ctx->entry_funcptr) + { + + retCode = stmtprep_wrapper_cbk_fn(loc_ctx->entry_funcptr, + loc_ctx->entry_ctxptr, hndlp, type, fcode, + when, returnCode, errnop, stmthp, errhp, + sqlstmt, stmtlen, language, mode); + } + + return retCode; +} + + +/* ----------------------------------------------------------------- */ +/* Entry wrapper callback function for OCIStmtPrepare. This */ +/* function "recreates the arglist that is expected by the dynamic */ +/* callback. */ +/* ----------------------------------------------------------------- */ +sword stmtprep_wrapper_cbk_fn (OCIUserCallback *funcptr, dvoid *ctxp, dvoid + *hndlp, ub4 type, ub4 fcode, ub4 when, + sword returnCode, sb4 *errnop, ...) +{ + va_list arglist; + sword retCode; + + va_start(arglist, errnop); + + printf("In wrapper callback routine for OCIStmtPrepare:\n"); + + retCode = (*funcptr)(ctxp, hndlp, type, fcode, when, returnCode, errnop, + arglist); + va_end(arglist); + + return retCode; +} + + +/* ----------------------------------------------------------------- */ +/* Exit callback function (static) for OCIStmtPrepare. Since it */ +/* does not utilize any parameters in the arglist, it can pass */ +/* the arglist directly to the dynamic callback. */ +/* ----------------------------------------------------------------- */ +sword stmtprep_exit_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + stat_ctx_struct *loc_ctx; + sword retCode = OCI_CONTINUE; + + + printf("\nIn static exit callback routine for OCIStmtPrepare\n"); + + /* If dynamic callback was registered, then make a */ + /* call to the dynamic routine. */ + + loc_ctx = ctxp; + + if (loc_ctx->exit_funcptr) + { + + retCode = (*loc_ctx->exit_funcptr)(loc_ctx->exit_ctxptr, hndlp, type, + fcode, when, returnCode, errnop, arglist); + } + + return retCode; +} + + + +/* end of file cdemoucb.c */ + diff --git a/cdemoucb.sql b/cdemoucb.sql new file mode 100644 index 0000000..2dcf645 --- /dev/null +++ b/cdemoucb.sql @@ -0,0 +1,27 @@ +rem +rem $Header: cdemoucb.sql 10-apr-2007.18:07:12 azhao Exp $ +rem +rem cdemoucb.sql +rem +rem Copyright (c) 1998, 2007, Oracle. All rights reserved. +rem +rem NAME +rem cdemoucb.sql - +rem +rem DESCRIPTION +rem +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem azhao 04/10/07 - case sensitive password +rem hdnguyen 11/14/00 - fixed connect internal +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem bgoyal 10/16/98 - Sql for cdemoucb.c +rem bgoyal 10/16/98 - Created +rem +connect / as sysdba; +drop user cdemoucb cascade; +grant connect, resource to cdemoucb identified by CDEMOUCB; + diff --git a/cdemoucbl.c b/cdemoucbl.c new file mode 100644 index 0000000..2ebb344 --- /dev/null +++ b/cdemoucbl.c @@ -0,0 +1,284 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoucbl.c 14-jul-99.13:18:43 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemoucbl.c - User callback demo program. + + DESCRIPTION + This file contains the routine which is used to + create the shared library to be used for dynamic + callback registration. + + Makefile ociucb.mk is required to compile this file + and for creating shared library. The make command is: + + make -f ociucb.mk user_callback SHARED_LIBNAME=ociucb.so.1.0 \ + OBJS=cdemoucbl.o + + For creating 64-bit shared library make command is: + + make -f ociucb.mk user_callback SHARED_LIBNAME=ociucb.so.1.0 \ + LDFLAGS="\$(LDFLAGS64)" RDBMSLIB="\$(RDBMSLIB64)" \ + LIBHOME="\$(LIBHOME64)" COMPFLAGS="\$(COMPFLAGS64)" \ + LIBD4R= OBJS=cdemoucbl.o + + + The environment variable ORA_OCI_UCBPKG should be set to ociucb. + + setenv ORA_OCI_UCBPKG ociucb + + + PUBLIC FUNCTION(S) + + PRIVATE FUNCTION(S) + + RETURNS + + NOTES + + MODIFIED (MM/DD/YY) + slari 09/10/99 - bg989981: remove envCallback from ociucbInit + slari 08/30/99 - add OCIUcb * + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + slari 11/22/98 - use arglist instead of ellipsis + slari 11/21/98 - conform to new OCIUserCallback with arglist + svedala 10/13/98 - Creation + +*/ + + +#include +#include +#include +#include +#include + + + /* the forward declaration must be done so that + OCIShareLibInit can be passed a pointer to this function + */ + +sword ociucbEnvCallback(OCIEnv *env, ub4 mode, size_t xtramemsz, dvoid *usrmemp, + OCIUcb *ucbDesc); + + +static sword stmtprep_entry_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + + +static sword stmtprep_replace_dyncbk_fn(dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +static sword stmtprep_exit_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +struct dyn_ctx_struct /* Context to be passed to */ +{ + char str1[40]; /* dynamic callback function */ +}; + +typedef struct dyn_ctx_struct dyn_ctx_struct; + + + +/*--------------------------------- ociucbInit ---------------------------------*/ + +/* + NAME: + ociucbInit - OCI Shared Library CallBack Main function + + PARAMETERS: + meta - The metacontext + libCtx - The context for this package + argfmt - The package argument format + argc - The number of arguments passed + argv - The arguments to the package + + DESCRIPTION: + This is called by OCI to load and initialize the shared library + (package). + + The OCI shared library initialization is done by passing all the + parameters passed to the the shared library initialization function to + the OCISharedLibInit function. User's environment callback function of + type OCIEnvCallbackType is also passed to the OCISharedLibInit call. + + + RETURNS: + the return code from OCISharedLibInit function. + + NOTES: +*/ + +sword ociucbInit(metaCtx, libCtx, argfmt, argc, argv, envCallback) +dvoid * metaCtx; /* The metacontext */ +dvoid * libCtx; /* The context for this program or package if you + have previously been called. */ +ub4 argfmt; /* What am I supposed to do? */ +sword argc; /* argc if I am being called as a program */ +dvoid * argv[]; /* argv if I am being called as a program */ +{ + return (OCISharedLibInit(metaCtx, libCtx, argfmt, argc, argv, + ociucbEnvCallback)); +} + + + +/* ------------------------------------------------------------- */ +/* Entry point for dynamic callback registration. This routine */ +/* is called if environment variable ORA_OCI_UCBPKG is set */ +/* ------------------------------------------------------------- */ +sword ociucbEnvCallback(env, mode, xtramemsz, usrmemp, ucbDesc) +OCIEnv *env; +ub4 mode; +size_t xtramemsz; +dvoid *usrmemp; +OCIUcb *ucbDesc; +{ + OCISvcCtx *svchp; + OCIError *errhp; + dyn_ctx_struct *dynamic_context; + + dynamic_context = (dyn_ctx_struct *) malloc(sizeof(dyn_ctx_struct)); + + /* copy a string into element str1 of context, this value */ + /* will be printed in dynamic callback function */ + + strcpy(dynamic_context->str1, "Dynamic_Context_Test_String"); + + + /* register the dynamic callback function */ + + + /* Note that the replacement callback function in the + preferred way of using the ucbDesc passed-in in the + EnvCallbackk function */ + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_replace_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_REPLACE, ucbDesc)) + { + printf("cdemoucbl: OCIUserCallbackRegister returns error\n"); + return OCI_ERROR; + } + + /* The entry and exit callback functions are registered + using a NULL UCB Descriptor so that the application is + responsible for chaining them */ + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_entry_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_ENTRY, (OCIUcb *)0)) + { + printf("cdemoucbl: OCIUserCallbackRegister returns error\n"); + return OCI_ERROR; + } + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_exit_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_EXIT, (OCIUcb *)0)) + { + printf("cdemoucbl: OCIUserCallbackRegister returns error\n"); + return OCI_ERROR; + } + + return OCI_CONTINUE; +} + + + +/* ------------------------------------------------------------------ */ +/* Entry callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function ociucbEnvCallback */ +/* ------------------------------------------------------------------ */ +sword stmtprep_entry_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf("In dynamic entry callback function for OCIStmtPrepare:\n"); + printf("sql_stmt = [%s]\n", sqlstmt); + printf("Context string = [%s]\n", loc_ctx->str1); + + return OCI_CONTINUE; +} + + + +/* ------------------------------------------------------------------ */ +/* Replacement callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function ociucbEnvCallback */ +/* ------------------------------------------------------------------ */ +sword stmtprep_replace_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf("In dynamic replacement callback function for OCIStmtPrepare:\n"); + printf("sql_stmt = [%s]\n", sqlstmt); + printf("Context string = [%s]\n", loc_ctx->str1); + + return OCI_CONTINUE; +} + + + +/* ------------------------------------------------------------------ */ +/* Exit callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function ociucbEnvCallback */ +/* ------------------------------------------------------------------ */ +sword stmtprep_exit_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf("In dynamic exit callback function for OCIStmtPrepare:\n"); + printf("sql_stmt = [%s]\n", sqlstmt); + printf("Context string = [%s]\n", loc_ctx->str1); + + return OCI_CONTINUE; +} + + + + + +/* end of file cdemoucbl.c */ + diff --git a/cdemouni.c b/cdemouni.c new file mode 100644 index 0000000..a11f2c7 --- /dev/null +++ b/cdemouni.c @@ -0,0 +1,588 @@ +/* Copyright (c) 2001, 2002, Oracle Corporation. All rights reserved. */ + +/* + + NAME + cdemouni.c - a simple program for OCI UTF16 API + + DESCRIPTION + This is a demo for OCI UTF16 API. + + UTF16 is the encoding scheme of choice for internationalized + application developers, due to the support provided by JAVA + and MS windows platforms. This demo tries to illustrate the + fixed width Unicode support for UTF-16 encoded strings. + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + + + MODIFIED (MM/DD/YY) + aliu 03/14/02 - add conn to report_error on line 409. + anzhang 12/04/01 - fix bug 2116117 + anzhang 03/12/01 - Merged anzhang_utf16demo + anzhang 03/12/01 - Creation + +*/ + +#ifndef ORASTDLIB +# include +# define ORASTDLIB +#endif /* !ORASTDLIB */ + +#ifndef ORASTDIO +# include +# define ORASTDIO +#endif /* ifndef ORASTDIO */ + +#ifndef ORASTRING +#include +#define ORASTRING +#endif /* ifndef ORASTRING */ + +#ifndef OCI_ORACLE +#include +#endif /* ifndef OCI_ORACLE */ + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +#define DISCARD (void) + +/* database connection context */ +struct db_conn { + OCIEnv * envhp; /* OCI environment handle */ + OCIEnv * cnvhp; /* OCI environment handle for conversion */ + OCIServer * srvhp; /* OCI server handle */ + OCIError * errhp; /* OCI error handle */ + OCISvcCtx * svchp; /* OCI service context */ + OCISession * authp; /* OCI session handle */ + + boolean attached; /* if server is attached */ + boolean is_logged_on; /* if we have logged on to server */ +}; +typedef struct db_conn db_conn; + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ + +/* Static Function */ +static db_conn* db_conn_init(); /* initialize database connection context */ + +static void db_conn_free(); /* Environment clean up */ + +static void connect(); /* function to initialize connection */ + +static sb4 ustrlen(); /* calculate length for UTF16-string */ + +static void report_error(); /* print out error message */ + +static void checkerr(); /* report error if there is one and exit */ + +static void execute(); /* execute a statement */ + +/* display column data for select statement */ +static void display_column(); + +/* convert a native text to unicode */ +static text* text2unicode(); + +/* convert a unicode string to native text */ +static text* unicode2text(); + +/* ----------------------------------------------------------------- */ +/* db_conn_init: initialize a connection context */ +/* ----------------------------------------------------------------- */ +db_conn* +db_conn_init() +{ + sword retval; + /* allocate memory */ + db_conn * conn = (db_conn *)calloc(1,sizeof(db_conn)); + if (conn == NULL) + return NULL; + + conn->envhp = (OCIEnv*)0; + conn->cnvhp = (OCIEnv*)0; + conn->srvhp = (OCIServer*)0; + conn->svchp = (OCISvcCtx*)0; + conn->authp = (OCISession*)0; + conn->attached = FALSE; + conn->is_logged_on = FALSE; + + /* create OCI environment handle */ + if ((retval = OCIEnvCreate((OCIEnv **) &conn->envhp, (ub4) OCI_UTF16, + (dvoid *)0, (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0, (size_t) 0, + (dvoid **) 0)) || + (retval = OCIEnvCreate((OCIEnv **) &conn->cnvhp, (ub4) OCI_DEFAULT, + (dvoid *)0, (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0, (size_t) 0, + (dvoid **) 0))) + { + DISCARD fprintf(stdout, "FAILED: OCIEnvCreate() retval = %d\n", retval); + exit(OCI_ERROR); + } + + /* allocation of service context handle */ + if (retval = OCIHandleAlloc((dvoid *) conn->envhp, (dvoid **) &conn->svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + DISCARD fprintf(stdout, "FAILED: OCIHandleAlloc() on svchp, RC = %d\n", + retval); + db_conn_free(conn); + exit(OCI_ERROR); + } + + /* allocate error handle */ + if (retval = OCIHandleAlloc((dvoid *) conn->envhp, (dvoid **) &conn->errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + DISCARD fprintf(stdout, "FAILED: OCIHandleAlloc() on errhp, RC = %d\n", + retval); + db_conn_free(conn); + exit(OCI_ERROR); + } + + /* allocate server handle */ + if (retval = OCIHandleAlloc((dvoid *) conn->envhp, (dvoid **) &conn->srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + DISCARD fprintf(stdout, "FAILED: OCIHandleAlloc() on srvhp, RC = %d\n", + retval); + db_conn_free(conn); + } + + /* allocation of session handle */ + if (retval = OCIHandleAlloc((dvoid *) conn->envhp, (dvoid **) &conn->authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + DISCARD fprintf(stdout, "FAILED: OCIHandleAlloc() on authp, RC = %d\n", + retval); + db_conn_free(conn); + } + + return conn; +} + +/* ----------------------------------------------------------------- */ +/* db_conn_free: Free a connect context, clean up */ +/* ----------------------------------------------------------------- */ +void +db_conn_free(conn) + db_conn * conn; +{ + /* log off the user if we are logged on */ + if (conn->is_logged_on) + DISCARD OCISessionEnd(conn->svchp, conn->errhp, conn->authp, (ub4) 0); + + /* detach server */ + if (conn->attached) + DISCARD OCIServerDetach(conn->srvhp, conn->errhp, (ub4) OCI_DEFAULT); + + /* free server handle */ + if (conn->srvhp) + DISCARD OCIHandleFree((dvoid *) conn->srvhp, (ub4) OCI_HTYPE_SERVER); + /* free service context */ + if (conn->svchp) + DISCARD OCIHandleFree((dvoid *) conn->svchp, (ub4) OCI_HTYPE_SVCCTX); + /* free error handle */ + if (conn->errhp) + DISCARD OCIHandleFree((dvoid *) conn->errhp, (ub4) OCI_HTYPE_ERROR); + /* free environment handle */ + if (conn->authp) + DISCARD OCIHandleFree((dvoid *) conn->authp, (ub4) OCI_HTYPE_SESSION); + /* deallocate connect object */ + free(conn); +} + +/* ----------------------------------------------------------------- */ +/* initialize environment, allocate handles, make connection, etc. */ +/* ----------------------------------------------------------------- */ +void +connect(conn,dblink,username,password) + db_conn *conn; /* database connection */ + text *dblink; /* Connection string */ + text *username; /* username */ + text *password; /* password */ +{ + sword retval; /* return value of OCI funcs */ + + /* log on to server */ + if (retval = OCIServerAttach(conn->srvhp, conn->errhp, dblink, + ustrlen((void *)dblink)*sizeof(utext), OCI_DEFAULT)) + { + DISCARD fprintf(stdout, "FAILED: OCIServerAttach(), RC = %d\n", retval); + db_conn_free(conn); + exit(OCI_ERROR); + } + + conn->attached = TRUE; + + checkerr(conn, OCIAttrSet((dvoid *) conn->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) conn->srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, conn->errhp)); + + checkerr(conn, OCIAttrSet((dvoid *) conn->authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) username, (ub4) ustrlen((void *)username)*sizeof(utext), + (ub4) OCI_ATTR_USERNAME, conn->errhp)); + + checkerr(conn, OCIAttrSet((dvoid *) conn->authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) ustrlen((void *)password)*sizeof(utext), + (ub4) OCI_ATTR_PASSWORD, conn->errhp)); + + /* log on to server */ + checkerr(conn, OCISessionBegin(conn->svchp, conn->errhp,conn->authp, + OCI_CRED_RDBMS, OCI_DEFAULT)); + conn->is_logged_on = TRUE; + + checkerr(conn, OCIAttrSet((dvoid *) conn->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) conn->authp, (ub4) 0, + (ub4) OCI_ATTR_SESSION, conn->errhp)); +} + +/* ----------------------------------------------------------------- */ +/* display_column: display the data after execution */ +/* ----------------------------------------------------------------- */ +void +display_column(stmhp, conn) + OCIStmt *stmhp; + db_conn *conn; +{ + text *pcoln[20]; /* column name: OCI_ATTR_NAME */ + ub2 pcoll[20]; /* column size: OCI_ATTR_DATA_SIZE */ + ub2 podt[20]; /* data type: OCI_ATTR_DATA_TYPE */ + ub1 isnull[20]; /* is this column NULL? */ + ub4 namelen[20]; + + eword i, pos; /* iterators */ + ub4 parmcnt = 0; /* parameter count */ + sword retval = 0; /* return value from OCI functions */ + OCIParam *parmdp; /* a parameter handle */ + + OCIDefine *dfnp[20]; /* define handle pointer */ + text *column[20]; /* buffers to hold data fetched */ + + memset((void *) pcoln, 0, 20 * sizeof(text *)); + /* get parameter count */ + checkerr(conn, OCIAttrGet((dvoid *) stmhp, (ub4)OCI_HTYPE_STMT, + (dvoid *) &parmcnt, + (ub4 *) 0, (ub4)OCI_ATTR_PARAM_COUNT, conn->errhp)); + + /* iterate every column, display data */ + for (pos = 1; pos <= parmcnt; pos++) + { + retval = OCIParamGet((dvoid *)stmhp, (ub4)OCI_HTYPE_STMT, conn->errhp, + (dvoid **)&parmdp, (ub4) pos ); + + if (retval) + { + DISCARD fprintf(stdout,"OCIParamGet RC=%d, position=%d\n", retval, pos); + continue; + } + + /* get the column name */ + checkerr(conn, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &pcoln[pos-1], + (ub4 *) &namelen[pos-1], (ub4) OCI_ATTR_NAME, + (OCIError *) conn->errhp)); + + /* get the data size */ + checkerr(conn, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &pcoll[pos-1], + (ub4 *) 0, (ub4) OCI_ATTR_DATA_SIZE, + (OCIError *) conn->errhp)); + + /* get the data type */ + checkerr(conn, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &podt[pos-1], + (ub4 *) 0, (ub4) OCI_ATTR_DATA_TYPE, + (OCIError *) conn->errhp)); + + /* is column null */ + checkerr(conn, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &isnull[pos-1], + (ub4 *) 0, (ub4) OCI_ATTR_IS_NULL, + (OCIError *) conn->errhp)); + + } + + for (i = 1; i <= parmcnt; i++) + { + /* print out the column name */ + DISCARD fprintf(stdout, "%-*s ", pcoll[i-1], + unicode2text(conn, (void *) pcoln[i-1], + ustrlen ((void *)pcoln[i-1]))); + column[i-1] = (text *) calloc( pcoll[i-1] + 1, sizeof(utext)); + + checkerr(conn, OCIDefineByPos(stmhp, &dfnp[i-1], conn->errhp, (ub4)i, + (dvoid *)column[i-1], + (sb4)((pcoll[i-1]+1)*2),(ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, + (ub4)OCI_DEFAULT)); + } + DISCARD fprintf(stdout, "\n========================================\n"); + + /* since we define after execute, we need to fetch */ + checkerr(conn, OCIStmtFetch(stmhp, conn->errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)); + do + { + for (i = 0; i < parmcnt; i++) + { + if (ustrlen((void *)column[i]) != 0) + { + /* display the data */ + DISCARD fprintf(stdout, "%-*s ", pcoll[i], + unicode2text(conn, (void *)column[i], + ustrlen((void *)column[i]))); + /* clean up data */ + memset(column[i], 0, (pcoll[i] + 1)*sizeof(utext)); + } + } + DISCARD fprintf(stdout, "\n"); + } + /* continue to fetch */ + while ((retval = OCIStmtFetch(stmhp, conn->errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)) == OCI_SUCCESS || + retval == OCI_SUCCESS_WITH_INFO); + + + /* Ignore NO DATA FOUND error */ + if (retval != OCI_NO_DATA) + { + checkerr(conn,retval); + } +} + +/* ----------------------------------------------------------------- */ +/* execute: parse and execute a sql statement */ +/* ----------------------------------------------------------------- */ + +void +execute(conn,stmt,func) + db_conn *conn; + text *stmt; + dvoid (*func)(OCIStmt * stmhp, db_conn * conn); +{ + sword retval; + OCIStmt * stmtp; + + /* allocate a statement handle */ + if ( retval = OCIHandleAlloc((dvoid *)conn->envhp, (dvoid **)&stmtp, + OCI_HTYPE_STMT, 0, (dvoid **) 0) ) + { + DISCARD fprintf(stdout, "FAILED: OCIHandleAlloc() on stmtp, RC = %d\n", + retval); + db_conn_free(conn); + exit(OCI_ERROR); + } + + /* Parse the statement */ + if (retval = OCIStmtPrepare (stmtp, conn->errhp, (CONST text *) stmt, + (ub4) ustrlen((void *)stmt)*sizeof(utext), + OCI_NTV_SYNTAX, OCI_DEFAULT)) + { + DISCARD fprintf(stdout, "FAILED: OCIStmtPrepare() on stmtp, RC = %d\n", + retval); + report_error(conn); + db_conn_free(conn); + exit(OCI_ERROR); + } + + if ( retval = OCIStmtExecute (conn->svchp, stmtp, conn->errhp, + 0, 0, (const OCISnapshot *) 0, (OCISnapshot *) 0, OCI_DEFAULT)) + { + report_error(conn); + db_conn_free(conn); + } + + if (func != NULL) + (*func)(stmtp, conn); + + /* free the statement handle */ + if (stmtp) + DISCARD OCIHandleFree((dvoid *) stmtp, (ub4) OCI_HTYPE_STMT); + +} + +/* ----------------------------------------------------------------- */ +/* ustrlen: calculate the length of UTF16 string */ +/* ----------------------------------------------------------------- */ + +sb4 +ustrlen(vustr) + void * vustr; +{ + utext *ustr = (utext *)vustr; + + utext * p = (utext*) ustr; + while (*p) + p++; + return (sb4)(p - ustr); +} + +/* ----------------------------------------------------------------- */ +/* report_error: get error code and message */ +/* ----------------------------------------------------------------- */ +void +report_error(conn) + db_conn * conn; +{ + text msgbuf[1024]; + sb4 errcode; + + DISCARD OCIErrorGet ((dvoid *)conn->errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + + DISCARD fprintf(stdout,(const char*) + unicode2text(conn,(void*)msgbuf,1024)); +} + +/* ----------------------------------------------------------------- */ +/* checkerr: print error message and exit if OCI func failed */ +/* ----------------------------------------------------------------- */ +void checkerr(conn, status) + db_conn *conn; + sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + return; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + report_error(conn); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } + + db_conn_free(conn); + exit(1); +} + +/* ----------------------------------------------------------------- */ +/* text2unicode: convert a string to UTF16 encoding */ +/* ----------------------------------------------------------------- */ +text* text2unicode(conn,src,srclen) + db_conn * conn; + const text* src; + size_t srclen; +{ + text* result = NULL; + size_t resultlen = (srclen+1)*sizeof(utext); + void *temp; + + result = (text*)calloc(resultlen,sizeof(text)); + temp = (void *)result; + + if (OCICharSetToUnicode((dvoid *)conn->cnvhp, (ub2 *)temp, + resultlen, src, srclen, NULL)) + { + fprintf(stderr,"OCICharSetToUnicode failed\n"); + free(temp); + return NULL; + } + result = (text *)temp; + + return result; +} + +/* ----------------------------------------------------------------- */ +/* unicode2text: convert a given UTF16 text */ +/* string to native encoding */ +/* ----------------------------------------------------------------- */ +text* unicode2text(conn,src,srclen) + db_conn * conn; + void* src; + size_t srclen; +{ + text *result = NULL; + size_t resultlen = ustrlen((void *)src) + 1; + result = (text*)calloc(resultlen,sizeof(text)); + + if (OCIUnicodeToCharSet((dvoid*)conn->cnvhp,result, + resultlen, (CONST ub2 *)src, srclen, NULL)) + { + fprintf(stderr,"OCIUnicodeToCharSet failed\n"); + free(result); + return NULL; + } + + return result; +} + +#define LINK "" +#define USER "hr" +#define PASS "hr" +#define SQLS "SELECT FIRST_NAME, LAST_NAME FROM EMPLOYEES" + +/* ----------------------------------------------------------------- */ +/* main routine */ +/* ----------------------------------------------------------------- */ +int main() +{ + db_conn *conn = NULL; /* db connection object */ + text *user = NULL; /* username */ + text *pass = NULL; /* password */ + text *dblink = NULL; /* database descriptor */ + text *sqlstmt = NULL; /* sql statement to be excuted */ + + conn = db_conn_init(); /* initilalize the connect object */ + + /* convert the all text strings to UTF16 encoding */ + dblink = text2unicode(conn,(text*)LINK, strlen(LINK)); + user = text2unicode(conn,(text*)USER, strlen(USER)); + pass = text2unicode(conn,(text*)PASS, strlen(PASS)); + sqlstmt = text2unicode(conn,(text*)SQLS, strlen(SQLS)); + + /* connect to database */ + connect(conn,dblink,user,pass); + execute(conn,sqlstmt,display_column); + + /* clean up */ + db_conn_free(conn); + free(dblink); + free(user); + free(pass); + free(sqlstmt); + + return OCI_SUCCESS; +} + + +/* end of file cdemouni.c */ diff --git a/cdemoup1.c b/cdemoup1.c new file mode 100644 index 0000000..775aee3 --- /dev/null +++ b/cdemoup1.c @@ -0,0 +1,266 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoup1.c 20-oct-99.14:12:18 svedala Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) Oracle Corporation 1999, 2000. All Rights Reserved. */ + +/* + + NAME + cdemoup1.c - User callback library routine 1. + + DESCRIPTION + The library cdemoup1 for user callback is created using this + file. The command for compiling and creating the library is: + + make -f ociucb.mk user_callback SHARED_LIBNAME=cdemoup1.so.1.0 \ + OBJS=cdemoup1.o + + The make file ociucb.mk is located in the demo directory. + + + PUBLIC FUNCTION(S) + None + + PRIVATE FUNCTION(S) + As described below + + RETURNS + + NOTES + + MODIFIED (MM/DD/YY) + jchai 04/26/00 - fix bug1238864 + svedala 10/20/99 - Creation + +*/ + +#include +#include +#include +#include +#include + + + /* the forward declaration must be done so that OCIShareLibInit + can be passed a pointer to this function */ + +sword cdemoup1EnvCallback(OCIEnv *env, ub4 mode, size_t xtramemsz, + dvoid *usrmemp, OCIUcb *ucbDesc); + + +static sword stmtprep_entry_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + + +static sword stmtprep_replace_dyncbk_fn(dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +static sword stmtprep_exit_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +struct dyn_ctx_struct /* Context to be passed to */ +{ + char str1[40]; /* dynamic callback function */ +}; + +static ub4 id = 1; /* library id */ + +typedef struct dyn_ctx_struct dyn_ctx_struct; + + + +/*--------------------------- cdemoup1Init ---------------------------------*/ + +/* + NAME: + cdemoup1Init - OCI Shared Library CallBack Main function + + PARAMETERS: + meta - The metacpmtext for the program manager + mycx - The primary context for the package + argfmt - The behviour that package must undergo + argc - The number arguments passed + argv - The arguments to the package + envCallback - pointer to user's environment callback function + + DESCRIPTION: + This is called by OCI to load and initialize the shared library. + + The OCI shared library initialization is done by passing all the + parameters passed to the the shared library initialization function to + the OCISharedLibInit function. User's environment callback function of + type OCIEnvCallbackType is also passed to the OCISharedLibInit call. + + + RETURNS: + the return code from OCISharedLibInit function. + + NOTES: +*/ + +sword cdemoup1Init(metaCtx, libCtx, argfmt, argc, argv, envCallback) +dvoid *metaCtx; /* The metacontext */ +dvoid *libCtx; /* The context for this program or package if you + have previously been called. */ +ub4 argfmt; /* What am I supposed to do? */ +sword argc; /* argc if I am being called as a program */ +dvoid *argv[]; /* argv if I am being called as a program */ +OCIEnvCallbackType envCallback; /* user's environment callback function */ +{ + return (OCISharedLibInit(metaCtx, libCtx, argfmt, argc, argv, + cdemoup1EnvCallback)); +} + + + +/* ------------------------------------------------------------- */ +/* Entry point for dynamic callback registration. This routine */ +/* is called if environment variable ORA_OCI_UCBPKG is set */ +/* ------------------------------------------------------------- */ +sword cdemoup1EnvCallback(env, mode, xtramemsz, usrmemp, ucbDesc) +OCIEnv *env; +ub4 mode; +size_t xtramemsz; +dvoid *usrmemp; +OCIUcb *ucbDesc; +{ + OCISvcCtx *svchp; + OCIError *errhp; + dyn_ctx_struct *dynamic_context; + + dynamic_context = (dyn_ctx_struct *) malloc(sizeof(dyn_ctx_struct)); + + /* copy a string into element str1 of context, this value */ + /* will be printed in dynamic callback function */ + + strcpy(dynamic_context->str1, "Dynamic_Context_Test_String"); + + + /* register the dynamic callback function */ + + + /* Note that the replacement callback function in the preferred + way of using the ucbDesc passed-in in the EnvCallbackk function */ + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_replace_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_REPLACE, ucbDesc)) + { + printf("Library%d: OCIUserCallbackRegister returns error\n", id); + return OCI_ERROR; + } + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_entry_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_ENTRY, ucbDesc)) + { + printf("Library%d: OCIUserCallbackRegister returns error\n", id); + return OCI_ERROR; + } + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_exit_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_EXIT, ucbDesc)) + { + printf("Library%d: OCIUserCallbackRegister returns error\n", id); + return OCI_ERROR; + } + + return OCI_CONTINUE; +} + + + +/* -------------------------------------------------------------------- */ +/* Entry callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function cdemoup1EnvCallback */ +/* -------------------------------------------------------------------- */ +sword stmtprep_entry_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf( + "Library%d: In dynamic entry callback function for OCIStmtPrepare:\n", id); + printf("Library%d: sql_stmt = [%s]\n", id, sqlstmt); + printf("Library%d: Context string = [%s]\n", id, loc_ctx->str1); + + return OCI_CONTINUE; +} + + + +/* -------------------------------------------------------------------- */ +/* Replacement callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function cdemoup1EnvCallback */ +/* -------------------------------------------------------------------- */ +sword stmtprep_replace_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf( + "Library%d: In dynamic replacement callback function for OCIStmtPrepare:\n", + id); + printf("Library%d: sql_stmt = [%s]\n", id, sqlstmt); + printf("Library%d: Context string = [%s]\n", id, loc_ctx->str1); + + return OCI_CONTINUE; +} + + + +/* -------------------------------------------------------------------- */ +/* Exit callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function cdemoup1EnvCallback */ +/* -------------------------------------------------------------------- */ +sword stmtprep_exit_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf( + "Library%d: In dynamic exit callback function for OCIStmtPrepare:\n", id); + printf("Library%d: sql_stmt = [%s]\n", id, sqlstmt); + printf("Library%d: Context string = [%s]\n", id, loc_ctx->str1); + + return OCI_CONTINUE; +} + + + + +/* end of file cdemoup1.c */ + diff --git a/cdemoup2.c b/cdemoup2.c new file mode 100644 index 0000000..4871cb2 --- /dev/null +++ b/cdemoup2.c @@ -0,0 +1,267 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoup2.c 20-oct-99.14:15:13 svedala Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) Oracle Corporation 1999, 2000. All Rights Reserved. */ + +/* + + NAME + cdemoup2.c - User callback library routine 2. + + DESCRIPTION + The library cdemoup2 for user callback is created using this + file. The command for compiling and creating the library is: + + make -f ociucb.mk user_callback SHARED_LIBNAME=cdemoup2.so.1.0 \ + OBJS=cdemoup2.o + + The make file ociucb.mk is located in the demo directory. + + + PUBLIC FUNCTION(S) + None. + + PRIVATE FUNCTION(S) + As described below. + + RETURNS + + NOTES + + MODIFIED (MM/DD/YY) + jchai 04/26/00 - fix bug1238864 + svedala 10/20/99 - Creation + +*/ + +#include +#include +#include +#include +#include + + + /* the forward declaration must be done so that OCIShareLibInit + can be passed a pointer to this function */ + +sword cdemoup2EnvCallback(OCIEnv *env, ub4 mode, size_t xtramemsz, dvoid + *usrmemp, OCIUcb *ucbDesc); + + +static sword stmtprep_entry_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + + +static sword stmtprep_replace_dyncbk_fn(dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +static sword stmtprep_exit_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +struct dyn_ctx_struct /* Context to be passed to */ +{ + char str1[40]; /* dynamic callback function */ +}; + +static ub4 id = 2; /* library id */ + +typedef struct dyn_ctx_struct dyn_ctx_struct; + + + +/*---------------------------- cdemoup2Init ---------------------------------*/ + +/* + NAME: + cdemoup2Init - OCI Shared Library CallBack Main function + + PARAMETERS: + meta - The metacpmtext for the program manager + mycx - The primary context for the package + argfmt - The behviour that package must undergo + argc - The number arguments passed + argv - The arguments to the package + envCallback - pointer to user's environment callback function + + DESCRIPTION: + This is called by OCI to load and initialize the shared library. + + The OCI shared library initialization is done by passing all the + parameters passed to the the shared library initialization function to + the OCISharedLibInit function. User's environment callback function of + type OCIEnvCallbackType is also passed to the OCISharedLibInit call. + + + RETURNS: + the return code from OCISharedLibInit function. + + NOTES: +*/ + +sword cdemoup2Init(metaCtx, libCtx, argfmt, argc, argv, envCallback) +dvoid * metaCtx; /* The metacontext */ +dvoid * libCtx; /* The context for this program or package if you + have previously been called. */ +ub4 argfmt; /* What am I supposed to do? */ +sword argc; /* argc if I am being called as a program */ +dvoid * argv[]; /* argv if I am being called as a program */ +OCIEnvCallbackType envCallback; /* user's environment callback function */ +{ + return (OCISharedLibInit(metaCtx, libCtx, argfmt, argc, argv, + cdemoup2EnvCallback)); +} + + + +/* ------------------------------------------------------------- */ +/* Entry point for dynamic callback registration. This routine */ +/* is called if environment variable ORA_OCI_UCBPKG is set */ +/* ------------------------------------------------------------- */ +sword cdemoup2EnvCallback(env, mode, xtramemsz, usrmemp, ucbDesc) +OCIEnv *env; +ub4 mode; +size_t xtramemsz; +dvoid *usrmemp; +OCIUcb *ucbDesc; +{ + OCISvcCtx *svchp; + OCIError *errhp; + dyn_ctx_struct *dynamic_context; + + dynamic_context = (dyn_ctx_struct *) malloc(sizeof(dyn_ctx_struct)); + + /* copy a string into element str1 of context, this value */ + /* will be printed in dynamic callback function */ + + strcpy(dynamic_context->str1, "Dynamic_Context_Test_String"); + + + /* register the dynamic callback function */ + + + /* Note that the replacement callback function in the + preferred way of using the ucbDesc passed-in in the + EnvCallbackk function */ + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_replace_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_REPLACE, ucbDesc)) + { + printf("Library%d: OCIUserCallbackRegister returns error\n", id); + return OCI_ERROR; + } + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_entry_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_ENTRY, ucbDesc)) + { + printf("Library%d: OCIUserCallbackRegister returns error\n", id); + return OCI_ERROR; + } + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_exit_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_EXIT, ucbDesc)) + { + printf("Library%d: OCIUserCallbackRegister returns error\n", id); + return OCI_ERROR; + } + + return OCI_CONTINUE; +} + + + +/* -------------------------------------------------------------------- */ +/* Entry callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function cdemoup2EnvCallback */ +/* -------------------------------------------------------------------- */ +sword stmtprep_entry_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf("Library%d: In dynamic entry callback function for OCIStmtPrepare:\n", + id); + printf("Library%d: sql_stmt = [%s]\n", id, sqlstmt); + printf("Library%d: Context string = [%s]\n", id, loc_ctx->str1); + + return OCI_CONTINUE; +} + + + +/* -------------------------------------------------------------------- */ +/* Replacement callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function cdemoup2EnvCallback */ +/* -------------------------------------------------------------------- */ +sword stmtprep_replace_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf( + "Library%d: In dynamic replacement callback function for OCIStmtPrepare:\n", + id); + printf("Library%d: sql_stmt = [%s]\n", id, sqlstmt); + printf("Library%d: Context string = [%s]\n", id, loc_ctx->str1); + + return OCI_CONTINUE; +} + + + +/* -------------------------------------------------------------------- */ +/* Exit callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function cdemoup2EnvCallback */ +/* -------------------------------------------------------------------- */ +sword stmtprep_exit_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf("Library%d: In dynamic exit callback function for OCIStmtPrepare:\n", + id); + printf("Library%d: sql_stmt = [%s]\n", id, sqlstmt); + printf("Library%d: Context string = [%s]\n", id, loc_ctx->str1); + + return OCI_CONTINUE; +} + + + + +/* end of file cdemoup2.c */ + diff --git a/cdemoupk.c b/cdemoupk.c new file mode 100644 index 0000000..8e70a18 --- /dev/null +++ b/cdemoupk.c @@ -0,0 +1,466 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoupk.c 15-feb-2007.10:21:02 aliu Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 2007, Oracle. All rights reserved. */ + +/* + + NAME + cdemoupk.c - User callbacks demo program with multiple packages. + + DESCRIPTION + This programs tests loading of multiple packages. + + The dynamic callback files cdemoup1.c and cdemoup2.c need + to be linked into shared libraries using the make file provided, + see comments in cdemoup1.c for more details. + + Callback "chaining" is demonstrated as follows: If + ORA_OCI_UCBPKG is set then the dynamic callbacks are + registered first for OCIStmtPrepare. The environment + variable can be set to upto 5 package names, delimited + by semi-colons. + + PUBLIC FUNCTION(S) + None + + PRIVATE FUNCTION(S) + As described below + + RETURNS + + NOTES + Multiple packages can be specified by setting the + environment variable ORA_OCI_UCBPKG as follows: + + setenv ORA_OCI_UCBPKG "cdemoup1;cdemoup2" + + The above setting specifies two packages are to be used. + A maximum of 5 packages can be specified separated by + semi-colons. + + MODIFIED (MM/DD/YY) + aliu 02/15/07 - fix lrg 2863937: initialize variables + mpjoshi 11/04/99 - do not use wrapper functions + svedala 10/20/99 - Creation + +*/ + +#include +#include +#include +#include +#include + +static text *username = (text *) "CDEMOUPK"; +static text *password = (text *) "CDEMOUPK"; + +static text *crstmt = (text *) "CREATE TABLE TAB1 (COL1 VARCHAR2(40))"; + +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCIError *errhp; +static OCISvcCtx *svchp; +static OCIStmt *stmthp; +static OCISession *authp = (OCISession *) 0; + +struct stat_ctx_struct +{ + OCIUserCallback *entry_funcptr; + dvoid *entry_ctxptr; + OCIUserCallback *exit_funcptr; + dvoid *exit_ctxptr; +}; + +typedef struct stat_ctx_struct stat_ctx_struct; + +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void cleanup(/*_ void _*/); + +sword stmtprep_entry_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +sword stmtprep_exit_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + + +int main(/*_ int argc, char *argv[] _*/); + +static sword status; + +int main(argc, argv) +int argc; +char *argv[]; +{ + + static ub4 pos; + ub4 attrval; + ub4 attrsiz; + text errbuf[512]; + sb4 errcode = 0; + text sversion[512]; + + stat_ctx_struct *static_context = (stat_ctx_struct *) 0; + + (void) printf("Initializing and Connecting\n\n"); + + if (init_handles()) + { + (void) printf("FAILED: init_handles()\n"); + return OCI_ERROR; + } + + if (log_on()) + { + (void) printf("FAILED: log_on()\n"); + return OCI_ERROR; + } + + if (status = OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + + /* Register the static callback routine "stmtprep_entry_statcbk_fn" */ + /* for OCIStmtPrepare, entry-time. This will overwrite the */ + /* of entry dynamic callback if one was registered */ + + if (OCIUserCallbackRegister(envhp, OCI_HTYPE_ENV, errhp, + stmtprep_entry_statcbk_fn, static_context, + OCI_FNCODE_STMTPREPARE, OCI_UCBTYPE_ENTRY, + (OCIUcb *)0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + + /* Register the exit static callback function for OCIStmtPrepare */ + + if (OCIUserCallbackRegister(envhp, OCI_HTYPE_ENV, errhp, + stmtprep_exit_statcbk_fn, static_context, + OCI_FNCODE_STMTPREPARE, OCI_UCBTYPE_EXIT, + (OCIUcb *)0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + if (status = OCIStmtPrepare(stmthp, errhp, crstmt, + (ub4) strlen((char *) crstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + if ((status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT)) + && (status != OCI_NO_DATA)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + if (status = OCITransCommit(svchp, errhp, 0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + + if (status = OCISessionEnd(svchp, errhp, authp, (ub4) 0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + (void) printf("\nDetach and deallocate handles\n"); + + if (status = OCIServerDetach( srvhp, errhp, OCI_DEFAULT)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + cleanup(); +} + + +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +/* ----------------------------------------------------------------- */ +/* initialize environment, allocate handles, etc. */ +/* ----------------------------------------------------------------- */ + +sb4 init_handles() +{ + if (OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + /* initialize environment handle */ + if (OCIEnvInit((OCIEnv **) &envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* attach to the server and log on */ +/* ----------------------------------------------------------------- */ + +sb4 log_on() +{ + text *uid = (text *)"CDEMOUPK"; + text *pwd = (text *)"CDEMOUPK"; + text *cstring = (text *) ""; + + /* attach to the server */ + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *)uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *)pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* set the server attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* log on */ + if (OCISessionBegin(svchp, errhp, authp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionBegin()\n"); + return OCI_ERROR; + } + + /* set the session attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *) authp, + (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; + +} + + +/* ----------------------------------------------------------------- */ +/* Exit program with an exit code. */ +/* ----------------------------------------------------------------- */ +void cleanup() +{ + sword status; + + if (stmthp) + { + if (status = OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)) + { + (void) printf("Status = %d\n", status); + checkerr(errhp, status); + } + } + + if (srvhp) + { + if (status = OCIHandleFree((dvoid *) srvhp, OCI_HTYPE_SERVER)) + { + (void) printf("Status = %d\n", status); + checkerr(errhp, status); + } + } + + if (errhp) + { + (void) OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + } + return; +} + + + +/* ----------------------------------------------------------------- */ +/* Entry callback function for OCIStmtPrepare. This function is */ +/* statically registered (i.e. from within this file). Since, it */ +/* uses (via va_arg) the parametes passed to it, it calls a wrapper */ +/* function that recreates the arglist to be passed to the dynamic */ +/* callback. */ +/* ----------------------------------------------------------------- */ +sword stmtprep_entry_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + stat_ctx_struct *loc_ctx; + OCIStmt *stmthp; + OCIError *errhp; + text *sqlstmt; + ub4 stmtlen; + ub4 language; + ub4 mode; + sword retCode = OCI_CONTINUE; + + + /* Retrieve all arguments of OCIStmtPrepare and save */ + /* them so they can be passed on to dynamic-registered */ + /* callback if one was registered */ + + stmthp = va_arg(arglist, OCIStmt *); + errhp = va_arg(arglist, OCIError *); + sqlstmt = va_arg(arglist, text *); + stmtlen = va_arg(arglist, ub4); + language = va_arg(arglist, ub4); + mode = va_arg(arglist, ub4); + + printf("In static entry callback routine for OCIStmtPrepare:\n"); + printf("sql_stmt = [%s]\n\n", sqlstmt); + + + return retCode; +} + + +/* ----------------------------------------------------------------- */ +/* Exit callback function (static) for OCIStmtPrepare. Since it */ +/* does not utilize any parameters in the arglist, it can pass */ +/* the arglist directly to the dynamic callback. */ +/* ----------------------------------------------------------------- */ +sword stmtprep_exit_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + stat_ctx_struct *loc_ctx; + sword retCode = OCI_CONTINUE; + + + printf("\nIn static exit callback routine for OCIStmtPrepare\n"); + + return retCode; +} + + + +/* end of file cdemoupk.c */ + diff --git a/cdemoupk.sql b/cdemoupk.sql new file mode 100644 index 0000000..c3c048d --- /dev/null +++ b/cdemoupk.sql @@ -0,0 +1,34 @@ +Rem +Rem $Header: cdemoupk.sql 10-apr-2007.18:07:13 azhao Exp $ +Rem +Rem cdemoupk.sql +Rem +Rem Copyright (c) 2004, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem cdemoupk.sql - create user for cdemooupk +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem azhao 04/10/07 - case sensitive password +Rem jchai 03/23/04 - jchai_add_cdemoucb_cdempupk_shiptest +Rem jchai 03/18/04 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +connect system/manager; +drop user cdemoupk cascade; +grant connect, resource to cdemoupk identified by CDEMOUPK; + + diff --git a/cdemoxml.c b/cdemoxml.c new file mode 100644 index 0000000..e02fdbd --- /dev/null +++ b/cdemoxml.c @@ -0,0 +1,649 @@ +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemoxml.c - XMLType demo program in OCI + + DESCRIPTION - demo of selection and insertion of XMLType column + using OCI interface. + + Note: Before running this program, ensure that the database is + started up with compatible=9.0.0.0.0 and an table CDEMOXML_FOO does + not exist in the SCOTT/TIGER sample account. + + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + aliu 07/05/01 - update SQLCS_IMPLICIT to OCI_DEFAULT for OCILobCreateTemporary. + aliu 06/27/01 - Change table name not to be conflict with other tests. + aliu 04/24/01 - Merged aliu_dt_demo_oci + aliu 04/24/01 - Modify variable names and main prototype. + aliu 04/24/01 - Update lint warnings. + aliu 04/23/01 - Add more comments. + aliu 04/10/00 - Creation + +*/ + +#ifndef CDEMOXML +#define CDEMOXML + +/*------------------------------------------------------------------------ + * Include Files + */ + +#ifndef STDIO +#include +#endif + +#ifndef STDLIB +#include +#endif + +#ifndef STRING +#include +#endif + +#ifndef OCI_ORACLE +#include +#endif + +/*----------------- End of including files -----------------*/ + +/*--------------------- Public Constants and Variables ----------------------*/ + +/* constants */ +#define MAXBUFLEN 2000 + +/* database login information */ +static text *user=(text *)"SCOTT"; +static text *password=(text *)"tiger"; + +/* OCI Handles and Variables */ +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCISvcCtx *svchp; +static OCIError *errhp; +static OCISession *authp; +static OCIStmt *stmthp; +static OCIDefine *defnp = (OCIDefine *) 0; +static OCIBind *bndhp1 = (OCIBind *) 0, *bndhp2 = (OCIBind *) 0; + +/* Misellaneous */ +static sword status; +static boolean tab_exists = FALSE; + +/*----------------- End of Constants and Variables -----------------*/ + +/*--------------------- Functions Declaration --------------------*/ + +int main(/*_ void _*/); +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void cleanup(/*_ void _*/); +static sb4 connect_server(/*_ void _*/); +static void disconnect_server(/*_ void _*/); +static void drop_table(/*_ void _*/); +static sb4 init_env_handle(/*_ void _*/); +static sb4 init_table(/*_ void _*/); +static sb4 insert_xml(/*_ ub4 rownum _*/); +static sb4 select_xml(/*_ ub4 rownum _*/); + +/*--------------------- End of Functions Declaration --------------------*/ + +#endif + + +/*---------------------------Main function -----------------------------*/ +int main() +{ + ub4 rownum; + + /* Initialize the environment and allocate handles */ + if (init_env_handle()) + { + printf("FAILED: init_env_handle()!\n"); + return OCI_ERROR; + } + + /* Log on to the server and begin a session */ + if (connect_server()) + { + printf("FAILED: connect_server()!\n"); + cleanup(); + return OCI_ERROR; + } + + /* Initialize the demo table */ + if (init_table()) + { + printf("FAILED: init_table()\n"); + disconnect_server(); + return OCI_ERROR; + } + + rownum = 1; + /* Insertion */ + if (insert_xml(rownum)) + { + printf("FAILED: insert_xml()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* Selection */ + if (select_xml(rownum)) + { + printf("FAILED: select_xml()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* Detach from a server and clean up the environment */ + disconnect_server(); + + return OCI_SUCCESS; +} + + +/*---------------------------Subfunctions -----------------------------*/ + +/*--------------------------------------------------------*/ +/* Return corresponding messages in differrent cases */ +/*--------------------------------------------------------*/ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text msgbuf[512]; + sb4 errcode = 0; + + memset((void *) msgbuf, (int)'\0', (size_t)512); + + switch (status) + { + case OCI_SUCCESS: break; + case OCI_SUCCESS_WITH_INFO: + printf("status = OCI_SUCCESS_WITH_INFO\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_NEED_DATA: + printf("status = OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("status = OCI_NO_DATA\n"); + break; + case OCI_ERROR: + printf("status = OCI_ERROR\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_INVALID_HANDLE: + printf("status = OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("status = OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("status = OCI_CONTINUE\n"); + break; + default: + break; + } + + return; +} + + +/*--------------------------------------------------------*/ +/* Free the envhp whenever there is an error */ +/*--------------------------------------------------------*/ +void cleanup() +{ + if (envhp) { + OCIHandleFree((dvoid *)envhp, OCI_HTYPE_ENV); + } + + return; +} + + +/*--------------------------------------------------------*/ +/* attach to server, set attributes, and begin session */ +/*--------------------------------------------------------*/ +sb4 connect_server() +{ + /* attach to server */ + if (status = OCIServerAttach((OCIServer *) srvhp, (OCIError *) errhp, + (text *) "", (sb4) strlen(""), (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIServerAttach() on srvhp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set server attribute to service context */ + if (status = OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, + (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on svchp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set user attribute to session */ + if (status = OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) user, (ub4) strlen((char *)user), + (ub4) OCI_ATTR_USERNAME, (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on authp for user\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set password attribute to session */ + if (status = OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *)password), + (ub4) OCI_ATTR_PASSWORD, (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on authp for password\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* Begin a session */ + if (status = OCISessionBegin((OCISvcCtx *) svchp, (OCIError *) errhp, + (OCISession *) authp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCISessionBegin()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set session attribute to service context */ + if (status = OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, + (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on svchp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* End the session, detach server and free handles. */ +/*--------------------------------------------------------*/ +void disconnect_server() +{ + printf("\n\nLogged off and detached from server.\n"); + + /* Drop the demo table if any */ + if (tab_exists) + drop_table(); + + /* End a session */ + if (status = OCISessionEnd((OCISvcCtx *)svchp, (OCIError *)errhp, + (OCISession *)authp, (ub4) OCI_DEFAULT)) { + checkerr(errhp, status); + cleanup(); + return; + } + + /* Detach from the server */ + if (status = OCIServerDetach((OCIServer *)srvhp, (OCIError *)errhp, + (ub4)OCI_DEFAULT)) { + checkerr(errhp, status); + cleanup(); + return; + } + + /* Free the handles */ + if (stmthp) { + OCIHandleFree((dvoid *)stmthp, (ub4) OCI_HTYPE_STMT); + } + if (authp) { + OCIHandleFree((dvoid *)authp, (ub4) OCI_HTYPE_SESSION); + } + if (svchp) { + OCIHandleFree((dvoid *)svchp, (ub4) OCI_HTYPE_SVCCTX); + } + if (srvhp) { + OCIHandleFree((dvoid *)srvhp, (ub4) OCI_HTYPE_SERVER); + } + if (errhp) { + OCIHandleFree((dvoid *)errhp, (ub4) OCI_HTYPE_ERROR); + } + if (envhp) { + OCIHandleFree((dvoid *)envhp, (ub4) OCI_HTYPE_ENV); + } + + return; +} + + +/*--------------------------------------------------------*/ +/* Drop table CDEMOXML_FOO before logging off from the server */ +/*--------------------------------------------------------*/ +void drop_table() +{ + text *dropstmt = (text *) "DROP TABLE CDEMOXML_FOO"; + + /* prepare drop statement */ + if (OCIStmtPrepare(stmthp, errhp, dropstmt, (ub4) strlen((char *) dropstmt), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtPrepare() dropstmt\n"); + return; + } + /* execute drop statement */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtExecute() dropstmt\n"); + return; + } + + return; +} + + +/*--------------------------------------------------------*/ +/* Initialize the environment and allocate handles */ +/*--------------------------------------------------------*/ +sb4 init_env_handle() +{ + /* Environment initialization and creation */ + if (OCIEnvCreate((OCIEnv **) &envhp, (ub4) OCI_OBJECT, (dvoid *) 0, + (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t)) 0, + (void (*)(dvoid *, dvoid *)) 0, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIEnvCreate()\n"); + return OCI_ERROR; + } + + /* allocate error handle */ + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on errhp\n"); + return OCI_ERROR; + } + + /* allocate server handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on srvhp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* allocate service context handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on svchp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* allocate session handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on authp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* Allocate statement handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on stmthp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* create a table CDEMOXML_FOO with one XMLType column */ +/*--------------------------------------------------------*/ +sb4 init_table() +{ + int colc; + text *crtstmt = (text *) "CREATE TABLE CDEMOXML_FOO (xml_col sys.xmltype, int_col INTEGER)"; + + /* prepare create statement */ + if (status = OCIStmtPrepare(stmthp, errhp, crtstmt, (ub4) strlen((char *) crtstmt), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtPrepare() crtstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + /* execute create statement */ + if (status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtExecute() crtstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + /* commit the Xn */ + OCITransCommit(svchp, errhp, (ub4)0); + + /* set flag to be used by disconnect_server() to drop the table */ + tab_exists = TRUE; + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* insert xml into the table */ +/*--------------------------------------------------------*/ +sb4 insert_xml(rownum) +ub4 rownum; +{ + ub4 colc = rownum; + ub4 amtp, nbytes; + ub1 bufp[MAXBUFLEN] = "\nRachel"; + text *insstmt = (text *)"INSERT INTO CDEMOXML_FOO (xml_col, int_col) VALUES (sys.xmltype.createxml(:xmlval), :intval)"; + OCILobLocator *clob; + + printf("\n=> Inserting to row %d......\n", rownum); + + /* Allocate the lob descriptor */ + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &clob, + (ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIDescriptorAlloc()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* initialize a lob */ + if (status = OCILobCreateTemporary(svchp,errhp,clob, + (ub2)OCI_DEFAULT,(ub1)OCI_DEFAULT,OCI_TEMP_CLOB,FALSE, + OCI_DURATION_SESSION)) + { + printf("ERROR: OCILobCreateTemporary()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + nbytes = MAXBUFLEN-1; + amtp = (ub4)strlen((char *)bufp); + if ( status = OCILobWrite(svchp, errhp, clob, &amtp, 1, + (dvoid *) bufp, (ub4) nbytes, OCI_ONE_PIECE, (dvoid *)0, + (sb4 (*)(dvoid *, dvoid *, ub4 *, ub1 *)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT)) + { + printf("ERROR: OCILobWrite()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* prepare insert statement */ + if (status = OCIStmtPrepare(stmthp, errhp, (text *)insstmt, + (ub4) strlen((char *)insstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtPrepare() insstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* associate variables with bind placeholders in the SQL statement */ + if ((status = OCIBindByName(stmthp, &bndhp1, errhp, + (CONST text *)":xmlval",(sb4) strlen((char *) ":xmlval"), + (dvoid *)&clob, (sb4) -1, SQLT_CLOB, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + || (status = OCIBindByName(stmthp, &bndhp2, errhp, + (CONST text *)":intval",(sb4) strlen((char *) ":intval"), + (dvoid *)&colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT))) + { + printf("FAILED: OCIBindByName()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* execute the statement */ + if (status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtExecute() insstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + printf("\n=> Insertion done\n"); + + /* Free the lob locator */ + if (clob) { + OCIDescriptorFree((dvoid *) clob, (ub4) OCI_DTYPE_LOB); + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* select xml column from the table */ +/*--------------------------------------------------------*/ +sb4 select_xml(rownum) +ub4 rownum; +{ + ub4 colc = rownum; + ub4 amtp, nbytes; + ub1 bufp[MAXBUFLEN]; + text *selstmt =(text *)"SELECT t.xml_col.getClobVal() FROM CDEMOXML_FOO t WHERE t.int_col = :1"; + OCILobLocator *clob; + + printf("\n=> Selecting row %d......\n", rownum); + + /* Allocate the lob descriptor */ + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &clob, + (ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIDescriptorAlloc()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* prepare select statement */ + if (status = OCIStmtPrepare(stmthp, errhp, (text *)selstmt, + (ub4) strlen((char *)selstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtPrepare() selstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* associate variable colc with bind placeholder #1 in the SQL statement */ + if (status = OCIBindByPos(stmthp, &bndhp1, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIBindByPos()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* associate lob var with its define handle */ + if (status = OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, + (dvoid *) &clob, (sb4) -1, (ub2) SQLT_CLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIDefineByPos() CLOB\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* execute the select statement */ + if (status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtExecute() selstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* read the fetched value into a buffer */ + amtp = nbytes = MAXBUFLEN-1; + if (status = OCILobRead(svchp, errhp, clob, &amtp, + (ub4) 1, (dvoid *) bufp, (ub4) nbytes, (dvoid *)0, + (sb4 (*)(dvoid *, CONST dvoid *, ub4, ub1)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT)) + { + printf("FAILED: OCILobRead() \n"); + checkerr(errhp, status); + return OCI_ERROR; + } + bufp[amtp] = '\0'; + + /* Print out the buffer */ + if (amtp > 0) { + printf("\n=> Query result of %s on row %d: \n%s\n", selstmt, rownum, bufp); + } + else { + printf("\nEmpty value\n"); + } + + /* Free the lob locator */ + if (clob) { + OCIDescriptorFree((dvoid *) clob, (ub4) OCI_DTYPE_LOB); + } + + return OCI_SUCCESS; +} + + +/* end of file cdemoxml.c */ diff --git a/clobdemo.dat b/clobdemo.dat new file mode 100644 index 0000000..a6d6923 --- /dev/null +++ b/clobdemo.dat @@ -0,0 +1,6 @@ +This is .dat file for clob demo. This .dat file content will be +printed using lob stream interface . If these contents are +printed properly, this demo program is working well. +Otherwise there is a problem in printing. Hope this demo will +work properly. + diff --git a/dattime1.sql b/dattime1.sql new file mode 100644 index 0000000..262f649 --- /dev/null +++ b/dattime1.sql @@ -0,0 +1,79 @@ +Rem +Rem $Header: rdbms/demo/dattime1.sql /main/3 2009/07/04 16:43:57 wezhu Exp $ +Rem +Rem dattime1.sql +Rem +Rem Copyright (c) 2007, 2009, Oracle and/or its affiliates. +Rem All rights reserved. +Rem +Rem NAME +Rem dattime1.sql - create table with 5 different data type +Rem TIMESTAMP +Rem TIMESTAMP WITH TIME ZONE +Rem TIMESTAMP WITH LOCAL TIME ZONE +Rem INTERVAL YEAR TO MONTH +Rem INTERVAL DAY TO SECOND +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem wezhu 07/01/09 - add default session time zone +Rem chli 04/09/07 - fix password issue +Rem jxfan 04/10/01 - Merged jxfan_demo +Rem jxfan 04/10/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO OFF + +COL c1 FORMAT A30 +COL c2 FORMAT A48 +COL c3 FORMAT A30 +COL c4 FORMAT A48 +COL c5 FORMAT A30 + +COL c1 HEADING TIMESTAMP +COL c2 HEADING "TIMESTAMP WITH TIME ZONE" +COL c3 HEADING "TIMESTAMP WITH LOCAL TIME ZONE" +COL c4 HEADING "INTERVAL YEAR TO MONTH" +COL c5 HEADING "INTERVAL DAY TO SECOND" + +CONNECT oe/oe + +ALTER SESSION SET time_zone = 'US/Pacific'; + +CREATE TABLE dattime ( + c1 TIMESTAMP, + c2 TIMESTAMP WITH TIME ZONE, + c3 TIMESTAMP WITH LOCAL TIME ZONE, + c4 INTERVAL YEAR TO MONTH, + c5 INTERVAL DAY TO SECOND); + +INSERT INTO dattime +VALUES ( TIMESTAMP'1980-1-12 15:13:23.33', + TIMESTAMP'2000-10-28 11:26:38 AMERICA/LOS_ANGELES', + TIMESTAMP'1985-3-1 1:11:11.11', + INTERVAl '1-2' YEAR TO MONTH, + INTERVAL '90 00:00:00' DAY TO SECOND); + +INSERT INTO dattime +VALUES (TO_TIMESTAMP('08-11-83 3:43:55.49','DD-MM-RR HH24:MI:SSXFF'), + TO_TIMESTAMP_TZ('2-4-58 14:2:56.18+8:53','DD-MM-RR HH24:MI:SSXFFTZH:TZM'), + TO_TIMESTAMP('12-8-38 1:2:56.1','DD-MM-RR HH24:MI:SSXFF'), + TO_YMINTERVAL('02-03'), + TO_DSINTERVAL('65 10:00:00')); + + +SELECT * FROM dattime; + +DROP TABLE dattime; + diff --git a/dattime2.sql b/dattime2.sql new file mode 100644 index 0000000..b805d59 --- /dev/null +++ b/dattime2.sql @@ -0,0 +1,71 @@ +Rem +Rem $Header: dattime2.sql 10-apr-2001.15:02:35 jxfan Exp $ +Rem +Rem dattime2.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem dattime2.sql - Daylight Saving Time (DST) +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem jxfan 04/10/01 - Merged jxfan_demo +Rem jxfan 04/10/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO OFF + +CONNECT OE/OE + +PROMPT Calculate Daylight Saving Time (DST) when the session TIME_ZONE is a region +PROMPT +SET ECHO ON +UPDATE orders +SET order_date = TIMESTAMP '2000-4-1 23:24:54 AMERICA/LOS_ANGELES' +WHERE order_id = 2457; +ALTER SESSION SET TIME_ZONE='AMERICA/LOS_ANGELES'; +SELECT order_date + INTERVAL '8' HOUR FROM orders +WHERE order_id = 2457; + +SET ECHO OFF +PROMPT +PAUSE Press enter to continue ... +PROMPT +PROMPT The time period from 02:00:00 AM to 02:59:59 AM does not exist +PROMPT during APRIL boundary +PROMPT + +SET ECHO ON +UPDATE orders +SET order_date = TIMESTAMP'2000-04-02 02:30:30 AMERICA/LOS_ANGELES' +WHERE order_id = 2457; + +SET ECHO OFF +PROMPT +PROMPT +PAUSE Press enter to continue ... +PROMPT +PROMPT The time period from 01:00:01 AM to 02:00:00 AM is repeated during +PROMPT OCTOBER boundary +PROMPT + +SET ECHO ON +ALTER SESSION SET ERROR_ON_OVERLAP_TIME = TRUE; + +UPDATE orders +SET order_date = TIMESTAMP '2000-10-29 01:00:01 AMERICA/LOS_ANGELES' +WHERE order_id = 2457; + + diff --git a/dattime3.sql b/dattime3.sql new file mode 100644 index 0000000..0b735e5 --- /dev/null +++ b/dattime3.sql @@ -0,0 +1,79 @@ +Rem +Rem $Header: dattime3.sql 09-apr-2007.15:52:50 chli Exp $ +Rem +Rem dattime3.sql +Rem +Rem Copyright (c) 2001, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dattime3.sql - Using Built-in SQL function +Rem TO_YMINTERVAL(); +Rem TO_DSINTERVAL(); +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem chli 04/09/07 - lowercase password +Rem jxfan 04/10/01 - Merged jxfan_demo +Rem jxfan 04/10/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO OFF + +COL employee_id FORMAT 9999 +COL first_name FORMAT A20 +COL last_name FORMAT A20 +COL employee_id HEADING ID +COL first_name HEADING "FIRST NAME" +COL last_name HEADING "LAST NAME" +COL hire_date HEADING "HIRE DATE" +CONNECT HR/hr + +PROMPT +PROMPT +PROMPT Add 1 year 2 months to hire date by using Built-in SQL function TO_YMINTERVAL +PROMPT +PROMPT + +SELECT employee_id, first_name, last_name, hire_date, + hire_date + TO_YMINTERVAL('01-02') "NEW DATE" +FROM employees +WHERE department_id = 30; + +PROMPT +PROMPT +rem PAUSE Press enter to continue ... +PROMPT +PROMPT Subtract 10 days from hire date by using Built-in SQL function TO_DSINTERVAL +PROMPT +PROMPT + +SELECT employee_id, first_name, last_name, hire_date, + hire_date - TO_DSINTERVAL('10 00:00:00') "NEW DATE" +FROM employees +WHERE department_id = 30; + +PROMPT +PROMPT +rem PAUSE Press enter to continue ... +PROMPT +PROMPT Add 24 hours to hire date using INTERVAL +PROMPT +PROMPT +SELECT employee_id, first_name, last_name, hire_date, + hire_date + INTERVAL '24' HOUR "NEW DATE" +FROM employees +WHERE department_id = 30; +PROMPT +PROMPT + diff --git a/dattime4.sql b/dattime4.sql new file mode 100644 index 0000000..bd892a6 --- /dev/null +++ b/dattime4.sql @@ -0,0 +1,332 @@ +Rem +Rem $Header: dattime4.sql 30-mar-2006.08:56:23 lburgess Exp $ +Rem +Rem dattime4.sql +Rem +Rem Copyright (c) 2001, 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem dattime4.sql - A Comprehensive DateTime Demo +Rem +Rem DESCRIPTION +Rem This is a sample program to demonstrate +Rem -the usage of datetime types available in 9i database. +Rem -different possible combination of datetime assignments +Rem -the usage of datetime built-ins +Rem -the usage of datetime arithmetic +Rem -the usage of ERROR_ON_OVERLAP_TIME Session parameter +Rem +Rem NOTES +Rem TS stands for TIMESTAMP +Rem TSTZ stands for TIMESTAMP WITH TIME ZONE +Rem TSLTZ stands for TIMESTAMP WITH LOCAL TIME ZONE +Rem +Rem MODIFIED (MM/DD/YY) +Rem lburgess 03/30/06 - lowercase passwords +Rem nmeng 10/23/02 - +Rem rchennoj 10/22/02 - Query from v$timezone_names +Rem rchennoj 05/07/01 - +Rem rchennoj 04/30/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 132 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +CONNECT SYSTEM/manager; + +DROP USER dtdemo CASCADE; +GRANT CONNECT, RESOURCE TO dtdemo IDENTIFIED BY dtdemo; + +CONNECT dtdemo/dtdemo; + + +ALTER SESSION SET TIME_ZONE='-08:00'; +SELECT dbtimezone, sessiontimezone from dual; + + +------------------------------------------------------ +--1. TIMESTAMP datatype +------------------------------------------------------ + +CREATE TABLE tab_ts (c_id number, c_ts TIMESTAMP); + +--Use fractional seconds +INSERT INTO tab_ts +VALUES (1, TIMESTAMP'1980-1-12 15:13:23.33'); + +--Use TimeZone info, should truncate the zone info as +--Timestamp type doesnot store zone info. +INSERT INTO tab_ts +VALUES (2, TIMESTAMP'1980-1-12 15:13:23 -07:00'); + + +ALTER SESSION SET NLS_TIMESTAMP_FORMAT='YYYY-MM-DD HH24:MI:SSXFF'; +SELECT c_id, c_ts from tab_ts order by c_id; + +ALTER SESSION SET NLS_TIMESTAMP_FORMAT='DD-MON-YYYY HH:MI:SSXFF AM'; +SELECT c_id, c_ts from tab_ts order by c_id; + + +------------------------------------------------------ +--2. TIMESTAMP WITH TIME ZONE datatype +------------------------------------------------------ + +CREATE TABLE tab_tstz (c_id number, c_tstz TIMESTAMP WITH TIME ZONE); + +--Use No TimeZone info, should take Sessiontimezone +INSERT INTO tab_tstz +VALUES ( 1, TIMESTAMP'2000-10-28 11:26:38'); + +--Use TimeZone Offset +INSERT INTO tab_tstz +VALUES ( 2, TIMESTAMP'2000-10-28 11:26:38 -07:00'); + +--Use TimeZone Region Name +INSERT INTO tab_tstz +VALUES ( 3, TIMESTAMP'2000-10-28 11:26:38 AMERICA/LOS_ANGELES'); + +INSERT INTO tab_tstz +VALUES ( 4, TIMESTAMP'2000-01-28 11:26:38 AMERICA/LOS_ANGELES PST'); + +INSERT INTO tab_tstz +VALUES ( 5, TIMESTAMP'2000-01-28 11:26:38 GMT'); + + +--show zone info in OFFSET format +ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT='DD-MON-YYYY HH:MI:SSXFF AM TZH:TZM'; +SELECT c_id, c_tstz from tab_tstz order by c_id; + +--show zone info in Regionname if one inserted +ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT='DD-MON-YYYY HH:MI:SSXFF AM TZR'; +SELECT c_id, c_tstz from tab_tstz order by c_id; + +--show zone info in Regionname and Zone Abbreviation if one inserted +ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT='DD-MON-YYYY HH:MI:SSXFF AM TZR TZD'; +SELECT c_id, c_tstz from tab_tstz order by c_id; + + +------------------------------------------------------ +--3. TIMESTAMP WITH LOCAL TIME ZONE datatype +------------------------------------------------------ + +CREATE TABLE tab_tsltz (c_id number, c_tsltz TIMESTAMP WITH LOCAL TIME ZONE); + +--Use fractional seconds +INSERT INTO tab_tsltz +VALUES (1, TIMESTAMP'1980-1-12 15:13:23.33'); + +--Use TimeZone info, should convert the value from specified time zone +--to Sessiontimezone +INSERT INTO tab_tsltz +VALUES (2, TIMESTAMP'1980-1-12 15:13:23 -07:00'); + + +ALTER SESSION SET NLS_TIMESTAMP_FORMAT='YYYY-MM-DD HH24:MI:SSXFF'; +SELECT c_id, c_tsltz from tab_tsltz order by c_id; + +ALTER SESSION SET NLS_TIMESTAMP_FORMAT='DD-MON-YYYY HH:MI:SSXFF AM'; +SELECT c_id, c_tsltz from tab_tsltz order by c_id; + + +--Change Sessiontimezone. TSLTZ value should be adjusted to the +--new sessiontimezone +ALTER SESSION SET TIME_ZONE='GMT'; +SELECT c_id, c_tsltz from tab_tsltz order by c_id; + +ALTER SESSION SET TIME_ZONE='Asia/Calcutta'; +SELECT c_id, c_tsltz from tab_tsltz order by c_id; + + +------------------------------------------------------ +--4. INTERVAL YEAR TO MONTH datatype +------------------------------------------------------ + +CREATE TABLE tab_iym (c_id number, c_iym INTERVAL YEAR(3) TO MONTH); + +INSERT INTO tab_iym +VALUES(1, INTERVAL '01-01' YEAR TO MONTH); + +INSERT INTO tab_iym +VALUES(2, INTERVAL '-01-01' YEAR TO MONTH); + +INSERT INTO tab_iym +VALUES(3, INTERVAL '100-10' YEAR(3) TO MONTH); + + +SELECT c_id, c_iym from tab_iym order by c_id; + + +------------------------------------------------------ +--5. INTERVAL DAY TO SECOND datatype +------------------------------------------------------ + +CREATE TABLE tab_ids (c_id number, c_ids INTERVAL DAY(3) TO SECOND(9)); + +INSERT INTO tab_ids +VALUES(1, INTERVAL '01 01:01:01.000001' DAY TO SECOND); + +INSERT INTO tab_ids +VALUES(2, INTERVAL '100 10:10:10' DAY(3) TO SECOND); + +INSERT INTO tab_ids +VALUES(3, INTERVAL '100 10:10:10.123456789' DAY(3) TO SECOND(9)); + + +SELECT c_id, c_ids from tab_ids order by c_id; + + +------------------------------------------------------ +--6. Use Datetime Builtins +------------------------------------------------------ + +--------FROM_TZ +SELECT FROM_TZ(TIMESTAMP'1997-01-01 01:00:00', 'US/Pacific') FROM DUAL; +SELECT FROM_TZ(TIMESTAMP'1999-04-04 01:59:59', 'US/Pacific') FROM DUAL; +SELECT FROM_TZ(TIMESTAMP'1999-04-04 03:00:00', 'US/Pacific') FROM DUAL; + +--------EXTRACT +SELECT EXTRACT(TIMEZONE_HOUR FROM TIMESTAMP'1999-12-31 01:30:00 US/Pacific') + FROM DUAL; +SELECT EXTRACT(TIMEZONE_MINUTE FROM TIMESTAMP'1999-12-31 01:30:00 US/Pacific') + FROM DUAL; +SELECT EXTRACT(TIMEZONE_REGION FROM TIMESTAMP'1999-12-31 01:30:00 US/Pacific') + FROM DUAL; +SELECT EXTRACT(TIMEZONE_ABBR FROM TIMESTAMP'1999-12-31 01:30:00 US/Pacific') + FROM DUAL; + +--------TZ_OFFSET +SELECT TZ_OFFSET('GMT') FROM DUAL; +SELECT TZ_OFFSET('Asia/Calcutta') FROM DUAL; + +--------TO_CHAR +SELECT TO_CHAR(TIMESTAMP '1997-01-01 01:00:00 US/Pacific', + 'YYYY-MM-DD HH24:MI:SS TZR') + FROM DUAL; +SELECT TO_CHAR(TIMESTAMP '1997-01-01 01:00:00 US/Pacific PST', + 'YYYY-MM-DD HH24:MI:SS TZR TZD') + FROM DUAL; + +--------CAST +SELECT CAST(TIMESTAMP'1999-10-31 01:01:01.123 US/Pacific' + AS TIMESTAMP(0)) + FROM DUAL; + +SELECT CAST(TIMESTAMP'1999-10-31 01:01:01.123 US/Pacific PST' + AS TIMESTAMP(6)) + FROM DUAL; + +-------TO_TIMESTAMP_TZ +SELECT TO_TIMESTAMP_TZ('14-MAR-1970 01:00:00 AM US/Pacific PST', + 'DD-MON-YYYY HH:MI:SS AM TZR TZD') + FROM DUAL; +SELECT TO_TIMESTAMP_TZ('14-MAR-1970 01:00:00 US/Pacific PST', + 'DD-MON-YYYY HH24:MI:SS TZR TZD') + FROM DUAL; + +-------TO_DSINTERVAL +SELECT TO_DSINTERVAL('100 10:00:00') FROM dual; + +-------TO_YMINTERVAL +SELECT TO_YMINTERVAL('01-02') FROM dual; + +-------NUMTODSINTERVAL +SELECT NUMTODSINTERVAL(12, 'DAY') FROM dual; +SELECT NUMTODSINTERVAL(12, 'MINUTE') FROM dual; + +-------NUMTOYMINTERVAL +SELECT NUMTOYMINTERVAL('01', 'YEAR') FROM dual; +SELECT NUMTOYMINTERVAL('01', 'MONTH') FROM dual; + +-------SYS_EXTRACT_UTC +--extracts the UTC(GMT) from a datetime with timezone displacement +SELECT SYS_EXTRACT_UTC(TIMESTAMP'2000-03-28 11:30:00 -08:00') + FROM dual; + +-------SYSTIMESTAMP, returns TSTZ type +--returns the system date and timezone of the system the database resides +SELECT SYSTIMESTAMP FROM dual; + +-------CURRENT_TIMESTAMP, returns TSTZ type +--returns the current date and time in session time zone +SELECT CURRENT_TIMESTAMP FROM dual; + +-------LOCALTIMESTAMP, returns TS type +--returns the current date and time in session time zone +SELECT LOCALTIMESTAMP FROM dual; +------------------------------------------------------ +--7. Use AT TIME ZONE +------------------------------------------------------ + +SELECT TIMESTAMP'1999-01-01 01:01:01' AT TIME ZONE 'US/Pacific' + FROM dual; + +SELECT TIMESTAMP'1999-01-01 01:01:01' AT TIME ZONE TZ_OFFSET('GMT') FROM DUAL; + +CREATE OR REPLACE FUNCTION myzone RETURN varchar2 IS +BEGIN + RETURN('US/Pacific'); +END; +/ +show errors + +SELECT TIMESTAMP'1997-01-01 01:00:00' AT TIME ZONE myzone FROM dual; + + +------------------------------------------------------ +--8. Datetime Arithmetic +------------------------------------------------------ +--Expect 10-NOV-99 01.30.00.000000000 AM -07:00 +SELECT TIMESTAMP'1999-10-31 01:30:00 -7:00' + +INTERVAL '10 00:00:00' DAY TO SECOND FROM dual; + +--Expect 1999-10-30 11:00:00 -07:00 +SELECT TIMESTAMP'1999-10-31 10:00:00 US/Pacific PST' + + INTERVAL '24' HOUR FROM dual; + +--Expect 1999-04-04 12:00:00.000000000-08:00 +SELECT TIMESTAMP'1999-04-05 01:00:00 US/Pacific PDT' + -INTERVAL '1440' MINUTE FROM dual; + +SELECT TIMESTAMP'1997-01-01 01:00:00 GMT' + +NUMTOYMINTERVAL('01','YEAR') FROM dual; + + +------------------------------------------------------ +--9. Use ERROR_ON_OVERLAP_TIME session parameter +------------------------------------------------------ + +--ERROR_ON_OVERLAP_TIME=TRUE +ALTER SESSION SET ERROR_ON_OVERLAP_TIME=TRUE; + +--error ORA-01883 +SELECT TIMESTAMP'1999-10-31 01:30:00 US/Pacific' FROM dual; + +SELECT TIMESTAMP'1999-10-31 01:30:00 US/Pacific PST' FROM dual; + + +--ERROR_ON_OVERLAP_TIME=FALSE +ALTER SESSION SET ERROR_ON_OVERLAP_TIME=FALSE; + +SELECT TIMESTAMP'1999-10-31 01:30:00 US/Pacific' FROM dual; + +SELECT TIMESTAMP'1999-10-31 01:30:00 US/Pacific PST' FROM dual; + +------------------------------------------------------ +--10. Query from v$timezone_names +------------------------------------------------------ + +CONNECT sys/change_on_install as sysdba; +SELECT DISTINCT tzname FROM v_$timezone_names + WHERE upper(tzname) LIKE '%AMERICA%' + ORDER BY tzname; + + + +connect system/manager; +drop user dtdemo cascade; +exit; diff --git a/demo_rdbms.mk b/demo_rdbms.mk new file mode 100644 index 0000000..f98da3c --- /dev/null +++ b/demo_rdbms.mk @@ -0,0 +1,326 @@ +# +# Example for building demo OCI programs: +# +# 1. All OCI demos (including extdemo2, extdemo4 and extdemo5): +# +# make -f demo_rdbms.mk demos +# +# 2. A single OCI demo: +# +# make -f demo_rdbms.mk build EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms.mk build EXE=oci02 OBJS=oci02.o +# +# 3. A single OCI demo with static libraries: +# +# make -f demo_rdbms.mk build_static EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms.mk build_static EXE=oci02 OBJS=oci02.o +# +# 4. To re-generate shared library: +# +# make -f demo_rdbms.mk generate_sharedlib +# +# 5. All OCCI demos +# +# make -f demo_rdbms.mk occidemos +# +# 6. A single OCCI demo: +# +# make -f demo_rdbms.mk +# e.g. make -f demo_rdbms.mk occidml +# OR +# make -f demo_rdbms.mk buildocci EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildocci EXE=occidml OBJS=occidml.o +# +# 7. A single OCCI demo with static libraries: +# +# make -f demo_rdbms.mk buildocci_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildocci_static EXE=occiblob OBJS=occiblob.o +# +# 8. All OCI Connection Pooling, Session Pooling and Statement Cache demos +# +# make -f demo_rdbms.mk cpdemos +# +# 9. A single OCI Connection Pooling demo: +# +# make -f demo_rdbms.mk +# e.g. make -f demo_rdbms.mk cdemocp +# OR +# make -f demo_rdbms.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildcp EXE=cdemocp OBJS=cdemocp.o +# +# 10. A single OCI Connection Pooling demo with static libraries: +# +# make -f demo_rdbms.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildcp_static EXE=cdemocp OBJS=cdemocp.o +# +# 11. A single OCI Session Pooling demo: +# +# make -f demo_rdbms.mk +# e.g. make -f demo_rdbms.mk cdemosp +# OR +# make -f demo_rdbms.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildcp EXE=cdemosp OBJS=cdemosp.o +# +# 12. A single OCI Session Pooling demo with static libraries: +# +# make -f demo_rdbms.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildcp_static EXE=cdemosp OBJS=cdemosp.o +# +# 13. A single OCI Statement Cache demo: +# +# make -f demo_rdbms.mk +# e.g. make -f demo_rdbms.mk cdemostc +# OR +# make -f demo_rdbms.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildcp EXE=cdemostc OBJS=cdemostc.o +# +# 14. A single OCI Statement Cache demo with static libraries: +# +# make -f demo_rdbms.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildcp_static EXE=cdemostc OBJS=cdemostc.o +# +# Example for building demo DIRECT PATH API programs: +# +# 1. All DIRECT PATH API demos: +# +# make -f demo_rdbms.mk demos_dp +# +# 2. A single DIRECT PATH API demo: +# +# make -f demo_rdbms.mk build_dp EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms.mk build_dp EXE=cdemdplp OBJS=cdemdplp.o +# +# +# Example for building external procedures demo programs: +# +# 1. All external procedure demos: +# +# 2. A single external procedure demo whose 3GL routines do not use the +# "with context" argument: +# +# make -f demo_rdbms.mk extproc_no_context SHARED_LIBNAME=libname +# OBJS="demo.o ..." +# e.g. make -f demo_rdbms.mk extproc_no_context SHARED_LIBNAME=epdemo.so +# OBJS="epdemo1.o epdemo2.o" +# +# 3. A single external procedure demo where one or more 3GL routines use the +# "with context" argument: +# +# make -f demo_rdbms.mk extproc_with_context SHARED_LIBNAME=libname +# OBJS="demo.o ..." +# e.g. make -f demo_rdbms.mk extproc_with_context SHARED_LIBNAME=epdemo.so +# OBJS="epdemo1.o epdemo2.o" +# e.g. make -f demo_rdbms.mk extproc_with_context +# SHARED_LIBNAME=extdemo2.so OBJS="extdemo2.o" +# e.g. or For EXTDEMO2 DEMO ONLY: make -f demo_rdbms.mk demos +# +# 4. To link C++ demos: +# +# make -f demo_rdbms.mk cppdemos +# +# Example for building OCI programs with no pthread dependency +# +# 1. A single OCI demo: +# +# make -f demo_rdbms.mk build_nopthread EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms.mk build_nopthread EXE=oci02 OBJS=oci02.o +# +# +# NOTE: 1. ORACLE_HOME must be either: +# . set in the user's environment +# . passed in on the command line +# . defined in a modified version of this makefile +# +# 2. If the target platform support shared libraries (e.g. Solaris) +# look in the platform specific documentation for information +# about environment variables that need to be properly +# defined (e.g. LD_LIBRARY_PATH in Solaris). +# + +include $(ORACLE_HOME)/rdbms/lib/env_rdbms.mk + +# flag for linking with non-deferred option (default is deferred mode) +NONDEFER=false + +DEMO_DIR=$(ORACLE_HOME)/rdbms/demo +DEMO_MAKEFILE = $(DEMO_DIR)/demo_rdbms.mk + +DEMOS = cdemo1 cdemo2 cdemo3 cdemo4 cdemo5 cdemo81 cdemo82 \ + cdemobj cdemolb cdemodsc cdemocor cdemolb2 cdemolbs \ + cdemodr1 cdemodr2 cdemodr3 cdemodsa obndra \ + cdemoext cdemothr cdemofil cdemofor \ + oci02 oci03 oci04 oci05 oci06 oci07 oci08 oci09 oci10 \ + oci11 oci12 oci13 oci14 oci15 oci16 oci17 oci18 oci19 oci20 \ + oci21 oci22 oci23 oci24 oci25 readpipe cdemosyev \ + ociaqdemo00 ociaqdemo01 ociaqdemo02 cdemoucb nchdemo1 \ + ociaqarraydeq ociaqarrayenq strmmon + +DEMOS_DP = cdemdpco cdemdpin cdemdpit cdemdplp cdemdpno cdemdpro cdemdpss + +CPPDEMOS = cdemo6 +# OCCI Demos +OCCIDEMOS = occiblob occiclob occicoll occidesc occidml occipool occiproc \ + occistre occiaqlis occiscp occixa occiuni1 occimb1 occilbar +OCCIOTTDEMOS = occiobj occiinh occipobj occiaqop +OCCIOTTUSR = hr +OCCIOTTPWD = hr +OCCI_UNICODE_OPT = none +# OTT Markers Support +OCCIOTTDEMOSWITHMARKER = mdemo1 +OTTUSR = scott +OTTPWD = tiger +CPDEMOS = cdemocp cdemocpproxy cdemosp cdemostc + +.SUFFIXES: .o .cob .for .c .pc .cc .cpp + +demos: $(DEMOS) extdemo2 extdemo4 extdemo5 extdemo6 + +demos_dp: $(DEMOS_DP) + +generate_sharedlib: + $(SILENT)$(ECHO) "Building client shared library ..." + $(SILENT)$(ECHO) "Calling script $$ORACLE_HOME/bin/genclntsh ..." + $(GENCLNTSH) + $(SILENT)$(ECHO) "The library is $$ORACLE_HOME/lib/libclntsh.so... DONE" + $(SILENT)$(ECHO) "Building occi shared library ..." + $(SILENT)$(ECHO) "Calling script $$ORACLE_HOME/bin/genoccish ..." + $(GENOCCISH) + $(SILENT)$(ECHO) "The library is $$ORACLE_HOME/lib/libocci.so... DONE" + +BUILD=build +$(DEMOS): + $(MAKE) -f $(DEMO_MAKEFILE) $(BUILD) EXE=$@ OBJS=$@.o + +$(DEMOS_DP): cdemodp.c cdemodp0.h cdemodp.h + $(MAKE) -f $(DEMO_MAKEFILE) build_dp EXE=$@ OBJS=$@.o + +cppdemos: $(CPPDEMOS) + +$(CPPDEMOS): + $(MAKE) -f $(DEMO_MAKEFILE) buildcpp EXE=$@ OBJS=$@.o + +buildcpp: $(OBJS) + $(MAKECPLPLDEMO) + +occidemos: $(OCCIDEMOS) $(OCCIOTTDEMOS) $(OCCIOTTDEMOSWITHMARKER) + +$(OCCIDEMOS): + $(MAKE) -f $(DEMO_MAKEFILE) buildocci EXE=$@ OBJS=$@.o + +$(OCCIOTTDEMOS): + $(MAKE) -f $(DEMO_MAKEFILE) occiott OCCIOTTFILE=$@ + $(MAKE) -f $(DEMO_MAKEFILE) buildocci EXE=$@ OBJS="$@.o $@o.o $@m.o" + +# OTT Markers Support +$(OCCIOTTDEMOSWITHMARKER): + $(MAKE) -f $(DEMO_MAKEFILE) ott_mrkr OTTFILE=$@ + $(MAKE) -f $(DEMO_MAKEFILE) buildocci EXE=$@ OBJS="$@.o $@o.o $@m.o" + + +buildocci: $(OBJS) + $(MAKEOCCISHAREDDEMO) + +buildocci_static: $(OBJS) + $(MAKEOCCISTATICDEMO) + +occiott: + $(ORACLE_HOME)/bin/ott \ + userid=$(OCCIOTTUSR)/$(OCCIOTTPWD) \ + intype=$(OCCIOTTFILE).typ \ + outtype=$(OCCIOTTFILE)out.type \ + code=cpp \ + hfile=$(OCCIOTTFILE).h \ + cppfile=$(OCCIOTTFILE)o.cpp \ + attraccess=private \ + unicode=$(OCCI_UNICODE_OPT) + +# OTT Markers Suppport +ott_mrkr: + $(ORACLE_HOME)/bin/ott \ + userid=$(OTTUSR)/$(OTTPWD) \ + intype=$(OTTFILE).typ \ + outtype=$(OTTFILE)out.type \ + code=cpp \ + hfile=$(OTTFILE).h \ + cppfile=$(OTTFILE)o.cpp \ + use_marker=true + +cpdemos: $(CPDEMOS) +$(CPDEMOS): + $(MAKE) -f $(DEMO_MAKEFILE) buildcp EXE=$@ OBJS=$@.o +buildcp: $(OBJS) + $(MAKECPSHAREDDEMO) +buildcp_static: $(OBJS) + $(MAKECPSTATICDEMO) + +# Pro*C rules +# SQL Precompiler macros + +pc1: + $(PCC2C) + +.pc.c: + $(MAKE) -f $(DEMO_MAKEFILE) PCCSRC=$* I_SYM=include= pc1 + +.pc.o: + $(MAKE) -f $(DEMO_MAKEFILE) PCCSRC=$* I_SYM=include= pc1 + $(PCCC2O) + +.cc.o: + $(CCC2O) + +.cpp.o: + $(CCC2O) + +build: $(LIBCLNTSH) $(OBJS) + $(BUILDEXE) + +extdemo2: + $(MAKE) -f $(DEMO_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo2.so OBJS="extdemo2.o" + +extdemo4: + $(MAKE) -f $(DEMO_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo4.so OBJS="extdemo4.o" + +extdemo5: + $(MAKE) -f $(DEMO_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo5.so OBJS="extdemo5.o" + +extdemo6: + $(MAKE) -f $(DEMO_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo6.so OBJS="extdemo6.o" + +.c.o: + $(C2O) + +build_dp: $(LIBCLNTSH) $(OBJS) cdemodp.o + $(DPTARGET) + +build_static: $(OBJS) + $(O2STATIC) + +# These 3 macros should be supplied by platform-specific files +#LLIBCLNTSH_NPT=$(LDLIBFLAG)$(LIBCLNTSHNAME)_nopthread +#LIBCLNTSH_NPT=$(LIBHOME)$(LIB_PREFIX)$(LIBCLNTSHNAME)_nopthread.$(SO_EXT) +#SYSLIBS_NPT=`$(CAT) $(SYSLIBLIST) | sed 's/-lpthread//g' ` + +build_clntshared : + $(MAKECLNTSHAREDDEMO) + +# You can build OCI programs with no pthread dependency using +# the following target. +build_nopthread: $(LIBCLNTSH_NPT) $(OBJS) + $(SILENT)$(MAKE) -f $(DEMO_MAKEFILE) build EXE=$(EXE) OBJS=$(OBJS) \ + LLIBCLNTSH=$(LLIBCLNTSH_NPT) SYSLIBS='$(SYSLIBS_NPT)' + +# extproc_no_context and extproc_with_context are the current names of these +# targets. The old names, extproc_nocallback and extproc_callback are +# preserved for backward compatibility. + +extproc_no_context extproc_nocallback: $(OBJS) + $(BUILDLIB_NO_CONTEXT) + +extproc_with_context extproc_callback: $(OBJS) $(LIBCLNTSH) + $(BUILDLIB_WITH_CONTEXT) + +clean: + $(RM) -f $(DEMOS) $(CPDEMOS) extdemo2 extdemo4 extdemo5 extdemo6 *.o *.so + $(RM) -f $(OCCIDEMOS) $(OCCIOTTDEMOS) $(OCCIOTTDEMOSWITHMARKER) occi*m.cpp occi*o.cpp occi*.type occiobj*.h occiinh*.h occipobj*.h + $(RM) -f $(DEMOS_DP) diff --git a/demo_rdbms32.mk b/demo_rdbms32.mk new file mode 100644 index 0000000..535a1f2 --- /dev/null +++ b/demo_rdbms32.mk @@ -0,0 +1,337 @@ +# This makefile is similar to demo_rdbms.mk, but this one builds +# 32-bit client executables. (It uses demo_rdbms.mk to build any +# shared-libraries that are loaded into the database server, e.g. for +# external procedure call.) +# +# Example for building demo OCI programs: +# +# 1. All OCI demos (including extdemo2, extdemo4 and extdemo5): +# +# make -f demo_rdbms32.mk demos +# +# 2. A single OCI demo: +# +# make -f demo_rdbms32.mk build EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms32.mk build EXE=oci02 OBJS=oci02.o +# +# 3. A single OCI demo with static libraries: +# +# make -f demo_rdbms32.mk build_static EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms32.mk build_static EXE=oci02 OBJS=oci02.o +# +# 4. To re-generate shared library: +# +# make -f demo_rdbms32.mk generate_sharedlib +# +# 5. All OCCI demos +# +# make -f demo_rdbms32.mk occidemos +# +# 6. A single OCCI demo: +# +# make -f demo_rdbms32.mk +# e.g. make -f demo_rdbms32.mk occidml +# OR +# make -f demo_rdbms32.mk buildocci EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildocci EXE=occidml OBJS=occidml.o +# +# 7. A single OCCI demo with static libraries: +# +# make -f demo_rdbms32.mk buildocci_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildocci_static EXE=occiblob OBJS=occiblob.o +# +# 8. All OCI Connection Pooling, Session Pooling and Statement Cache demos +# +# make -f demo_rdbms32.mk cpdemos +# +# 9. A single OCI Connection Pooling demo: +# +# make -f demo_rdbms32.mk +# e.g. make -f demo_rdbms32.mk cdemocp +# OR +# make -f demo_rdbms32.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildcp EXE=cdemocp OBJS=cdemocp.o +# +# 10. A single OCI Connection Pooling demo with static libraries: +# +# make -f demo_rdbms32.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildcp_static EXE=cdemocp OBJS=cdemocp.o +# +# 11. A single OCI Session Pooling demo: +# +# make -f demo_rdbms32.mk +# e.g. make -f demo_rdbms32.mk cdemosp +# OR +# make -f demo_rdbms32.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildcp EXE=cdemosp OBJS=cdemosp.o +# +# 12. A single OCI Session Pooling demo with static libraries: +# +# make -f demo_rdbms32.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildcp_static EXE=cdemosp OBJS=cdemosp.o +# +# +# 13. A single OCI Statement Cache demo: +# +# make -f demo_rdbms32.mk +# e.g. make -f demo_rdbms32.mk cdemostc +# OR +# make -f demo_rdbms32.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildcp EXE=cdemostc OBJS=cdemostc.o +# +# 14. A single OCI Statement Cache demo with static libraries: +# +# make -f demo_rdbms32.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildcp_static EXE=cdemostc OBJS=cdemostc.o +# +# +# Example for building demo DIRECT PATH API programs: +# +# 1. All DIRECT PATH API demos: +# +# make -f demo_rdbms32.mk demos_dp +# +# 2. A single DIRECT PATH API demo: +# +# make -f demo_rdbms32.mk build_dp EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms32.mk build_dp EXE=cdemdplp OBJS=cdemdplp.o +# +# +# Example for building external procedures demo programs: +# +# 1. All external procedure demos: +# +# 2. A single external procedure demo whose 3GL routines do not use the +# "with context" argument: +# +# make -f demo_rdbms32.mk extproc_no_context SHARED_LIBNAME=libname +# OBJS="demo.o ..." +# e.g. make -f demo_rdbms32.mk extproc_no_context SHARED_LIBNAME=epdemo.so +# OBJS="epdemo1.o epdemo2.o" +# +# 3. A single external procedure demo where one or more 3GL routines use the +# "with context" argument: +# +# make -f demo_rdbms32.mk extproc_with_context SHARED_LIBNAME=libname +# OBJS="demo.o ..." +# e.g. make -f demo_rdbms32.mk extproc_with_context SHARED_LIBNAME=epdemo.so +# OBJS="epdemo1.o epdemo2.o" +# e.g. make -f demo_rdbms32.mk extproc_with_context +# SHARED_LIBNAME=extdemo2.so OBJS="extdemo2.o" +# e.g. or For EXTDEMO2 DEMO ONLY: make -f demo_rdbms32.mk demos +# +# 4. To link C++ demos: +# +# make -f demo_rdbms32.mk cppdemos +# +# Example for building OCI programs with libclntsh.so +# +# 1. A single OCI demo: +# +# make -f demo_rdbms32.mk build_clntshared EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms32.mk build_clntshared EXE=oci02 OBJS=oci02.o +# +# Example for building OCI programs with no pthread dependency +# +# 1. A single OCI demo: +# +# make -f demo_rdbms32.mk build_nopthread EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms32.mk build_nopthread EXE=oci02 OBJS=oci02.o +# +# +# +# NOTE: 1. ORACLE_HOME must be either: +# . set in the user's environment +# . passed in on the command line +# . defined in a modified version of this makefile +# +# 2. If the target platform support shared libraries (e.g. Solaris) +# look in the platform specific documentation for information +# about environment variables that need to be properly +# defined (e.g. LD_LIBRARY_PATH in Solaris). +# + +include $(ORACLE_HOME)/rdbms/lib/env_rdbms.mk + +# flag for linking with non-deferred option (default is deferred mode) +NONDEFER=false + +DEMO_DIR=$(ORACLE_HOME)/rdbms/demo +DEMO_MAKEFILE = $(DEMO_DIR)/demo_rdbms.mk +DEMO32_MAKEFILE = $(DEMO_DIR)/demo_rdbms32.mk + +DEMOS = cdemo1 cdemo2 cdemo3 cdemo4 cdemo5 cdemo81 cdemo82 \ + cdemobj cdemolb cdemodsc cdemocor cdemolb2 cdemolbs \ + cdemodr1 cdemodr2 cdemodr3 cdemodsa obndra \ + cdemoext cdemothr cdemofil cdemofor \ + oci02 oci03 oci04 oci05 oci06 oci07 oci08 oci09 oci10 \ + oci11 oci12 oci13 oci14 oci15 oci16 oci17 oci18 oci19 oci20 \ + oci21 oci22 oci23 oci24 oci25 readpipe cdemosyev \ + ociaqdemo00 ociaqdemo01 ociaqdemo02 cdemoucb nchdemo1 \ + ociaqarraydeq ociaqarrayenq strmmon + +DEMOS_DP = cdemdpco cdemdpin cdemdpit cdemdplp cdemdpno cdemdpro cdemdpss + +CPPDEMOS = cdemo6 +# OCCI Demos +OCCIDEMOS = occiblob occiclob occicoll occidesc occidml occipool occiproc \ + occistre occiaqlis occiscp occixa occiuni1 occimb1 occilbar +OCCIOTTDEMOS = occiobj occiinh occipobj occiaqop +OCCIOTTUSR = hr +OCCIOTTPWD = hr +OCCI_UNICODE_OPT = none +# OTT Markers Support +OCCIOTTDEMOSWITHMARKER = mdemo1 +OTTUSR = scott +OTTPWD = tiger +CPDEMOS = cdemocp cdemocpproxy cdemosp cdemostc + +.SUFFIXES: .o .cob .for .c .pc .cc .cpp + +demos: $(DEMOS) extdemo2 extdemo4 extdemo5 extdemo6 + +demos_dp: $(DEMOS_DP) + +generate_sharedlib: + $(SILENT)$(ECHO) "Building client shared library ..." + $(SILENT)$(ECHO) "Calling script $$ORACLE_HOME/bin/genclntsh ..." + $(GENCLNTSH32) + $(SILENT)$(ECHO) "The library is $$ORACLE_HOME/lib/libclntsh.so... DONE" + +BUILD=build +$(DEMOS): + $(MAKE) -f $(DEMO32_MAKEFILE) $(BUILD) EXE=$@ OBJS=$@.o + +$(DEMOS_DP): cdemodp.c cdemodp0.h cdemodp.h + $(MAKE) -f $(DEMO32_MAKEFILE) build_dp EXE=$@ OBJS=$@.o + +cppdemos: $(CPPDEMOS) + +$(CPPDEMOS): + $(MAKE) -f $(DEMO32_MAKEFILE) buildcpp EXE=$@ OBJS=$@.o + +buildcpp: $(OBJS) + $(MAKECPLPLDEMO32) + +occidemos: $(OCCIDEMOS) $(OCCIOTTDEMOS) $(OCCIOTTDEMOSWITHMARKER) + +$(OCCIDEMOS): + $(MAKE) -f $(DEMO32_MAKEFILE) buildocci EXE=$@ OBJS=$@.o + +$(OCCIOTTDEMOS): + $(MAKE) -f $(DEMO32_MAKEFILE) occiott OCCIOTTFILE=$@ + $(MAKE) -f $(DEMO32_MAKEFILE) buildocci EXE=$@ OBJS="$@.o $@o.o $@m.o" + +# OTT Markers Support +$(OCCIOTTDEMOSWITHMARKER): + $(MAKE) -f $(DEMO32_MAKEFILE) ott_mrkr OTTFILE=$@ + $(MAKE) -f $(DEMO32_MAKEFILE) buildocci EXE=$@ OBJS="$@.o $@o.o $@m.o" + + +buildocci: $(OBJS) + $(MAKEOCCISHAREDDEMO32) + +buildocci_static: $(OBJS) + $(MAKEOCCISTATICDEMO32) + +occiott: + $(ORACLE_HOME)/bin/ott \ + userid=$(OCCIOTTUSR)/$(OCCIOTTPWD) \ + intype=$(OCCIOTTFILE).typ \ + outtype=$(OCCIOTTFILE)out.type \ + code=cpp \ + hfile=$(OCCIOTTFILE).h \ + cppfile=$(OCCIOTTFILE)o.cpp \ + attraccess=private \ + unicode=$(OCCI_UNICODE_OPT) + +# OTT Markers Suppport +ott_mrkr: + $(ORACLE_HOME)/bin/ott \ + userid=$(OTTUSR)/$(OTTPWD) \ + intype=$(OTTFILE).typ \ + outtype=$(OTTFILE)out.type \ + code=cpp \ + hfile=$(OTTFILE).h \ + cppfile=$(OTTFILE)o.cpp \ + use_marker=true + +cpdemos: $(CPDEMOS) +$(CPDEMOS): + $(MAKE) -f $(DEMO32_MAKEFILE) buildcp EXE=$@ OBJS=$@.o +buildcp: $(OBJS) + $(MAKECPSHAREDDEMO32) +buildcp_static: $(OBJS) + $(MAKECPSTATICDEMO32) + +# Pro*C rules +# SQL Precompiler macros + +pc1: + $(PCC2C) + +.pc.c: + $(MAKE) -f $(DEMO32_MAKEFILE) PCCSRC=$* I_SYM=include= pc1 + +.pc.o: + $(MAKE) -f $(DEMO32_MAKEFILE) PCCSRC=$* I_SYM=include= pc1 + $(PCCC2O32) + +.cc.o: + $(CCC2O32) + +.cpp.o: + $(CCC2O32) + +build: $(LIBCLNTSH) $(OBJS) + $(BUILDEXE32) + +extdemo2: + $(MAKE) -f $(DEMO32_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo2.so OBJS="extdemo2.o" + +extdemo4: + $(MAKE) -f $(DEMO32_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo4.so OBJS="extdemo4.o" + +extdemo5: + $(MAKE) -f $(DEMO32_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo5.so OBJS="extdemo5.o" + +extdemo6: + $(MAKE) -f $(DEMO32_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo6.so OBJS="extdemo6.o" + +.c.o: + $(C2O32) + +build_dp: $(LIBCLNTSH) $(OBJS) cdemodp.o + $(DPTARGET32) + +build_static: $(OBJS) + $(O2STATIC32) + +# These 3 should be supplied by platform specific files +#LLIBCLNTSH_NPT=$(LDLIBFLAG)$(LIBCLNTSHNAME)_nopthread +#LIBCLNTSH_NPT=$(LIBHOME32)$(LIB_PREFIX)$(LIBCLNTSHNAME)_nopthread.$(SO_EXT) +#BUILDEXE32_NPT=$(CC) $(LDFLAGS32) -o $(EXE) $(OBJS) $(LLIBCLNTSH_NPT) $(MATHLIB) + +build_clntshared : + $(MAKECLNTSHAREDDEMO32) + +# You can build OCI programs with no pthread dependency using +# the following target. +build_nopthread: $(LIBCLNTSH_NPT) $(OBJS) + $(MAKENPTDEMO32) + +# extproc_no_context and extproc_with_context are the current names of these +# targets. The old names, extproc_nocallback and extproc_callback are +# preserved for backward compatibility. + +extproc_no_context extproc_nocallback: $(OBJS) + $(BUILDLIB32_NO_CONTEXT) + +extproc_with_context extproc_callback: $(OBJS) $(LIBCLNTSH) + $(BUILDLIB32_WITH_CONTEXT) + +clean: + $(RM) -f $(DEMOS) $(CPDEMOS) extdemo2 extdemo4 extdemo5 extdemo6 *.o *.so + $(RM) -f $(OCCIDEMOS) $(OCCIOTTDEMOS) $(OCCIOTTDEMOSWITHMARKER) occi*m.cpp occi*o.cpp \ + occi*.type occiobj*.h occiinh*.h occipobj*.h + $(RM) -f $(DEMOS_DP) diff --git a/demo_rdbms64.mk b/demo_rdbms64.mk new file mode 100644 index 0000000..8b6b2b2 --- /dev/null +++ b/demo_rdbms64.mk @@ -0,0 +1,327 @@ +# This makefile is similar to demo_rdbms.mk, but this one builds +# 64-bit client executables. (It uses demo_rdbms.mk to build any +# shared-libraries that are loaded into the database server, e.g. for +# external procedure call.) +# +# Example for building demo OCI programs: +# +# 1. All OCI demos (including extdemo2, extdemo4 and extdemo5): +# +# make -f demo_rdbms64.mk demos +# +# 2. A single OCI demo: +# +# make -f demo_rdbms64.mk build EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms64.mk build EXE=oci02 OBJS=oci02.o +# +# 3. A single OCI demo with static libraries: +# +# make -f demo_rdbms64.mk build_static EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms64.mk build_static EXE=oci02 OBJS=oci02.o +# +# 4. To re-generate shared library: +# +# make -f demo_rdbms64.mk generate_sharedlib +# +# 5. All OCCI demos +# +# make -f demo_rdbms64.mk occidemos +# +# 6. A single OCCI demo: +# +# make -f demo_rdbms64.mk +# e.g. make -f demo_rdbms64.mk occidml +# OR +# make -f demo_rdbms64.mk buildocci EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildocci EXE=occidml OBJS=occidml.o +# +# 7. A single OCCI demo with static libraries: +# +# make -f demo_rdbms64.mk buildocci_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildocci_static EXE=occiblob OBJS=occiblob.o +# +# 8. All OCI Connection Pooling, Session Pooling and Statement Cache demos +# +# make -f demo_rdbms64.mk cpdemos +# +# 9. A single OCI Connection Pooling demo: +# +# make -f demo_rdbms64.mk +# e.g. make -f demo_rdbms64.mk cdemocp +# OR +# make -f demo_rdbms64.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildcp EXE=cdemocp OBJS=cdemocp.o +# +# 10. A single OCI Connection Pooling demo with static libraries: +# +# make -f demo_rdbms64.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildcp_static EXE=cdemocp OBJS=cdemocp.o +# +# 11. A single OCI Session Pooling demo: +# +# make -f demo_rdbms64.mk +# e.g. make -f demo_rdbms64.mk cdemosp +# OR +# make -f demo_rdbms64.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildcp EXE=cdemosp OBJS=cdemosp.o +# +# 12. A single OCI Session Pooling demo with static libraries: +# +# make -f demo_rdbms64.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildcp_static EXE=cdemosp OBJS=cdemosp.o +# +# +# 13. A single OCI Statement Cache demo: +# +# make -f demo_rdbms64.mk +# e.g. make -f demo_rdbms64.mk cdemostc +# OR +# make -f demo_rdbms64.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildcp EXE=cdemostc OBJS=cdemostc.o +# +# 14. A single OCI Statement Cache demo with static libraries: +# +# make -f demo_rdbms64.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildcp_static EXE=cdemostc OBJS=cdemostc.o +# +# +# Example for building demo DIRECT PATH API programs: +# +# 1. All DIRECT PATH API demos: +# +# make -f demo_rdbms64.mk demos_dp +# +# 2. A single DIRECT PATH API demo: +# +# make -f demo_rdbms64.mk build_dp EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms64.mk build_dp EXE=cdemdplp OBJS=cdemdplp.o +# +# +# Example for building external procedures demo programs: +# +# 1. All external procedure demos: +# +# 2. A single external procedure demo whose 3GL routines do not use the +# "with context" argument: +# +# make -f demo_rdbms64.mk extproc_no_context SHARED_LIBNAME=libname +# OBJS="demo.o ..." +# e.g. make -f demo_rdbms64.mk extproc_no_context SHARED_LIBNAME=epdemo.so +# OBJS="epdemo1.o epdemo2.o" +# +# 3. A single external procedure demo where one or more 3GL routines use the +# "with context" argument: +# +# make -f demo_rdbms64.mk extproc_with_context SHARED_LIBNAME=libname +# OBJS="demo.o ..." +# e.g. make -f demo_rdbms64.mk extproc_with_context SHARED_LIBNAME=epdemo.so +# OBJS="epdemo1.o epdemo2.o" +# e.g. make -f demo_rdbms64.mk extproc_with_context +# SHARED_LIBNAME=extdemo2.so OBJS="extdemo2.o" +# e.g. or For EXTDEMO2 DEMO ONLY: make -f demo_rdbms64.mk demos +# +# 4. To link C++ demos: +# +# make -f demo_rdbms64.mk cppdemos +# +# 1. A single OCI demo: +# +# make -f demo_rdbms64.mk build_clntshared EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms64.mk build_clntshared EXE=oci02 OBJS=oci02.o +# +# Example for building OCI programs with no pthread dependency +# +# 1. A single OCI demo: +# +# make -f demo_rdbms64.mk build_nopthread EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms64.mk build_nopthread EXE=oci02 OBJS=oci02.o +# +# NOTE: 1. ORACLE_HOME must be either: +# . set in the user's environment +# . passed in on the command line +# . defined in a modified version of this makefile +# +# 2. If the target platform support shared libraries (e.g. Solaris) +# look in the platform specific documentation for information +# about environment variables that need to be properly +# defined (e.g. LD_LIBRARY_PATH in Solaris). +# + +include $(ORACLE_HOME)/rdbms/lib/env_rdbms.mk + +# flag for linking with non-deferred option (default is deferred mode) +NONDEFER=false + +DEMO_DIR=$(ORACLE_HOME)/rdbms/demo +DEMO_MAKEFILE = $(DEMO_DIR)/demo_rdbms.mk +DEMO64_MAKEFILE = $(DEMO_DIR)/demo_rdbms64.mk + +DEMOS = cdemo1 cdemo2 cdemo3 cdemo4 cdemo5 cdemo81 cdemo82 \ + cdemobj cdemolb cdemodsc cdemocor cdemolb2 cdemolbs \ + cdemodr1 cdemodr2 cdemodr3 cdemodsa obndra \ + cdemoext cdemothr cdemofil cdemofor \ + oci02 oci03 oci04 oci05 oci06 oci07 oci08 oci09 oci10 \ + oci11 oci12 oci13 oci14 oci15 oci16 oci17 oci18 oci19 oci20 \ + oci21 oci22 oci23 oci24 oci25 readpipe cdemosyev \ + ociaqdemo00 ociaqdemo01 ociaqdemo02 cdemoucb nchdemo1 \ + ociaqarraydeq ociaqarrayenq strmmon + +DEMOS_DP = cdemdpco cdemdpin cdemdpit cdemdplp cdemdpno cdemdpro cdemdpss + +CPPDEMOS = cdemo6 +# OCCI Demos +OCCIDEMOS = occiblob occiclob occicoll occidesc occidml occipool occiproc \ + occistre occiaqlis occiscp occixa occiuni1 occimb1 occilbar +OCCIOTTDEMOS = occiobj occiinh occipobj occiaqop +OCCIOTTUSR = hr +OCCIOTTPWD = hr +OCCI_UNICODE_OPT = none +# OTT Markers Support +OCCIOTTDEMOSWITHMARKER = mdemo1 +OTTUSR = scott +OTTPWD = tiger +CPDEMOS = cdemocp cdemocpproxy cdemosp cdemostc + +.SUFFIXES: .o .cob .for .c .pc .cc .cpp + +demos: $(DEMOS) extdemo2 extdemo4 extdemo5 extdemo6 + +demos_dp: $(DEMOS_DP) + +generate_sharedlib: + $(SILENT)$(ECHO) "Building client shared library ..." + $(SILENT)$(ECHO) "Calling script $$ORACLE_HOME/bin/genclntsh ..." + $(GENCLNTSH64) + $(SILENT)$(ECHO) "The library is $$ORACLE_HOME/lib/libclntsh.so... DONE" + +BUILD=build +$(DEMOS): + $(MAKE) -f $(DEMO64_MAKEFILE) $(BUILD) EXE=$@ OBJS=$@.o + +$(DEMOS_DP): cdemodp.c cdemodp0.h cdemodp.h + $(MAKE) -f $(DEMO64_MAKEFILE) build_dp EXE=$@ OBJS=$@.o + +cppdemos: $(CPPDEMOS) + +$(CPPDEMOS): + $(MAKE) -f $(DEMO64_MAKEFILE) buildcpp EXE=$@ OBJS=$@.o + +buildcpp: $(OBJS) + $(MAKECPLPLDEMO64) + +occidemos: $(OCCIDEMOS) $(OCCIOTTDEMOS) $(OCCIOTTDEMOSWITHMARKER) + +$(OCCIDEMOS): + $(MAKE) -f $(DEMO64_MAKEFILE) buildocci EXE=$@ OBJS=$@.o + +$(OCCIOTTDEMOS): + $(MAKE) -f $(DEMO64_MAKEFILE) occiott OCCIOTTFILE=$@ + $(MAKE) -f $(DEMO64_MAKEFILE) buildocci EXE=$@ OBJS="$@.o $@o.o $@m.o" + +# OTT Markers Support +$(OCCIOTTDEMOSWITHMARKER): + $(MAKE) -f $(DEMO64_MAKEFILE) ott_mrkr OTTFILE=$@ + $(MAKE) -f $(DEMO64_MAKEFILE) buildocci EXE=$@ OBJS="$@.o $@o.o $@m.o" + +buildocci: $(OBJS) + $(MAKEOCCISHAREDDEMO64) + +buildocci_static: $(OBJS) + $(MAKEOCCISTATICDEMO64) + +occiott: + $(ORACLE_HOME)/bin/ott \ + userid=$(OCCIOTTUSR)/$(OCCIOTTPWD) \ + intype=$(OCCIOTTFILE).typ \ + outtype=$(OCCIOTTFILE)out.type \ + code=cpp \ + hfile=$(OCCIOTTFILE).h \ + cppfile=$(OCCIOTTFILE)o.cpp \ + attraccess=private \ + unicode=$(OCCI_UNICODE_OPT) + +# OTT Markers Suppport +ott_mrkr: + $(ORACLE_HOME)/bin/ott \ + userid=$(OTTUSR)/$(OTTPWD) \ + intype=$(OTTFILE).typ \ + outtype=$(OTTFILE)out.type \ + code=cpp \ + hfile=$(OTTFILE).h \ + cppfile=$(OTTFILE)o.cpp \ + use_marker=true + +cpdemos: $(CPDEMOS) +$(CPDEMOS): + $(MAKE) -f $(DEMO64_MAKEFILE) buildcp EXE=$@ OBJS=$@.o +buildcp: $(OBJS) + $(MAKECPSHAREDDEMO64) +buildcp_static: $(OBJS) + $(MAKECPSTATICDEMO64) + +# Pro*C rules +# SQL Precompiler macros + +pc1: + $(PCC2C) + +.pc.c: + $(MAKE) -f $(DEMO64_MAKEFILE) PCCSRC=$* I_SYM=include= pc1 + +.pc.o: + $(MAKE) -f $(DEMO64_MAKEFILE) PCCSRC=$* I_SYM=include= pc1 + $(PCCC2O64) + +.cc.o: + $(CCC2O64) + +.cpp.o: + $(CCC2O64) + +build: $(LIBCLNTSH) $(OBJS) + $(BUILDEXE64) + +extdemo2: + $(MAKE) -f $(DEMO64_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo2.so OBJS="extdemo2.o" + +extdemo4: + $(MAKE) -f $(DEMO64_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo4.so OBJS="extdemo4.o" + +extdemo5: + $(MAKE) -f $(DEMO64_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo5.so OBJS="extdemo5.o" + +extdemo6: + $(MAKE) -f $(DEMO64_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo6.so OBJS="extdemo6.o" + +.c.o: + $(C2O64) + +build_dp: $(LIBCLNTSH) $(OBJS) cdemodp.o + $(DPTARGET64) + +build_static: $(OBJS) + $(O2STATIC64) + +build_clntshared : + $(MAKECLNTSHAREDDEMO64) + +# You can build OCI programs with no pthread dependency using +# the following target. +build_nopthread: $(LIBCLNTSH_NPT) $(OBJS) + $(MAKENPTDEMO64) + +# extproc_no_context and extproc_with_context are the current names of these +# targets. The old names, extproc_nocallback and extproc_callback are +# preserved for backward compatibility. + +extproc_no_context extproc_nocallback: $(OBJS) + $(BUILDLIB64_NO_CONTEXT) + +extproc_with_context extproc_callback: $(OBJS) $(LIBCLNTSH) + $(BUILDLIB64_WITH_CONTEXT) + +clean: + $(RM) -f $(DEMOS) $(CPDEMOS) extdemo2 extdemo4 extdemo5 extdemo6 *.o *.so + $(RM) -f $(OCCIDEMOS) $(OCCIOTTDEMOS) $(OCCIOTTDEMOSWITHMARKER) occi*m.cpp occi*o.cpp \ + occi*.type occiobj*.h occiinh*.h occipobj*.h + $(RM) -f $(DEMOS_DP) diff --git a/dmabdemo.java b/dmabdemo.java new file mode 100644 index 0000000..b90ea30 --- /dev/null +++ b/dmabdemo.java @@ -0,0 +1,1125 @@ +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.Statement; + +import java.text.DecimalFormat; +import java.text.MessageFormat; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.rule.CompoundPredicate; +import javax.datamining.rule.Rule; +import javax.datamining.rule.SimplePredicate; +import javax.datamining.supervised.classification.ClassificationApplySettings; +import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.supervised.classification.ClassificationTestMetricOption; +import javax.datamining.supervised.classification.ClassificationTestMetrics; +import javax.datamining.supervised.classification.ClassificationTestMetricsTask; +import javax.datamining.supervised.classification.ClassificationTestMetricsTaskFactory; +import javax.datamining.supervised.classification.ClassificationTestTaskFactory; +import javax.datamining.supervised.classification.ConfusionMatrix; +import javax.datamining.supervised.classification.Lift; +import javax.datamining.supervised.classification.ReceiverOperatingCharacterics; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; + +import oracle.dmt.jdm.algorithm.abn.OraABNModelType; +import oracle.dmt.jdm.algorithm.abn.OraABNSettings; +import oracle.dmt.jdm.algorithm.abn.OraABNSettingsFactory; +import oracle.dmt.jdm.base.OraModel; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.modeldetail.abn.OraABNModelDetail; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.rule.OraSimplePredicate; +import oracle.dmt.jdm.supervised.classification.OraLift; +import oracle.dmt.jdm.task.OraBuildTask; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.OraExpressionTransform; +import oracle.dmt.jdm.transform.OraTransformationFactory; +import oracle.dmt.jdm.transform.OraTransformationSequence; +import oracle.dmt.jdm.transform.binning.OraBinningTransform; +import oracle.dmt.jdm.transform.binning.OraCategoricalBinningType; +import oracle.dmt.jdm.transform.binning.OraNumericalBinningType; + + +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmabdemo.java +//J2SE imports + + +// Java Data Mining (JDM) standard imports +// Oracle Java Data Mining (JDM) implemented api imports + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using Adaptive Bayes Network(ABN) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* How to predict whether a customer responds or not to the new affinity card +* program using a classifier based on ABN algorithm? +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created in the user +* schema using CUSTOMERS, COUNTRIES and SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographic, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographic, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographic and purchasing +* details for predicting response to the new affinity card program. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* For ABN, binning transformation is used to reduce the cardinality of +* higher cardinality attributes. The prepareData() method in this demo program +* illustrates the preparation of the build data and how we can embed these +* transformations into the model. Model apply and test operations +* automatically apply the embedded transformations. +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification model using the ABN algorithm. +* Test Model: +* Classification model performance can be evaluated by computing test +* metrics like accuracy, confusion matrix, lift and ROC. The testModel() or +* computeTestMetrics() method illustrates how to perform the test operation to +* compute various metrics. +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification models. The applyModel() method illustrates how to +* predict the customer response for affinity card program. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines to execute this demo program. +*/ +public class + +dmabdemo + extends Object +{ + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClassificationSettingsFactory m_clasFactory; + private static OraABNSettingsFactory m_abnFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClassificationTestTaskFactory m_testFactory; + private static ClassificationApplySettingsFactory m_applySettingsFactory; + private static ClassificationTestMetricsTaskFactory m_testMetricsTaskFactory; + private static OraTransformationFactory m_xformFactory; + private static OraTransformationTaskFactory m_xformTaskFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + private static String TAB = " "; + private static String CR = "\n"; + private static String CR_TAB = "\n "; + private static String HORZ_LINE = "----"; + private static String UNDERLINE = + "*************************************"; + private static String RULES_ABN_HEADER = + "* Rules *"; + // Global data members + private static OraBinningTransform m_buildDataXform; + + public static void main(String[] args) + { + try + { + if (args.length != 3) + { + System.out.println("Usage: java dmabdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Prepare data + prepareData(); + // 5. Build model - Please see dmnbdemo.java to see how to build a model + // with supplied prior probability. + buildModel(); + // 6. Test model - To compute accuracy and confusion matrix, lift result + // and ROC for the model from an apply output data. + // Please see dnnbdemo.java to see how to test the model + // with a test input data and cost matrix. + computeTestMetrics(); + // 7. Apply model + applyModel(); + //8. Start execution of the transformation task that trigger execution of + // its dependent task(s), here after completion of the transformation task, + // build task executes; after build task test and apply tasks are executed. + // Note that this whole process is executed in the server + m_dmeConn.execute("abnXFormTask_jdm"); + //9. Monitor the task executions of current and its dependent tasks + // and display task output results + monitorTaskExecutionProcess(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + } // Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + */ + public static void initFactories() + throws JDMException + { + m_pdsFactory = + (PhysicalDataSetFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalDataSet"); + m_paFactory = + (PhysicalAttributeFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalAttribute"); + m_clasFactory = + (ClassificationSettingsFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationSettings"); + m_abnFactory = + (OraABNSettingsFactory) m_dmeConn.getFactory("oracle.dmt.jdm.algorithm.abn.OraABNSettings"); + m_buildFactory = + (BuildTaskFactory) m_dmeConn.getFactory("javax.datamining.task.BuildTask"); + m_dsApplyFactory = + (DataSetApplyTaskFactory) m_dmeConn.getFactory("javax.datamining.task.apply.DataSetApplyTask"); + m_testFactory = + (ClassificationTestTaskFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationTestTask"); + m_applySettingsFactory = + (ClassificationApplySettingsFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationApplySettings"); + m_testMetricsTaskFactory = + (ClassificationTestMetricsTaskFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationTestMetricsTask"); + m_xformFactory = + (OraTransformationFactory) m_dmeConn.getFactory("oracle.dmt.jdm.transform.OraTransformation"); + m_xformTaskFactory = + (OraTransformationTaskFactory) m_dmeConn.getFactory("oracle.dmt.jdm.task.OraTransformationTask"); + } + + /** + * This method illustrates preparation of the data for build, test, and apply + * operations by using binning transformation. + * + * Here numerical attributes AGE and YRS_RESIDENCE are prepared using + * quantile binning. Categorical attributes COUNTRY_NAME and OCCUPATION + * are prepared using top-n binning. For more details about binning, + * refer to Oracle Data Mining Concepts Guide. + * + * The case id, target attribute, and any attribute with <= 2 distinct values + * should be excluded from the binning process. However, + * we may exclude additional attributes from the binning process to + * demonstrate how to exclude additional attributes from the binning process. + * + * The following table illustrates customer attributes available for building + * the mining model and data characteristics and type of binning used + * for each attribute and number of bins used. + * + * COLUMN_NAME DATA_TYPE DISTINCT EXCLUDED BIN TYPE BIN # + * ------------------ --------- -------- -------- ----------- ----- + * CUST_ID NUMBER 1500 YES + * CUST_GENDER CHAR 2 YES + * AGE NUMBER 66 NO QUANTILE 5 + * CUST_MARITAL_STATUS VARCHAR2 7 YES + * COUNTRY_NAME VARCHAR2 19 NO TOP-N 7 + * CUST_INCOME_LEVEL VARCHAR2 12 YES + * EDUCATION VARCHAR2 16 YES + * OCCUPATION VARCHAR2 15 NO TOP-N 7 + * HOUSEHOLD_SIZE VARCHAR2 6 YES + * YRS_RESIDENCE NUMBER 15 NO QUANTILE 5 + * AFFINITY_CARD NUMBER 2 YES + * BULK_PACK_DISKETTES NUMBER 2 YES + * FLAT_PANEL_MONITOR NUMBER 2 YES + * HOME_THEATER_PACKAGE NUMBER 2 YES + * BOOKKEEPING_APPLICATION NUMBER 2 YES + * PRINTER_SUPPLIES NUMBER 1 YES + * Y_BOX_GAMES NUMBER 2 YES + * OS_DOC_SET_KANJI NUMBER 2 YES + * + * Build data binnning transformation produces numerical and categorical + * bin boundary tables. These tables must be specified for test and apply data + * to bin the data consistent with the build data. + * Following binned tables are created after the execution of this method. + * + * Unprepared Data ---> Prepared(Binned) Data + * --------------------- --------------------------- + * MINING_DATA_BUILD_V ABN_BINNED_DATA_BUILD_JDM + * MINING_DATA_TEST_V ABN_BINNED_DATA_TEST_JDM + * MINING_DATA_APPLY_V ABN_BINNED_DATA_APPLY_JDM + */ + public static void prepareData() + throws JDMException + { + + boolean isOutputAsView = false; + String inputDataURI = null; + String outputDataURI = null; + String categoricalBinTable = null; + String numericalBinTable = null; + OraTransformationTask xformTask = null; + // 1. Prepare build data + isOutputAsView = true; + inputDataURI = "MINING_DATA_BUILD_V"; + outputDataURI = "ABN_PREP_DATA_BUILD_JDM"; + m_buildDataXform = m_xformFactory.createBinningTransform(); + String[] excludeColumnList = + { "CUST_ID", "CUST_GENDER", "CUST_MARITAL_STATUS", "CUST_INCOME_LEVEL", + "EDUCATION", "HOUSEHOLD_SIZE", "AFFINITY_CARD", + "BULK_PACK_DISKETTES", "FLAT_PANEL_MONITOR", "HOME_THEATER_PACKAGE", + "BOOKKEEPING_APPLICATION", "PRINTER_SUPPLIES", "Y_BOX_GAMES", + "OS_DOC_SET_KANJI" }; + m_buildDataXform.setExcludeColumnList(excludeColumnList); + // Categorical binning definition + m_buildDataXform.setNumberOfBinsForCategorical(7); + m_buildDataXform.setCategoricalBinningType(OraCategoricalBinningType.top_n); + // Numerical binning definition + m_buildDataXform.setNumberOfBinsForNumerical(5); + m_buildDataXform.setNumericalBinningType(OraNumericalBinningType.quantile); + //2. Create Transformation sequence + List xformList = + new ArrayList(1); //There is only one xform in this example, so capacity specified as 1 + xformList.add(m_buildDataXform); + OraTransformationSequence xformSeq = + m_xformFactory.createTransformationSequence(inputDataURI, xformList, + outputDataURI); + m_dmeConn.saveObject("abnBuildDataXformSeq_jdm", xformSeq, true); + //3. Create and execute transformation task + xformTask = + m_xformTaskFactory.create("abnBuildDataXformSeq_jdm", false); + saveTask(xformTask, "abnXFormTask_jdm", null); + } + + /** + * This method illustrates how to build a mining model using the + * ABN_BINNED_DATA_BUILD_JDM dataset and classification settings + * with ABN algorithm. + * + * By default, the ABN algorithm uses model type as multi feature. Multi feature + * doesn't produce model details. Here single feature is used to demonstrate + * retrieval of model details. + */ + public static void buildModel() + throws JDMException + { + + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + buildData.addAttribute(pa); + m_dmeConn.saveObject("abnBuildData_jdm", buildData, true); + // 2. Create & save Classification Settings + // Create ABN algorithm settings + OraABNSettings abnAlgo = m_abnFactory.create(); + abnAlgo.setModelType(OraABNModelType.singleFeature); + // Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(abnAlgo); + buildSettings.setTargetAttributeName("AFFINITY_CARD"); + m_dmeConn.saveObject("abnBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = //Build data specification + //Mining function settings name + //Mining model name + m_buildFactory.create("abnBuildData_jdm", "abnBuildSettings_jdm", + "abnModel_jdm"); + buildTask.setDescription("abnBuildTask_jdm"); + ((OraBuildTask) buildTask).setTransformationSequenceName("abnBuildDataXformSeq_jdm"); + saveTask(buildTask, "abnBuildTask_jdm", "abnXFormTask_jdm"); + } + + /** + * This method illustrates how to compute test metrics using + * an apply output table that has actual and predicted target values. Here the + * apply operation is done on ABN_BINNED_DATA_TEST_JDM dataset, which creates + * an apply output table with actual and predicted target values. Using + * ClassificationTestMetricsTask test metrics are computed. This produces + * the same test metrics results as ClassificationTestTask. + */ + public static void computeTestMetrics() + throws JDMException + { + // 1. Do the apply on test data to create an apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_TEST_V", false); + PhysicalAttribute pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("abnTestApplyData_jdm", applyData, true); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + HashMap srcDestMap = new HashMap(); + srcDestMap.put("AFFINITY_CARD", "AFFINITY_CARD"); + clasAS.setSourceDestinationMap(srcDestMap); + m_dmeConn.saveObject("abnTestApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("abnTestApplyData_jdm", "abnModel_jdm", + "abnTestApplySettings_jdm", + "ABN_TEST_APPLY_OUTPUT_JDM"); + saveTask(applyTask, "abnTestApplyTask_jdm", "abnBuildTask_jdm"); + // 4. Create & save PhysicalDataSpecification + PhysicalDataSet applyOutputData = + m_pdsFactory.create("ABN_TEST_APPLY_OUTPUT_JDM", false); + applyOutputData.addAttribute(pa); + m_dmeConn.saveObject("abnTestApplyOutput_jdm", applyOutputData, true); + // 5. Create a ClassificationTestMetricsTask + ClassificationTestMetricsTask testMetricsTask = + // apply output data used as input + // actual target column + // predicted target column + // test metrics result name + m_testMetricsTaskFactory.create("abnTestApplyOutput_jdm", + "AFFINITY_CARD", "PREDICTION", + "abnComputeTestMetrics_jdm"); // enable confusion matrix computation + testMetricsTask.computeMetric(ClassificationTestMetricOption.confusionMatrix, + true); // enable lift computation + testMetricsTask.computeMetric(ClassificationTestMetricOption.lift, + true); // enable ROC computation + testMetricsTask.computeMetric(ClassificationTestMetricOption.receiverOperatingCharacteristics, + true); + testMetricsTask.setPositiveTargetValue(new Integer(1)); + testMetricsTask.setNumberOfLiftQuantiles(10); + testMetricsTask.setPredictionRankingAttrName("PROBABILITY"); + // Save task and specify the parent task name + saveTask(testMetricsTask, "abnTestMetricsTask_jdm", + "abnTestApplyTask_jdm"); + } + + /** + * This method illustrates how to apply the mining model on the + * ABN_BINNED_DATA_APPLY_JDM dataset to predict customer + * response. After completion of the task, the apply output table with the + * predicted results is created at the user-specified location. + */ + public static void applyModel() + throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("abnApplyData_jdm", applyData, true); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject("abnApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("abnApplyData_jdm", "abnModel_jdm", + "abnApplySettings_jdm", + "ABN_APPLY_OUTPUT_JDM"); + saveTask(applyTask, "abnApplyTask_jdm", "abnBuildTask_jdm"); + } + + /** + * This method saves the given task with the specified task name and task + * dependency (parent task) in the DME. + * + * @param taskObj task object + * @param taskName name of the task + * @param parentTaskName name of the parent task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static void saveTask(Task taskObj, String taskName, + String parentTaskName) + throws JDMException + { + if (parentTaskName != null) + ((OraTask) taskObj).addDependency(parentTaskName); //Since OJDM 11.1 + ((OraTask) taskObj).overwriteOutput(true); //Since OJDM 11.1 + m_dmeConn.saveObject(taskName, taskObj, true); + } + + /** + * This method monitor task execution initiated by the first task + * in the sequence of dependent tasks. In addition, this method displays + * task output results (if any). + * @throws JDMException + */ + public static void monitorTaskExecutionProcess() + throws JDMException + { + //Data trasformation task + //1. Wait for the completion of the task + System.out.println("---------------------------------------------------"); + System.out.println("--- Prepare Data ---"); + System.out.println("---------------------------------------------------"); + System.out.print("Waiting for the completion of abnXFormTask_jdm. "); + ExecutionStatus xformTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("abnXFormTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(xformTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + //BuildTask + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of abnBuildTask_jdm. "); + ExecutionStatus buildTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("abnBuildTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(buildTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + // 3. Restore the model from the data mining server + ClassificationModel model = + (ClassificationModel) m_dmeConn.retrieveObject("abnModel_jdm", + NamedObject.model); + // 4. Explore the details of the restored model + // Display model build settings + ClassificationSettings retrievedBuildSettings = + (ClassificationSettings) model.getBuildSettings(); + if (retrievedBuildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, + "abnBuildSettings_jdm"); + // Display model details + OraABNModelDetail abnModelDetails = + (OraABNModelDetail) model.getModelDetail(); + displayABNModelDetails(abnModelDetails); + + // Display model transformations that are embedded in this example + OraExpressionTransform exprXforms = + ((OraModel) model).getModelTransformations(); + displayModelTransforms(exprXforms); + + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using apply output table ---"); + System.out.println("---------------------------------------------------"); + + //If model build is successful, then do testData ApplyTask + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of abnTestApplyTask_jdm. "); + ExecutionStatus testApplyTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("abnTestApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(testApplyTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + //If testdata apply is successful, then wait for its child test metrics tasks + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of abnTestMetricsTask_jdm. "); + ExecutionStatus testTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("abnTestMetricsTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(testTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + // Restore & display test metrics + ClassificationTestMetrics testMetrics = + (ClassificationTestMetrics) m_dmeConn.retrieveObject("abnComputeTestMetrics_jdm", + NamedObject.testMetrics); + // Display classification test metrics + displayTestMetricDetails(testMetrics); + } + else + { + System.out.println("It is at state:" + + testTaskCompletionStatus.getState().name() + + ((testTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + testTaskCompletionStatus.getDescription())); + } + + } + else + { + System.out.println("It is at state:" + + testApplyTaskCompletionStatus.getState().name() + + ((testApplyTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + testApplyTaskCompletionStatus.getDescription())); + } + //ApplyTask(s) + //Waiting for apply task to complete + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + + ExecutionStatus applyTaskStatus = + m_dmeConn.getLastExecutionHandle("abnApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + if (ExecutionState.success.equals(applyTaskStatus.getState())) + { + // Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + displayTable("ABN_APPLY_OUTPUT_JDM", "where ROWNUM < 11", + "order by CUST_ID"); + } + else + { + System.out.println("abnApplyTask_jdm is at state:" + + applyTaskStatus.getState().name() + + ((applyTaskStatus.getDescription() == null)? + "": + "State Description:" + applyTaskStatus.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + buildTaskCompletionStatus.getState().name() + + ((buildTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + buildTaskCompletionStatus.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + xformTaskCompletionStatus.getState().name() + + ((xformTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + xformTaskCompletionStatus.getDescription())); + } + } + + private static void displayBuildSettings(ClassificationSettings clasSettings, + String buildSettingsName) + { + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + System.out.println("BuildSettings Details from the " + + buildSettingsName + + " model build settings object:"); + String objName = clasSettings.getName(); + if (objName != null) + System.out.println("Name = " + objName); + String objDescription = clasSettings.getDescription(); + if (objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = clasSettings.getCreationDate(); + String creator = clasSettings.getCreatorInfo(); + String targetAttrName = clasSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = clasSettings.getAlgorithmSettings(); + if (algoSettings == null) + System.out.println("Failure: clasSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if (algo == null) + System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = clasSettings.getMiningFunction(); + if (function == null) + System.out.println("Failure: clasSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + try + { + Map map = clasSettings.getPriorProbabilitiesMap(targetAttrName); + if (map != null) + System.out.println("Priors Map: " + map.toString()); + } + catch (Exception jdmExp) + { + System.out.println("Failure: clasSettings.getPriorProbabilitiesMap(targetAttrName)throws exception"); + jdmExp.printStackTrace(); + } + } + + /** + * This method displayes ABN model signature. + */ + public static void displayModelSignature(Model model) + throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("ModelSignature Deatils: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = + new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[3]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while (attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute) attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println(mfSign.format(vals)); + } + } + + /** + * This method displayes ABN model details. + */ + public static void displayABNModelDetails(OraABNModelDetail abnModelDetails) + throws JDMException + { + System.out.println("ABN model details:"); + // Display all model rules + Collection vRules = abnModelDetails.getRules(); + if (vRules != null && vRules.isEmpty() == false) + { + Rule[] rules = (Rule[]) vRules.toArray(new Rule[vRules.size()]); + System.out.println(CR + CR + UNDERLINE); + System.out.println(RULES_ABN_HEADER); + System.out.println(UNDERLINE); + + for (int rl = 0; rl < rules.length; rl++) + { + printRuleDetails(rules[rl], 0); // printRuleDetails + } + } + System.out.println(CR + UNDERLINE + CR); + } + + /** + * This embedded transformations + */ + public static void displayModelTransforms(OraExpressionTransform exprXforms) + throws JDMException + { + System.out.println("ABN model transforms:"); + //Get per attribute name and expression element map object + Map exprMap = exprXforms.getAttributeExpressionMap(); + + OraExpressionTransform.OraExpressionElement exprElement = + (OraExpressionTransform.OraExpressionElement) exprMap.get("AGE"); + System.out.println("Attribute Name: AGE"); + System.out.println("Expression: " + exprElement.getExpression()); + System.out.println("Inverse Expression: " + exprElement.getInverseExpression()); + + exprElement = + (OraExpressionTransform.OraExpressionElement) exprMap.get("YRS_RESIDENCE"); + System.out.println("Attribute Name: YRS_RESIDENCE"); + System.out.println("Expression: " + exprElement.getExpression()); + System.out.println("Inverse Expression: " + exprElement.getInverseExpression()); + } + + + /** + * Prints rule details + */ + public static void printRuleDetails(Rule rule, int indent) + { + System.out.println(CR_TAB + getIndentation(indent, "Rule Details:") + + CR_TAB + TAB + + getIndentation(indent, "Support: " + m_df.format(rule.getSupport())) + + CR_TAB + TAB + + getIndentation(indent, "Confidence: " + + m_df.format(rule.getConfidence()))); + CompoundPredicate antecedent = + (CompoundPredicate) rule.getAntecedent(); + System.out.println(CR_TAB + TAB + + getIndentation(indent, ("Antecedent: "))); + printAntecedent(antecedent, indent); + CompoundPredicate consequent = + (CompoundPredicate) rule.getConsequent(); + System.out.println(CR_TAB + TAB + + getIndentation(indent, ("Consequent: "))); + printConsequent(consequent, indent); + } + + /** + * Prints antecedent + */ + public static void printAntecedent(CompoundPredicate predicate, + int indent) + { + try + { + SimplePredicate[] sps = + (SimplePredicate[]) predicate.getPredicates(); + if (sps == null) + return; + // Combine predicates by attribute name + Hashtable htNamePredicateMap = new Hashtable(); + for (int i = 0; i < sps.length; i++) + { + StringBuffer simplePredicate = printSimplePredicate(sps[i]); + String attrName = sps[i].getAttributeName(); + StringBuffer attrTotalPredicate = + (StringBuffer) htNamePredicateMap.get(attrName); + if (attrTotalPredicate == null) + htNamePredicateMap.put(attrName, simplePredicate); + else + { + attrTotalPredicate.append(" AND " + simplePredicate); + } + } + Enumeration en = htNamePredicateMap.keys(); + while (en.hasMoreElements()) + { + String name = (String) en.nextElement(); + StringBuffer sb = (StringBuffer) htNamePredicateMap.get(name); + System.out.println(getIndentation(indent, + (TAB + TAB + TAB + sb.toString()))); + } + } + catch (Exception e) + { + System.out.println("Error printing Antecedant"); + } + } + + /** + * Prints consequent + */ + public static void printConsequent(CompoundPredicate predicate, + int indent) + { + try + { + SimplePredicate[] sps = + (SimplePredicate[]) predicate.getPredicates(); + if (sps == null) + return; + for (int i = 0; i < sps.length; i++) + { + StringBuffer simplePredicate = printSimplePredicate(sps[i]); + if (i < sps.length - 1) + simplePredicate.append(" AND "); + System.out.println(getIndentation(indent, + TAB + TAB + TAB + simplePredicate.toString())); + } + } + catch (Exception e) + { + System.out.println("Error printing Consequent"); + } + } + + /** + * Prints simple predicate + */ + public static StringBuffer printSimplePredicate(SimplePredicate predicate) + throws JDMException + { + StringBuffer sb = new StringBuffer(); + if (predicate.isNumericalValue()) + { + //((OraSimplePredicate)predicate).getComparisonOperatorValue() + " " + + sb.append(predicate.getAttributeName() + " " + + ((OraSimplePredicate) predicate).getComparisonOperator().name() + + " " + predicate.getNumericalValue()); + } + else + { + //((OraSimplePredicate)predicate).getComparisonOperatorValue() + " " + sb = + new StringBuffer(predicate.getAttributeName() + " " + ((OraSimplePredicate) predicate).getComparisonOperator().name() + + " "); + Object[] inValues = predicate.getCategoryValues(); + if (inValues != null) + { + for (int i = 0; i < inValues.length; i++) + { + sb.append(inValues[i]); + if (i != inValues.length - 1) + sb.append(","); + } + } + } + return sb; + } + + /** + * Display classification test metrics object + */ + public static void displayTestMetricDetails(ClassificationTestMetrics testMetrics) + throws JDMException + { + // Retrieve Oracle ABN model test metrics deatils extensions + // Test Metrics Name + System.out.println("Test Metrics Name = " + testMetrics.getName()); + // Model Name + System.out.println("Model Name = " + testMetrics.getModelName()); + // Test Data Name + System.out.println("Test Data Name = " + + testMetrics.getTestDataName()); + // Accuracy + System.out.println("Accuracy = " + + m_df.format(testMetrics.getAccuracy().doubleValue())); + // Confusion Matrix + ConfusionMatrix confusionMatrix = testMetrics.getConfusionMatrix(); + Collection categories = confusionMatrix.getCategories(); + Iterator xIterator = categories.iterator(); + System.out.println("Confusion Matrix: Accuracy = " + + m_df.format(confusionMatrix.getAccuracy())); + System.out.println("Confusion Matrix: Error = " + + m_df.format(confusionMatrix.getError())); + System.out.println("Confusion Matrix:( Actual, Prection, Value )"); + MessageFormat mf = + new MessageFormat(" ( {0}, {1}, {2} )"); + String[] vals = new String[3]; + while (xIterator.hasNext()) + { + Object actual = xIterator.next(); + vals[0] = actual.toString(); + Iterator yIterator = categories.iterator(); + while (yIterator.hasNext()) + { + Object predicted = yIterator.next(); + vals[1] = predicted.toString(); + long number = + confusionMatrix.getNumberOfPredictions(actual, predicted); + vals[2] = Long.toString(number); + System.out.println(mf.format(vals)); + } + } + // Lift + Lift lift = testMetrics.getLift(); + System.out.println("Lift Details:"); + System.out.println("Lift: Target Attribute Name = " + + lift.getTargetAttributeName()); + System.out.println("Lift: Positive Target Value = " + + lift.getPositiveTargetValue()); + System.out.println("Lift: Total Cases = " + lift.getTotalCases()); + System.out.println("Lift: Total Positive Cases = " + + lift.getTotalPositiveCases()); + int numberOfQuantiles = lift.getNumberOfQuantiles(); + System.out.println("Lift: Number Of Quantiles = " + numberOfQuantiles); + System.out.println("Lift: ( QUANTILE_NUMBER, TOTAL_CASES, QUANTILE_PERCENT_SIZE, POSITIVE_CASES, NEGATIVE_CASES, PROBABILITY_THRESHOLD, LIFT, CUMULATIVE_LIFT, GAIN, CUMULATIVE_GAIN, TARGET_DENSITY, CUMULATIVE_TARGET_DENSITY)"); + MessageFormat mfLift = + new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10} )"); + double[] totalCasesPerQuantile = ((OraLift)lift).getCases();//Total cases per quantile + double[] quantilePercentageSize = ((OraLift)lift).getPercentageSize();//Quantile pecentage size + double[] positiveCasesPerQuantile = ((OraLift)lift).getNumberOfPositiveCases();//Positive target cases per quantile + double[] negativeCasesPerQuantile = ((OraLift)lift).getNumberOfNegativeCases();//Negative target cases per quantile + double[] probabilityOrCostThresholdPerQuantile = ((OraLift)lift).getProbabilityOrCostThreshold();//Probability or cost threshold per quantile + double[] liftPerQuantile = ((OraLift)lift).getLift();//Lift values for all quantiles + double[] targetDensityPerQuantile = ((OraLift)lift).getTargetDensity();//Target densities per quantile + + double[] cumulativeLift = ((OraLift)lift).getCumulativeLift(); + double[] cumulativeGain = ((OraLift)lift).getCumulativeGain(); + double[] cumulativeTargetDensity = ((OraLift)lift).getCumulativeTargetDensity(); + + + + String[] messageParams = new String[11]; + + for (int iQuantile = 0; iQuantile < numberOfQuantiles; iQuantile++) + { + //Assign message parameters + messageParams[0] = Integer.toString(iQuantile+1); //QUANTILE_NUMBER + messageParams[1] = m_df.format(totalCasesPerQuantile[iQuantile]); //TOTAL_CASES + messageParams[2] = m_df.format(quantilePercentageSize[iQuantile]);//QUANTILE_PERCENT_SIZE + messageParams[3] = m_df.format(positiveCasesPerQuantile[iQuantile]); //POSITIVE_CASES + messageParams[4] = m_df.format(negativeCasesPerQuantile[iQuantile]); //NEGATIVE_CASES + messageParams[5] = m_df.format(probabilityOrCostThresholdPerQuantile[iQuantile]); //PROBABILITY_THRESHOLD + messageParams[6] = m_df.format(liftPerQuantile[iQuantile]); //LIFT + messageParams[7] = m_df.format(cumulativeLift[iQuantile]); //CUMULATIVE_LIFT + messageParams[8] = m_df.format(cumulativeGain[iQuantile]); //CUMULATIVE_GAIN + messageParams[9] = m_df.format(targetDensityPerQuantile[iQuantile]); //TARGET_DENSITY + messageParams[10] = m_df.format(cumulativeTargetDensity[iQuantile]); //CUMULATIVE_TARGET_DENSITY + System.out.println(mfLift.format(messageParams)); + } + // ROC + ReceiverOperatingCharacterics roc = testMetrics.getROC(); + System.out.println("ROC Details:"); + System.out.println("ROC: Area Under Curve = " + + m_df.format(roc.getAreaUnderCurve())); + int nROCThresh = roc.getNumberOfThresholdCandidates(); + System.out.println("ROC: Number Of Threshold Candidates = " + + nROCThresh); + System.out.println("ROC: ( INDEX, PROBABILITY, TRUE_POSITIVES, FALSE_NEGATIVES, FALSE_POSITIVES, TRUE_NEGATIVES, TRUE_POSITIVE_FRACTION, FALSE_POSITIVE_FRACTION )"); + MessageFormat mfROC = + new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7} )"); + String[] rocVals = new String[8]; + for (int iROC = 1; iROC <= nROCThresh; iROC++) + { + rocVals[0] = Integer.toString(iROC); //INDEX + rocVals[1] = + m_df.format(roc.getProbabilityThreshold(iROC)); //PROBABILITY + rocVals[2] = + Long.toString(roc.getPositives(iROC, true)); //TRUE_POSITIVES + rocVals[3] = + Long.toString(roc.getNegatives(iROC, false)); //FALSE_NEGATIVES + rocVals[4] = + Long.toString(roc.getPositives(iROC, false)); //FALSE_POSITIVES + rocVals[5] = + Long.toString(roc.getNegatives(iROC, true)); //TRUE_NEGATIVES + rocVals[6] = + m_df.format(roc.getHitRate(iROC)); //TRUE_POSITIVE_FRACTION + rocVals[7] = + m_df.format(roc.getFalseAlarmRate(iROC)); //FALSE_POSITIVE_FRACTION + System.out.println(mfROC.format(rocVals)); + } + } + + private static String getIndentation(int indent, String sText) + { + StringBuffer sbIndent = new StringBuffer(TAB); + for (int in = 0; in < indent; in++) + sbIndent.append(TAB); + StringBuffer outPut = new StringBuffer(sbIndent.toString()); + outPut.append(sText); + return outPut.toString(); + } + + private static void displayTable(String tableName, String whereCause, + String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = + dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for (int iCol = 1; iCol <= colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while (rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for (int iCol = 1; iCol <= colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if (obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal) obj; + if (bd.scale() > 5) + { + colContent = m_df.format(obj); + } + else + { + colContent = bd.toString(); + } + } + catch (Exception anyExp) + { + colContent = m_df.format(obj); + } + } + else + { + if (obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" " + + emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } + catch (Exception anySqlExp) + { + anySqlExp.printStackTrace(); + } // Ignore + } + + private static void clean() + { + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + // Drop the model + try + { + m_dmeConn.removeObject("abnModel_jdm", NamedObject.model); + } + catch (JDMException jdmExp) + { + } + } +} diff --git a/dmabdemo.sql b/dmabdemo.sql new file mode 100644 index 0000000..310be10 --- /dev/null +++ b/dmabdemo.sql @@ -0,0 +1,712 @@ +Rem +Rem $Header: dmabdemo.sql 15-jun-2007.18:15:24 ramkrish Exp $ +Rem +Rem dmabdemo.sql +Rem +Rem Copyright (c) 2003, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmabdemo.sql - Sample program for DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a classification model +Rem using the ABN algorithm and data in the +Rem SH (Sales History) schema in the RDBMS. +Rem +Rem This sample demonstrates the backward compatibility of +Rem procedures for computing test metrics, apply, and ranked apply. +Rem Other samples demonstrate the use of the new SQL functions +Rem for data mining in Oracle10gR2. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem ktaylor 07/11/05 - minor editing of comments +Rem jcjeon 01/17/05 - add column format +Rem ramkrish 12/20/04 - add ORDER BY in missing values cursor +Rem jyarmus 11/01/04 - modify binning, ADD settings examples AS comments +Rem ramkrish 10/01/04 - add data analysis and comments/cleanup +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET linesize 100 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic data about a set of customers, predict the +-- customer response to an affinity card program using a classifier +-- based on ABN algorithm. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +-- The data for this sample is composed from base tables in SH Schema +-- (See Sample Schema Documentation) and presented through these views: +-- mining_data_build_v (build data) +-- mining_data_test_v (test data) +-- mining_data_apply_v (apply data) +-- (See dmsh.sql for view definitions). + +----------- +-- ANALYSIS +----------- +-- For classification using ABN, perform the following on mining data. +-- +-- 1. Missing Value Treatment for Predictors +-- +-- See dmsvcdem.sql for a definition of missing values, and the +-- steps to be taken for missing value imputation. +-- +-- ABN/NB treats NULL values for attributes as missing at random. +-- +-- 2. Outlier Treatment for Predictors for Build data +-- +-- See dmsvcdem.sql for a discussion on outlier treatment. +-- +-- ABN/NB (and Bayesian algorithms in general) require that high cardinality +-- data be binned. Studies have shown that equi-width binning into 10 bins +-- of data with no outliers provides good model performance. So if equiwidth +-- binning is considered, then outliers in the data have to be handled. +-- Not doing this would affect the bin boundaries such that data values +-- would tend to concentrate on too few bins. However .... +-- +-- 3. Binning high cardinality data +-- You can skip step 2 if the data is binned using quantile binning +-- (10 bins, for starters). ODM recommends quantile binning for NB +-- and ABN. +-- +-- eliminate old tables +BEGIN + EXECUTE IMMEDIATE 'DROP TABLE mining_data_build_hist'; +EXCEPTION WHEN OTHERS THEN + NULL; +END; +/ + +-- Gather histogram and cardinality for attributes as preparation for binning +-- +-- create table for column histogram +set echo off +CREATE GLOBAL TEMPORARY TABLE mining_data_build_hist ( + cname VARCHAR2(30), cnval NUMBER, csval VARCHAR2(30), vcnt NUMBER); + +DECLARE + cname VARCHAR2(30); + ctype VARCHAR2(30); + vstmt VARCHAR2(4000); + ccnt NUMBER; + CURSOR c1 IS + SELECT column_name,data_type + FROM all_tab_columns + WHERE table_name='MINING_DATA_BUILD_V' + ORDER BY column_name; +BEGIN + OPEN c1; + LOOP + FETCH c1 INTO cname,ctype; + EXIT WHEN c1%NOTFOUND; + + -- find cardinality + vstmt := 'SELECT COUNT(DISTINCT ' || cname || ') FROM mining_data_build_v'; + EXECUTE IMMEDIATE vstmt INTO ccnt; + DBMS_OUTPUT.PUT_LINE('Column: ' || cname || ', Card: ' || ccnt); + + -- find column histogram (skip case id) and store it in a temp table + IF (cname != 'CUST_ID') THEN + IF (ctype = 'NUMBER') THEN -- num column histogram + vstmt := + 'INSERT INTO mining_data_build_hist (cname, cnval, vcnt) ' || + 'SELECT ' || '''' || cname || '''' || ',' || cname || ',count(*) ' || + 'FROM mining_data_build_v GROUP BY ' || cname; + ELSIF (ctype = 'VARCHAR2') THEN -- str column histogram + vstmt := + 'INSERT INTO mining_data_build_hist (cname, csval, vcnt) ' || + 'SELECT ' || '''' || cname || '''' || ',' || cname || ',count(*) ' || + 'FROM mining_data_build_v GROUP BY ' || cname; + END IF; + EXECUTE IMMEDIATE vstmt; + END IF; + END LOOP; +END; +/ +set echo on + +-- Inspect COLUMN HISTOGRAMS +-- +column cname format a25; +column cval format a45; +SELECT cname, NVL(TO_CHAR(cnval), csval) cval, vcnt + FROM mining_data_build_hist +ORDER BY 1,2,3; + +-- . The target attribute is AFFINITY_CARD. CUST_ID is the case identifier. +-- The rest of the attributes are predictors. +-- . OCCUPATION has 15 distinct values, we decide to quantile bin it +-- into 7+1 bins. +-- . AGE has 66 distinct values in the range 17-80; we decide to quantile +-- bin it into 5+1 bins. +-- . All other attributes are categorical with binary values, so they +-- are not binned. + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup build data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_num'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW abn_sh_sample_build_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW abn_sh_sample_build_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +-- Cleanup old model with same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('ABN_SH_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- +-- 1. Missing Value treatment for all Predictors +-- Skipped - see dmnbdemo.sql +-- +-- 2. Outlier Treatment +-- Skipped - due to choice of quantile binning +-- +-- 3. Binning +-- +BEGIN + -- Bin categorical attributes: OCCUPATION + DBMS_DATA_MINING_TRANSFORM.CREATE_BIN_CAT ( + bin_table_name => 'abn_sh_sample_cat'); + + DBMS_DATA_MINING_TRANSFORM.INSERT_BIN_CAT_FREQ ( + bin_table_name => 'abn_sh_sample_cat', + data_table_name => 'mining_data_build_v', + bin_num => 7, + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'cust_gender', + 'cust_marital_status', + 'cust_income_level', + 'education', + 'household_size') + ); + + -- Bin numerical attributes: AGE + DBMS_DATA_MINING_TRANSFORM.CREATE_BIN_NUM ( + bin_table_name => 'abn_sh_sample_num'); + + DBMS_DATA_MINING_TRANSFORM.INSERT_BIN_NUM_QTILE ( + bin_table_name => 'abn_sh_sample_num', + data_table_name => 'mining_data_build_v', + bin_num => 5, + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'affinity_card', + 'bookkeeping_application', + 'bulk_pack_diskettes', + 'cust_id', + 'flat_panel_monitor', + 'home_theater_package', + 'os_doc_set_kanji', + 'printer_supplies', + 'y_box_games') + ); + + -- Create the transformed view + -- Execute the first transformation (categorical binning) + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_CAT ( + bin_table_name => 'abn_sh_sample_cat', + data_table_name => 'mining_data_build_v', + xform_view_name => 'abn_sh_sample_build_cat'); + + -- Provide the result (abn_sh_sample_build_cat) + -- to the next transformation (numerical binning) + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM ( + bin_table_name => 'abn_sh_sample_num', + data_table_name => 'abn_sh_sample_build_cat', + xform_view_name => 'abn_sh_sample_build_prepared'); +END; +/ + +-- BUILD DATA PREPARATION OBJECTS: +-- ------------------------------ +-- 1. Categorical Bin Table: abn_sh_sample_cat +-- 2. Numerical Bin Table: abn_sh_sample_num +-- 3. Input (view) to CREATE_MODEL: abn_sh_sample_build_prepared + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- CREATE AND POPULATE A PRIORS TABLE +-- +-- See dmnbdemo.sql - Classification using NB algorithm - for an example. + +-- NB is the default classifier. Override the default to ABN. +-- The default ABN model type is multi_feature. Override this +-- to single feature ABN (to demonstrate model details, since +-- get_model_details_abn() provides details only of single +-- feature ABN models. See Concepts Guide for distinction between +-- these models). +-- +-- CREATE AND POPULATE A SETTINGS TABLE +-- +set echo off +CREATE TABLE abn_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on + +BEGIN + -- Populate settings table + INSERT INTO abn_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.algo_name,dbms_data_mining.algo_adaptive_bayes_network); + INSERT INTO abn_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.abns_model_type,dbms_data_mining.abns_single_feature); + + -- Examples of other possible overrides are: + -- (dbms_data_mining.abns_max_build_minutes,10); + -- (dbms_data_mining.abns_max_nb_predictors,19); + -- (dbms_data_mining.abns_max_predictors,34); + -- (dbms_data_mining.abns_model_type, dbms_data_mining.abns_multi_feature); + -- (dbms_data_mining.abns_model_type, dbms_data_mining.abns_naive_bayes); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Build a new ABN model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'ABN_SH_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 'abn_sh_sample_build_prepared', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + settings_table_name => 'abn_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'ABN_SH_CLAS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'ABN_SH_CLAS_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- If the build data is prepared (as in this example), then the model +-- contains values of prepared data. The query shown below +-- reverse-transforms the model contents to be as close to the original +-- values as possible, based on the build data preparation objects. +-- Reporting the exact original value is impossible since the input +-- build data has already undergone some transformations (binning/ +-- normalization etc.) +-- +-- The SQL query presented below does the following. +-- 1. Use the bin boundary tables to create labels +-- 2. Replace attribute values with labels +-- 3. For numeric bins, the labels are "[/(lower_boundary,upper_boundary]/)" +-- 4. For categorical bins, label matches the value it represents +-- Note that this method of categorical label representation +-- will only work for cases where one value corresponds to one bin. +-- Target was not binned, hence we don't unbin the target. +-- +-- You can replace the model name in the query with your own, +-- and also adapt the query to accomodate other transforms. +-- +SET heading OFF +WITH +mod_dtls AS ( +SELECT * + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_ABN('abn_sh_clas_sample')) +), +bin_labels AS ( +SELECT col, bin, (DECODE(bin,'1','[','(') || lv || ',' || val || ']') label + FROM (SELECT col, + bin, + LAST_VALUE(val) OVER ( + PARTITION BY col ORDER BY val + ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) lv, + val + FROM abn_sh_sample_num) +UNION ALL +SELECT col, bin, val label + FROM abn_sh_sample_cat +), +mod_ante AS ( +SELECT R.rule_id, A.attribute_name Aa, A.conditional_operator Ac, + NVL(L.label, NVL(A.attribute_str_value,A.attribute_num_value)) + antecedent, + A.attribute_support antecedent_support, + A.attribute_confidence antecedent_confidence + FROM mod_dtls R, + TABLE(R.antecedent) A, + bin_labels L + WHERE A.attribute_name = L.col (+) AND + (NVL(A.attribute_str_value,A.attribute_num_value) = L.bin(+)) +), +mod_cons AS ( +SELECT R.rule_id, C.attribute_name Ca, C.conditional_operator Cc, + NVL(L.label, NVL(C.attribute_str_value,C.attribute_num_value)) + consequent, + C.attribute_support consequent_support, + C.attribute_confidence consequent_confidence + FROM mod_dtls R, + TABLE(R.consequent) C, + bin_labels L + WHERE C.attribute_name = L.col (+) AND + (NVL(C.attribute_str_value,C.attribute_num_value) = L.bin(+)) +), +model_details AS ( +SELECT R.rule_support, R.rule_id, + ante.Aa, ante.Ac, ante.antecedent, ante.antecedent_support, + ROUND(ante.antecedent_confidence,4) antecedent_confidence, + cons.Ca, cons.Cc, cons.consequent, cons.consequent_support, + ROUND(cons.consequent_confidence, 4) consequent_confidence + FROM mod_dtls R, + mod_ante ante, + mod_cons cons + WHERE R.rule_id = ante.rule_id AND ante.rule_id = cons.rule_id +ORDER BY R.rule_support DESC, + consequent_confidence DESC, cons.Ca, cons.consequent, + antecedent_confidence DESC, ante.Aa, ante.antecedent +) +SELECT 'Rule Support: ' || ROUND(rule_support, 4), +-- ' Rule Id: ' || rule_id , + ' Antecedent attribute: ' || Aa || ' ' || Ac || ' ' || antecedent, + ' Consequent attribute: ' || Ca || ' ' || Cc || ' ' || consequent, + ' Antecedent support: ' || antecedent_support, + ' Antecedent confidence: ' || antecedent_confidence, + ' Consequent support: ' || consequent_support, + ' Consequent confidence: ' || consequent_confidence + FROM model_details + WHERE ROWNUM < 21; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +-- Cleanup test data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP VIEW abn_sh_sample_test_targets'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW abn_sh_sample_test_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW abn_sh_sample_test_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------- +-- PREPARE TEST DATA +-- +-- If the data for model creation has been prepared, then the data used +-- for testing the model must be prepared to the same scale in order to +-- obtain meaningful results. +-- +-- 1. Missing value treatment - see dmsvcdem.sql for example of what +-- needs to be done with Test and Apply data input. +-- +-- 2. Outlier treatment and +-- 3. Binning +-- Quantile binning handles both the outlier treatment and binning in this case. +-- Transform the test data mining_test_v, using the transformation tables +-- generated during the Build data preparation, to generate a view representing +-- prepared test data. +-- +-- If this model is tested in a different schema or instance, the +-- data preparation objects generated in the CREATE step must also +-- be made available in the target schema/instance. So you must export +-- those objects (i.e. the num and cat bin tables and views) along with +-- the model to the target user schema. +-- +BEGIN + -- Execute the first transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_CAT ( + bin_table_name => 'abn_sh_sample_cat', + data_table_name => 'mining_data_test_v', + xform_view_name => 'abn_sh_sample_test_cat'); + + -- Provide the result to the next transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM ( + bin_table_name => 'abn_sh_sample_num', + data_table_name => 'abn_sh_sample_test_cat', + xform_view_name => 'abn_sh_sample_test_prepared'); +END; +/ + +-- Cleanup test result objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_test_apply'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_confusion_matrix'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_lift'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_roc'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +--------------------------------- +-- SPECIFY COST MATRIX (OPTIONAL) +-- +-- (See dmsvcdem.sql - SVM Classification - for example) +-- + +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- +-- The COMPUTE interfaces that provide the test results require two +-- data inputs: +-- 1. A table or view of targets - i.e. one that provides only the +-- case identifier and target columns of your test data. +-- 2. The table with the results of an APPLY operation on test data. +-- + +-- CREATE TEST TARGETS VIEW +-- +CREATE VIEW abn_sh_sample_test_targets AS +SELECT cust_id, affinity_card + FROM abn_sh_sample_test_prepared; + +-- APPLY MODEL ON TEST DATA +-- +BEGIN + DBMS_DATA_MINING.APPLY( + model_name => 'ABN_SH_Clas_sample', + data_table_name => 'abn_sh_sample_test_prepared', + case_id_column_name => 'cust_id', + result_table_name => 'abn_sh_sample_test_apply'); +END; +/ + +-- COMPUTE TEST METRICS +-- +DECLARE + v_accuracy NUMBER; + v_area_under_curve NUMBER; +BEGIN + DBMS_DATA_MINING.COMPUTE_CONFUSION_MATRIX ( + accuracy => v_accuracy, + apply_result_table_name => 'abn_sh_sample_test_apply', + target_table_name => 'abn_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + confusion_matrix_table_name => 'abn_sh_sample_confusion_matrix', + score_column_name => 'PREDICTION', + score_criterion_column_name => 'PROBABILITY'); + DBMS_OUTPUT.PUT_LINE('**** MODEL ACCURACY ****: ' || ROUND(v_accuracy, 4)); + + DBMS_DATA_MINING.COMPUTE_LIFT ( + apply_result_table_name => 'abn_sh_sample_test_apply', + target_table_name => 'abn_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + lift_table_name => 'abn_sh_sample_lift', + positive_target_value => '1', + num_quantiles => '10'); + + DBMS_DATA_MINING.COMPUTE_ROC ( + roc_area_under_curve => v_area_under_curve, + apply_result_table_name => 'abn_sh_sample_test_apply', + target_table_name => 'abn_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + roc_table_name => 'abn_sh_sample_roc', + positive_target_value => '1', + score_column_name => 'PREDICTION', + score_criterion_column_name => 'PROBABILITY'); + DBMS_OUTPUT.PUT_LINE('**** AREA UNDER ROC CURVE ****: ' || v_area_under_curve ); +END; +/ + +-- TEST RESULT OBJECTS: +-- ------------------- +-- 1. Confusion matrix Table: abn_sh_sample_confusion_matrix +-- 2. Lift Table: abn_sh_sample_lift +-- 3. ROC Table: abn_sh_sample_roc +-- + +-- +-- DISPLAY CONFUSION MATRIX +-- +-- NOTE: Cells with count 0 are not represented in the table +-- +SET heading ON +column predicted format a20; +SELECT actual_target_value actual, + to_char(predicted_target_value) predicted, + value as count + FROM abn_sh_sample_confusion_matrix +ORDER BY actual_target_value,predicted_target_value; + +-- DISPLAY LIFT RESULTS +-- +-- Uncomment the lines below to generate .csv for Lift charting using Excel +-- SET lines 32767 +-- SET pages 0 +-- SET colsep "," +-- SET feedback off +-- SET trimspool on +-- SPOOL dmabdemo.csv +SELECT quantile_number qtl, + lift_cumulative lcume, + percentage_records_cumulative prcume, + targets_cumulative tcume, + target_density_cumulative tdcume +-- Other info in Lift results +-- quantile_total_count, +-- target_density_cumulative, +-- non_targets_cumulative, +-- lift_quantile, +-- target_density + FROM abn_sh_sample_lift +ORDER BY quantile_number; +-- SPOOL OFF + +-- DISPLAY ROC - TOP 10 PROBABILITIES +-- +SELECT probability prob, + true_positives tp, + false_negatives fn, + false_positives fp, + true_negatives tn, + true_positive_fraction tpf, + false_positive_fraction fpf + FROM (SELECT * FROM abn_sh_sample_roc ORDER BY probability) + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- + +-- Cleanup scoring data preparation objects for repeat runs +-- +BEGIN EXECUTE IMMEDIATE 'DROP VIEW abn_sh_sample_apply_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW abn_sh_sample_apply_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +----------------------- +-- PREPARE SCORING DATA +-- +-- If the data for model creation has been prepared, then the data to be +-- scored using the model must be prepared to the same scale in order to +-- obtain meaningful results. +-- +-- 1. Missing value treatment - see dmsvcdem.sql for example of what +-- needs to be done with Test and Apply data input. +-- +-- 2. Outlier treatment and +-- 3. Binning +-- Quantile binning handles both the outlier treatment and binning in this case. +-- Transform the test data mining_test_v, using the transformation tables +-- generated during the Build data preparation, to generate a view representing +-- prepared test data. +-- +-- If this model is applied in a different schema or instance, the +-- data preparation objects generated in the CREATE step must also +-- be made available in the target schema/instance. So you must export +-- those objects (i.e. the num and cat bin tables and views) along with +-- the model to the target user schema. +-- +BEGIN + -- Execute the first transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_CAT ( + bin_table_name => 'abn_sh_sample_cat', + data_table_name => 'mining_data_apply_v', + xform_view_name => 'abn_sh_sample_apply_cat'); + + -- Provide the result to the next transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM ( + bin_table_name => 'abn_sh_sample_num', + data_table_name => 'abn_sh_sample_apply_cat', + xform_view_name => 'abn_sh_sample_apply_prepared'); +END; +/ + +-- Cleanup scoring result objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_apply_result'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------ +-- APPLY THE MODEL +-- +BEGIN + DBMS_DATA_MINING.APPLY( + model_name => 'ABN_SH_Clas_sample', + data_table_name => 'abn_sh_sample_apply_prepared', + case_id_column_name => 'cust_id', + result_table_name => 'abn_sh_sample_apply_result'); +END; +/ + +-- APPLY RESULT OBJECTS: abn_sh_sample_apply_result + +------------------------ +-- DISPLAY APPLY RESULTS +-- +-- 1. The results table contains a prediction set - i.e. ALL the predictions +-- for a given case id, with their corresponding probability values. +-- 2. In this example, note that APPLY results do not need to be reverse +-- transformed, as done in the case of model details. This is because +-- class values of a classification target were not (required to be) +-- binned or normalized. +-- 3. Only the first 10 rows of the table are displayed here. +-- +column prediction format a20 +column probability format 9.999999 +SELECT cust_id, TO_CHAR(prediction) AS prediction, probability + FROM (SELECT cust_id, prediction, ROUND(probability,4) probability + FROM abn_sh_sample_apply_result + ORDER BY cust_id, prediction, probability) + WHERE ROWNUM < 11 +ORDER BY cust_id; + +----------------------------------------------------------- +-- GENERATE RANKED APPLY RESULTS (OPTIONALLY BASED ON COST) +-- +-- See dmsvmcdem.sql - SVM Classification - for example +-- diff --git a/dmaidemo.java b/dmaidemo.java new file mode 100644 index 0000000..74ad523 --- /dev/null +++ b/dmaidemo.java @@ -0,0 +1,297 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmaidemo.java + +import java.text.DecimalFormat; +import java.text.MessageFormat; + +import java.util.Collection; +import java.util.Iterator; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.NamedObject; +import javax.datamining.SortOrder; +import javax.datamining.attributeimportance.AttributeImportanceModel; +import javax.datamining.attributeimportance.AttributeImportanceSettings; +import javax.datamining.attributeimportance.AttributeImportanceSettingsFactory; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.resource.Connection; +import javax.datamining.resource.ConnectionFactory; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; + +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.binning.OraBinningTransformFactory; + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to build an Attribute Importance (AI) model by using the Minimum Description +* Length (MDL) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Given a target attribute affinity_card, find the importance of independent +* attributes. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* See the corresponding section in dmabdemo.java - Classification using ABN. +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build an Attribute Importance model by using Minimum +* Description Length (MDL) algorithm with auto data preparation. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +public class dmaidemo + extends Object +{ + // Connection related data members + private static Connection m_dmeConn; + private static ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static AttributeImportanceSettingsFactory m_aiFactory; + private static BuildTaskFactory m_buildFactory; + private static OraBinningTransformFactory m_binningXformFactory; + private static OraTransformationTaskFactory m_xformTaskFactory; + // Provide schema name that has the data tables/views + private static String m_buildDataName = "MINING_DATA_BUILD_V"; + private static String m_idColName = "CUST_ID"; + private static String m_pdsName = "aiBuildData_jdm"; + private static String m_settingsName = "aiSettings_jdm"; + private static String m_modelName = "aiModel_jdm"; + private static String m_taskName = "aiBuildTask_jdm"; + private static String m_targetName = "AFFINITY_CARD"; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + + public static void main(String[] args) + { + try + { + if ((args.length != 0) & (args.length != 3)) + { + System.out.println("Usage: java dmaidemo "); + System.out.println(" or: java dmaidemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build a model + buildModel(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + //6. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + } //Ignore + } + } + + public static void initFactories() + throws JDMException + { + m_pdsFactory = + (PhysicalDataSetFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalDataSet"); + m_paFactory = + (PhysicalAttributeFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalAttribute"); + m_aiFactory = + (AttributeImportanceSettingsFactory) m_dmeConn.getFactory("javax.datamining.attributeimportance.AttributeImportanceSettings"); + m_buildFactory = + (BuildTaskFactory) m_dmeConn.getFactory("javax.datamining.task.BuildTask"); + m_binningXformFactory = + (OraBinningTransformFactory) m_dmeConn.getFactory("oracle.dmt.jdm.transform.binning.OraBinningTransform"); + m_xformTaskFactory = + (OraTransformationTaskFactory) m_dmeConn.getFactory("oracle.dmt.jdm.task.OraTransformationTask"); + } + + /** + * This method illustrates how to build attribute importance mining model + * using MINING_BUILD_DATA_V dataset and mining function settings. + */ + public static void buildModel() + throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create(m_buildDataName, false); + PhysicalAttribute pa = + m_paFactory.create(m_idColName, AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + buildData.addAttribute(pa); + m_dmeConn.saveObject(m_pdsName, buildData, false); + // 2. Create & save Mining Function Settings + // Create AttributeImportanceSettings + AttributeImportanceSettings buildSettings = m_aiFactory.create(); + buildSettings.setTargetAttributeName(m_targetName); + ((OraBuildSettings) buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject(m_settingsName, buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = // Build data specification + // Mining function settings name + // Mining model name + m_buildFactory.create(m_pdsName, m_settingsName, m_modelName); + buildTask.setDescription(m_taskName); + executeTask(buildTask, m_taskName); + // 4. Restore the model from the DME and explore the details of the model + AttributeImportanceModel model = + (AttributeImportanceModel) m_dmeConn.retrieveObject(m_modelName, + NamedObject.model); + // Display model details + displayAIModelDetails(model); + } + + /** + * This method stores the given task with the specified name in the DMS + * (Data Mining Server), + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints the error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException + { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = + execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if (isTaskSuccess) + { + //Task completed successfully + System.out.println(taskName + " is successful."); + } + else + { //Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription()); + } + return isTaskSuccess; + } + + /** + * This method displayes AI model details. + * */ + public static void displayAIModelDetails(AttributeImportanceModel model) + throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + // 1. Get spurious info from the model + System.out.println("Attribute Count:" + model.getAttributeCount()); + System.out.println("Max Rank:" + model.getMaxRank()); + // 2. List of attribute names ranked by their importance value. + // NOTE: The attributes that show negative importance values are not + // important attributes, similar to attributes with importance value of 0. + // From MDL principles, the negative importance value indicates that the + // given attribute simply adds to the size of the model - in this case, the + // list of attributes most relevant to the target - without adding any + // additional knowledge. + System.out.println("All attributes in descending order of their importance:"); + Collection attrColl = model.getAttributesByRank(SortOrder.descending); + displayAttributes(attrColl, model.getSignature()); + // 3. Get attributes by range (first top 5) + System.out.println("Top 5 attributes:"); + attrColl = model.getAttributesByRank(1, 5); + displayAttributes(attrColl, model.getSignature()); + // 4. Get attributes by percentage (bottom 20%) + System.out.println("Top 20% attributes:"); + attrColl = model.getAttributesByPercentage(20.0, SortOrder.descending); + displayAttributes(attrColl, model.getSignature()); + // 5. Get attributes by percentage (bottom 20%) + System.out.println("Bottom 20% attributes:"); + attrColl = model.getAttributesByPercentage(20.0, SortOrder.ascending); + displayAttributes(attrColl, model.getSignature()); + } + + private static void displayAttributes(Collection attrColl, + ModelSignature signature) + { + System.out.println("( Attribute Name, Importance, Rank )"); + MessageFormat mfSign = new MessageFormat("( {0}, {1}, {2} )"); + String[] vals = new String[3]; + Iterator attrI = attrColl.iterator(); + while (attrI.hasNext()) + { + try + { + vals[0] = (String) attrI.next(); + vals[1] = + m_df.format(signature.getAttribute(vals[0]).getImportanceValue()) + + ""; + vals[2] = + m_df.format(signature.getAttribute(vals[0]).getRank()) + ""; + } + catch (Exception e) + { + } + System.out.println(mfSign.format(vals)); + } + } + + private static void clean() + { + // Drop the model + try + { + m_dmeConn.removeObject(m_modelName, NamedObject.model); + } + catch (JDMException jdmExp) + { + } + } +} diff --git a/dmaidemo.sql b/dmaidemo.sql new file mode 100644 index 0000000..3e966ce --- /dev/null +++ b/dmaidemo.sql @@ -0,0 +1,184 @@ +Rem +Rem $Header: dmaidemo.sql 11-jul-2005.12:07:01 ktaylor Exp $ +Rem +Rem dmabdemo.sql +Rem +Rem Copyright (c) 2003, 2005, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmaidemo.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates an attribute importance model +Rem using the MDL algorithm +Rem and data in the SH (Sales History) schema in the RDBMS. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ktaylor 07/11/05 - minor edits to comments +Rem jcjeon 01/18/05 - add column format +Rem ramkrish 10/26/04 - add data analysis and comments/cleanup +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given a target attribute affinity_card, find the importance of +-- independent attributes. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +-- See the corresponding section in dmabdemo.sql - Classification +-- using ABN. The analysis and preparation steps are very similar. + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old build data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE ai_sh_sample_num'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE ai_sh_sample_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW ai_sh_sample_build_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW ai_sh_sample_build_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- +-- 1. Missing Value treatment for all Predictors +-- Skipped - see dmsvcdem.sql +-- +-- 2. Outlier Treatment +-- See notes in dmabdemo.sql and dmsvcdem.sql on outlier +-- treatment with equi-width binning. +-- Skipped - see dmsvcdem.sql for example. +-- +-- 3. Binning +-- +BEGIN + -- Bin categorical attributes: OCCUPATION + DBMS_DATA_MINING_TRANSFORM.CREATE_BIN_CAT ( + bin_table_name => 'ai_sh_sample_cat'); + + DBMS_DATA_MINING_TRANSFORM.INSERT_BIN_CAT_FREQ ( + bin_table_name => 'ai_sh_sample_cat', + data_table_name => 'mining_data_build_v', + bin_num => 7, + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'cust_gender', + 'cust_marital_status', + 'country_name', + 'cust_income_level', + 'education', + 'household_size') + ); + + -- Bin numerical attributes: AGE + DBMS_DATA_MINING_TRANSFORM.CREATE_BIN_NUM ( + bin_table_name => 'ai_sh_sample_num'); + + DBMS_DATA_MINING_TRANSFORM.INSERT_BIN_NUM_QTILE ( + bin_table_name => 'ai_sh_sample_num', + data_table_name => 'mining_data_build_v', + bin_num => 5, + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'affinity_card', + 'bookkeeping_application', + 'bulk_pack_diskettes', + 'cust_id', + 'flat_panel_monitor', + 'home_theater_package', + 'os_doc_set_kanji', + 'printer_supplies', + 'y_box_games', + 'yrs_residence') + ); + + -- Create the transformed view + -- Execute the first transformation (categorical binning) + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_CAT ( + bin_table_name => 'ai_sh_sample_cat', + data_table_name => 'mining_data_build_v', + xform_view_name => 'ai_sh_sample_build_cat'); + + -- Provide the result (ai_sh_sample_build_cat) + -- to the next transformation (numerical binning) + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM ( + bin_table_name => 'ai_sh_sample_num', + data_table_name => 'ai_sh_sample_build_cat', + xform_view_name => 'ai_sh_sample_build_prepared'); +END; +/ +-- BUILD DATA PREPARATION OBJECTS: +-- ------------------------------ +-- 1. Categorical Bin Table: ai_sh_sample_cat +-- 2. Numerical Bin Table: ai_sh_sample_num +-- 3. Input (view) to CREATE_MODEL: ai_sh_sample_build_prepared + +------------------- +-- SPECIFY SETTINGS +-- +-- There are no explicit settings for attribute importance. +-- +--------------------- +-- CREATE A NEW MODEL +-- +-- Cleanup old model with the same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('AI_SH_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Build a new AI model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'AI_SH_sample', + mining_function => DBMS_DATA_MINING.ATTRIBUTE_IMPORTANCE, + data_table_name => 'ai_sh_sample_build_prepared', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +-- Skip. This routine is not applicable for this function. + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +-- Skip. This routine is not applicable for this function. + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- list of attribute names ranked by their importance value. +-- +-- NOTE: The attributes that show negative importance values +-- are not important attributes, similar to attributes +-- with importance value of 0. From MDL principles, the +-- negative importance value indicates that the given +-- attribute simply adds to the size of the model - +-- in this case, the list of attributes most relevant +-- to the target - without adding any additional knowledge. +-- +column attribute_name format a40 +SELECT attribute_name, importance_value, rank + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_AI('AI_SH_sample')) +ORDER BY RANK; diff --git a/dmapplydemo.java b/dmapplydemo.java new file mode 100644 index 0000000..a12a5f6 --- /dev/null +++ b/dmapplydemo.java @@ -0,0 +1,743 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmapplydemo.java + +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.Statement; + +import java.text.DecimalFormat; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.NamedObject; +import javax.datamining.algorithm.naivebayes.NaiveBayesSettings; +import javax.datamining.algorithm.naivebayes.NaiveBayesSettingsFactory; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.CategoryProperty; +import javax.datamining.data.CategorySet; +import javax.datamining.data.CategorySetFactory; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataRecord; +import javax.datamining.data.PhysicalDataRecordFactory; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.classification.ClassificationApplyContent; +import javax.datamining.supervised.classification.ClassificationApplySettings; +import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.supervised.classification.ClassificationTestMetricsTaskFactory; +import javax.datamining.supervised.classification.ClassificationTestTaskFactory; +import javax.datamining.supervised.classification.CostMatrix; +import javax.datamining.supervised.classification.CostMatrixFactory; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; + +import javax.datamining.task.apply.RecordApplyTask; + +import javax.datamining.task.apply.RecordApplyTaskFactory; + +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; + + + +/** +* This sample program describes how to use the ODM Java API to build, test, +* and apply a classification model using the NaiveBayes(NB) algorithm. +* This program uses the "AP_BINNED_DATA_BUILD_JDM" prepared dataset for building +* a model to predict which customer would respond to a promotion campaign +* ("affinity_card"). It then tests the model by computing model accuracy, +* confusion matrix, and lift results using "AP_BINNED_DATA_TEST_JDM" prepared +* dataset. After testing the model, it applies the built model on the +* "AP_BINNED_DATA_APPLY_JDM" prepared dataset to predict which customers would +* respond to a promotion campaign. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +public class dmapplydemo + extends Object +{ + + //Connection related data members + private static javax.datamining.resource.Connection m_dmeConn = null; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory = + null; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory = null; + private static PhysicalAttributeFactory m_paFactory = null; + private static ClassificationSettingsFactory m_clasFactory = null; + private static NaiveBayesSettingsFactory m_nbFactory = null; + private static BuildTaskFactory m_buildFactory = null; + private static DataSetApplyTaskFactory m_dsApplyFactory = null; + private static ClassificationTestTaskFactory m_testFactory = null; + private static ClassificationApplySettingsFactory m_applySettingsFactory = null; + private static CostMatrixFactory m_costMatrixFactory = null; + private static CategorySetFactory m_catSetFactory = null; + private static ClassificationTestMetricsTaskFactory m_testMetricsTaskFactory = null; + private static RecordApplyTaskFactory m_recApplyFactory = null; + private static PhysicalDataRecordFactory m_pdrFactory = null; + private static ModelSignature m_modelSignature = null; + + public static void main(String[] args) + { + try + { + if ((args.length != 0) & (args.length != 3)) + { + System.out.println("Usage: java dmapplydemo "); + System.out.println(" or: java dmapplydemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build a model + buildModel(); + // 5. Create & save cost matrix + createCostMatrix(); + // 6. Run apply operations using + // various types of apply settings supported + defaultApply(); + + sourceDestinationMapApply(); + + mapByRankApply(); + + mapByCategoryApply(); + + mapTopPredictionApply(); + + //7. Start execution of the build task that trigger execution of + // its dependent apply tasks. + m_dmeConn.execute("apBuildTask_jdm"); + //8. Monitor the execution of the tasks in the server + monitorTaskExecutionProcess(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + //6. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + } //Ignore + } + } + + public static void initFactories() + throws JDMException + { + m_pdsFactory = + (PhysicalDataSetFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalDataSet"); + m_paFactory = + (PhysicalAttributeFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalAttribute"); + m_pdrFactory = (PhysicalDataRecordFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataRecord"); + m_clasFactory = + (ClassificationSettingsFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationSettings"); + m_nbFactory = + (NaiveBayesSettingsFactory) m_dmeConn.getFactory("javax.datamining.algorithm.naivebayes.NaiveBayesSettings"); + m_buildFactory = + (BuildTaskFactory) m_dmeConn.getFactory("javax.datamining.task.BuildTask"); + m_dsApplyFactory = + (DataSetApplyTaskFactory) m_dmeConn.getFactory("javax.datamining.task.apply.DataSetApplyTask"); + m_recApplyFactory = (RecordApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.RecordApplyTask"); + m_testFactory = + (ClassificationTestTaskFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationTestTask"); + m_applySettingsFactory = + (ClassificationApplySettingsFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationApplySettings"); + m_costMatrixFactory = + (CostMatrixFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.CostMatrix"); + m_catSetFactory = + (CategorySetFactory) m_dmeConn.getFactory("javax.datamining.data.CategorySet"); + m_testMetricsTaskFactory = + (ClassificationTestMetricsTaskFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationTestMetricsTask"); + } + + /** + * This method builds a mining model. The build operation requires the training + * dataset location details and the mining function setting. + * In this example, we will build a classification model using the prepared + * build dataset "AP_BINNED_DATA_BUILD_JDM" in the user schema, with the + * NaiveBayes algorithm. This model can be used to predict which customer + * would respond to a promotion campaign. After completing the build task, the + * model named "apModel_jdm" will be created in the DMS. + */ + public static void buildModel() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + buildData.addAttribute(pa); + m_dmeConn.saveObject("apBuildData_jdm", buildData, true); + //2. Create & save Mining Function Settings + //Create NB algorithm settings + NaiveBayesSettings nbAlgo = m_nbFactory.create(); + nbAlgo.setPairwiseThreshold(0.01f); + nbAlgo.setSingletonThreshold(0.01f); + //Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(nbAlgo); + buildSettings.setTargetAttributeName("affinity_card"); + ((OraBuildSettings) buildSettings).useAutomatedDataPreparations(true); + //Set target prior probabilities + Map priorMap = new HashMap(); + priorMap.put(new Double(0), new Double(0.7)); + priorMap.put(new Double(1), new Double(0.3)); + buildSettings.setPriorProbabilitiesMap("affinity_card", priorMap); + m_dmeConn.saveObject("apBuildSettings_jdm", buildSettings, true); + //3. Create, save & execute Build Task + BuildTask buildTask = //Build data specification + //Mining function settings name + //Mining model name + m_buildFactory.create("apBuildData_jdm", "apBuildSettings_jdm", + "apModel_jdm"); + buildTask.setDescription("apBuildTask_jdm"); + saveTask(buildTask, "apBuildTask_jdm", null); + } + + /** + * This method applies a mining model to a dataset. The apply dataset location + * details, input model, and the output table location details are required + * for this operation. + * In this example, we apply the "apModel_jdm" to the + * "AP_BINNED_DATA_APPLY_JDM" prepared dataset to predict which customers + * receive an "affinity_card". After completing the apply task, an apply + * output table "ap_def_apply_output_jdm" will be created in the DMS. + */ + public static void defaultApply() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("ap_def_ApplyData_jdm", applyData, true); + //2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject("ap_def_ApplySettings_jdm", clasAS, true); + + //3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("ap_def_ApplyData_jdm", "apModel_jdm", + "ap_def_ApplySettings_jdm", + "ap_def_apply_output_jdm"); + saveTask(applyTask, "ap_def_ApplyTask_jdm", "apBuildTask_jdm"); + } + + /** + * This method applies a mining model to a dataset. The apply dataset location + * details, input model and the output table location details are required + * for this operation. + * In this example, we apply the "apModel_jdm" to the + * "AP_BINNED_DATA_APPLY_JDM" prepared dataset to predict which customers + * receive an "affinity_card". After completing the apply task, an apply + * output table "ap_src_apply_output_jdm" will be created in the DMS. + */ + public static void sourceDestinationMapApply() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("ap_src_ApplyData_jdm", applyData, true); + //2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + //2.1 Create a Map of attributes to be included in the output dataset + Map srcDestMap = new HashMap(); + srcDestMap.put("AGE", "AGE_IN_YRS"); + srcDestMap.put("CUST_INCOME_LEVEL", "CUST_INCOME_LEVEL_IN_$"); + srcDestMap.put("OCCUPATION", "OCCUPATION_AS"); + clasAS.setSourceDestinationMap(srcDestMap); + m_dmeConn.saveObject("ap_src_ApplySettings_jdm", clasAS, true); + //3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("ap_src_ApplyData_jdm", "apModel_jdm", + "ap_src_ApplySettings_jdm", + "ap_src_apply_output_jdm"); + saveTask(applyTask, "ap_src_ApplyTask_jdm", "apBuildTask_jdm"); + } + + /** + * This method applies a mining model to a dataset. The apply dataset location + * details, input model, and the output table location details are required + * for this operation. + * In this example, we apply the "apModel_jdm" to the + * "AP_BINNED_DATA_APPLY_JDM" prepared dataset to predict which customers + * receive an "affinity_card". After completing the apply task, an apply + * output table "ap_apply_output" will be created in the DMS. + */ + public static void mapByRankApply() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("ap_rk_ApplyData_jdm", applyData, true); + //2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + String[] predCategories = new String[] + { "Top_1_Category" }; + clasAS.mapByRank(ClassificationApplyContent.predictedCategory, + predCategories, true); + m_dmeConn.saveObject("ap_rk_ApplySettings_jdm", clasAS, true); + + //3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("ap_rk_ApplyData_jdm", "apModel_jdm", + "ap_rk_ApplySettings_jdm", + "ap_rk_apply_output_jdm"); + saveTask(applyTask, "ap_rk_ApplyTask_jdm", "apBuildTask_jdm"); + } + + /** + * This method applies a mining model to a dataset. The apply dataset location + * details, input model, and the output table location details are required + * for this operation. + * In this example, we apply the "apModel_jdm" to the + * "AP_BINNED_DATA_APPLY_JDM" prepared dataset to predict which customers + * receive an "affinity_card". After completing the apply task, an apply + * output table "ap_cls_apply_output_jdm" will be created in the DMS. + */ + public static void mapByCategoryApply() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("ap_cls_ApplyData_jdm", applyData, true); + //2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + clasAS.mapByCategory(ClassificationApplyContent.probability, + new Integer(0), "NotResponds"); + clasAS.mapByCategory(ClassificationApplyContent.probability, + new Integer(1), "Responds"); + m_dmeConn.saveObject("ap_cls_ApplySettings_jdm", clasAS, true); + //3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("ap_cls_ApplyData_jdm", "apModel_jdm", + "ap_cls_ApplySettings_jdm", + "ap_cls_apply_output_jdm"); + saveTask(applyTask, "ap_cls_ApplyTask_jdm", "apBuildTask_jdm"); + + } + + /** + * This method applies a mining model to a dataset. The apply dataset location + * details, input model, and the output table location details are required + * for this operation. + * In this example, we apply the "apModel_jdm" to the + * "AP_BINNED_DATA_APPLY_JDM" prepared dataset to predict which customers + * receive an "affinity_card". After completing the apply task, an apply + * output table "ap_top_apply_output_jdm" will be created in the DMS. + */ + public static void mapTopPredictionApply() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("ap_top_ApplyData_jdm", applyData, true); + //2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + clasAS.mapTopPrediction(ClassificationApplyContent.predictedCategory, + "Responds"); + clasAS.mapTopPrediction(ClassificationApplyContent.probability, + "Probability"); + m_dmeConn.saveObject("ap_top_ApplySettings_jdm", clasAS, true); + //3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("ap_top_ApplyData_jdm", "apModel_jdm", + "ap_top_ApplySettings_jdm", + "ap_top_apply_output_jdm"); + saveTask(applyTask, "ap_top_ApplyTask_jdm", "apBuildTask_jdm"); + + } + + /** + * This method applies a mining model to a single record. + */ + public static void recordApply(ModelSignature modelSignature) throws JDMException + { + //1. Create a PhysicalDataRecord that contains an model signature attributes + PhysicalDataRecord applyInputRecord = m_pdrFactory.create(modelSignature); + //2. Specify attribute record values + applyInputRecord.setValue("AGE", "62"); + applyInputRecord.setValue("BOOKKEEPING_APPLICATION", new Integer(1)); + applyInputRecord.setValue("CUST_GENDER","F"); + applyInputRecord.setValue("CUST_MARITAL_STATUS","Widowed"); + applyInputRecord.setValue("EDUCATION","< Bach."); + applyInputRecord.setValue("HOME_THEATER_PACKAGE", new Integer(1)); + applyInputRecord.setValue("HOUSEHOLD_SIZE", new Integer(2)); + applyInputRecord.setValue("OCCUPATION","Exec."); + applyInputRecord.setValue("YRS_RESIDENCE",new Integer(3)); + applyInputRecord.setValue("Y_BOX_GAMES",new Integer(0)); + //3. Create and save ClassificationApplySettings object + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + clasAS.mapTopPrediction(ClassificationApplyContent.predictedCategory, "Responds"); + clasAS.mapTopPrediction(ClassificationApplyContent.probability, "Probability"); + m_dmeConn.saveObject( "ap_rec_ApplySettings_jdm", clasAS, true); + //4. Create and execute RecordApplyTask + RecordApplyTask applyTask = m_recApplyFactory.create(applyInputRecord, + "apModel_jdm", "ap_rec_ApplySettings_jdm"); + ExecutionStatus recExecStatus = m_dmeConn.execute(applyTask, null); + //5. Check the status of the task after completion + boolean isTaskSuccess = recExecStatus.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println("RecordApplyTask is successful."); + } else {//Task failed + System.out.println("RecordApplyTask is failed.\nFailure Description: " + + recExecStatus.getDescription() ); + } + //6. Display prediction for this record + PhysicalDataRecord applyOutputRecord = applyTask.getOutputRecord(); + Number customerResponds = (Number)applyOutputRecord.getValue("RESPONDS"); + String respondsStr = (customerResponds.intValue() == 0)?"do not responds":"responds"; + Number customerRespondsProbability = (Number)applyOutputRecord.getValue("PROBABILITY"); + System.out.println("This customer " + respondsStr + " to the affinity card promotion with probability " + customerRespondsProbability.toString()); + } + + /** + * This method saves the given task with the specified task name and task + * dependency (parent task) in the DME. + * + * @param taskObj task object + * @param taskName name of the task + * @param parentTaskName name of the parent task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static void saveTask(Task taskObj, String taskName, + String parentTaskName) + throws JDMException + { + if (parentTaskName != null) + ((OraTask) taskObj).addDependency(parentTaskName); //Since OJDM 11.1 + ((OraTask) taskObj).overwriteOutput(true); //Since OJDM 11.1 + m_dmeConn.saveObject(taskName, taskObj, true); + } + + + //create and save cost matrix + + private static void createCostMatrix() + throws JDMException + { + //create categorySet + CategorySet catSet = + m_catSetFactory.create(AttributeDataType.integerType); + //Add category values + catSet.addCategory(new Integer(0), CategoryProperty.valid); + catSet.addCategory(new Integer(1), CategoryProperty.valid); + //create cost matrix + CostMatrix costMatrix = m_costMatrixFactory.create(catSet); + costMatrix.setCellValue(new Integer(0), new Integer(0), 0); + costMatrix.setCellValue(new Integer(1), new Integer(1), 0); + costMatrix.setCellValue(new Integer(0), new Integer(1), 2); + costMatrix.setCellValue(new Integer(1), new Integer(0), 4); + //save cost matrix + m_dmeConn.saveObject("apCostMatrix", costMatrix, true); + } + + /** + * This method monitor task execution initiated by the first task + * in the sequence of dependent tasks. In addition, this method displays + * task output results (if any). + * @throws JDMException + */ + public static void monitorTaskExecutionProcess() + throws JDMException + { + //1. Monitor BuildTask + //Wait for the completion of the task + System.out.print("Waiting for the completion of apBuildTask_jdm. "); + ExecutionStatus buildTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("apBuildTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(buildTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + ClassificationModel model = + (ClassificationModel)m_dmeConn.retrieveObject( + "apModel_jdm", NamedObject.model); + m_modelSignature = model.getSignature(); + recordApply(m_modelSignature); + //2. Monitor default settings applyTask + //Wait for the completion of the task + { + System.out.print("Waiting for the completion of ap_def_ApplyTask_jdm. "); + ExecutionStatus defaultApplySettingsTaskStatus = + m_dmeConn.getLastExecutionHandle("ap_def_ApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(defaultApplySettingsTaskStatus.getState())) + { + System.out.println("It is successful. "); + displayApplyResults("ap_def_apply_output_jdm", + "cust_id, prediction"); + } + else + { + System.out.println("It is at state:" + + defaultApplySettingsTaskStatus.getState().name() + + ((defaultApplySettingsTaskStatus.getDescription() == + null)? "": + "State Description:" + defaultApplySettingsTaskStatus.getDescription())); + } + } + + //3. Monitor source destination settings applyTask + //Wait for the completion of the task + { + System.out.print("Waiting for the completion of ap_src_ApplyTask_jdm. "); + ExecutionStatus sourceDestinationMappingApplyTaskStatus = + m_dmeConn.getLastExecutionHandle("ap_src_ApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(sourceDestinationMappingApplyTaskStatus.getState())) + { + System.out.println("It is successful. "); + displayApplyResults("ap_src_apply_output_jdm", + "cust_id, prediction"); + } + else + { + System.out.println("It is at state:" + + sourceDestinationMappingApplyTaskStatus.getState().name() + + ((sourceDestinationMappingApplyTaskStatus.getDescription() == + null)? "": + "State Description:" + sourceDestinationMappingApplyTaskStatus.getDescription())); + } + } + + //4. Monitor rank applyTask + //Wait for the completion of the task + { + System.out.print("Waiting for the completion of ap_rk_ApplyTask_jdm. "); + ExecutionStatus rankApplyTaskStatus = + m_dmeConn.getLastExecutionHandle("ap_rk_ApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(rankApplyTaskStatus.getState())) + { + System.out.println("It is successful. "); + displayApplyResults("ap_rk_apply_output_jdm", + "cust_id, prediction"); + } + else + { + System.out.println("It is at state:" + + rankApplyTaskStatus.getState().name() + + ((rankApplyTaskStatus.getDescription() == + null)? "": + "State Description:" + rankApplyTaskStatus.getDescription())); + } + } + + //5. Monitor rank applyTask + //Wait for the completion of the task + { + System.out.print("Waiting for the completion of ap_cls_ApplyTask_jdm. "); + ExecutionStatus classApplyTaskStatus = + m_dmeConn.getLastExecutionHandle("ap_cls_ApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(classApplyTaskStatus.getState())) + { + System.out.println("It is successful. "); + displayApplyResults("ap_cls_apply_output_jdm", + "cust_id, notresponds, responds"); + } + else + { + System.out.println("It is at state:" + + classApplyTaskStatus.getState().name() + + ((classApplyTaskStatus.getDescription() == + null)? "": + "State Description:" + classApplyTaskStatus.getDescription())); + } + } + + //6. Monitor top-prediction applyTask + //Wait for the completion of the task + { + System.out.print("Waiting for the completion of ap_top_ApplyTask_jdm. "); + ExecutionStatus topPredApplyTaskStatus = + m_dmeConn.getLastExecutionHandle("ap_top_ApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(topPredApplyTaskStatus.getState())) + { + System.out.println("It is successful. "); + displayApplyResults("ap_top_apply_output_jdm", + "cust_id, prediction"); + } + else + { + System.out.println("It is at state:" + + topPredApplyTaskStatus.getState().name() + + ((topPredApplyTaskStatus.getDescription() == + null)? "": + "State Description:" + topPredApplyTaskStatus.getDescription())); + } + } + } + else + { + System.out.println("It is at state:" + + buildTaskCompletionStatus.getState().name() + + ((buildTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + buildTaskCompletionStatus.getDescription())); + } + } + + public static void displayApplyResults(String applyTableName, + String orderBy) + { + StringBuffer emptyCol = new StringBuffer(" "); + + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = + dbConn.prepareStatement("SELECT * FROM " + applyTableName + " WHERE ROWNUM<10 ORDER BY " + + orderBy); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + applyTableName); + //Build table header + for (int iCol = 1; iCol <= colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + //Write table data + while (rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for (int iCol = 1; iCol <= colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + DecimalFormat df = new DecimalFormat("00000000.##E0"); + if (obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal) obj; + if (bd.scale() > 5) + { + colContent = df.format(obj); + } + else + { + colContent = bd.toString(); + } + } + catch (Exception anyExp) + { + colContent = df.format(obj); + } + } + else + { + colContent = obj.toString(); + } + + rowContent.append(emptyCol.replace(0, colContent.length(), + colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } + catch (Exception anySqlExp) + { + anySqlExp.printStackTrace(); + } //Ignore + } + + private static void clean() + { + //Drop the model + try + { + m_dmeConn.removeObject("apModel_jdm", NamedObject.model); + } + catch (Exception jdmExp) + { + } + + + } +} diff --git a/dmardemo.java b/dmardemo.java new file mode 100644 index 0000000..5a8dc32 --- /dev/null +++ b/dmardemo.java @@ -0,0 +1,793 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmardemo.java +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; + +import java.sql.SQLException; + +import java.sql.Statement; + +import java.text.DecimalFormat; + +import java.util.Collection; + +import java.util.Iterator; + +import java.util.TreeSet; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.SortOrder; +import javax.datamining.association.AssociationModel; +import javax.datamining.association.AssociationSettings; +import javax.datamining.association.AssociationSettingsFactory; +import javax.datamining.association.Itemset; +import javax.datamining.association.RuleProperty; +import javax.datamining.association.RulesFilterFactory; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.resource.Connection; +import javax.datamining.resource.ConnectionFactory; +import javax.datamining.resource.ConnectionSpec; + +import javax.datamining.task.BuildTask; + +import javax.datamining.task.BuildTaskFactory; + +import oracle.dmt.jdm.association.OraAssociationRule; +import oracle.dmt.jdm.association.OraItemset; +import oracle.dmt.jdm.association.OraRulesFilter; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to build an Association model by using Apriori (AR) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Find the associations between items bought by customers. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from a small subset of sales transactions +* from base tables in the Sales History (SH) Schema. The SH schema is an Oracle Database +* Sample Schema that has customer demographics, purchasing, and +* response details for the previous affinity card programs. Data +* exploration and preparing the data is a common step before doing data mining. +* Here in this demo, the following views are created in the user schema using +* SALES and PRODUCT tables. +* +* SALES_TRANS_CUST_V: +* This view collects the previous customers' purchasing details for building the +* model. This view will contain purchasing details for customers who have a +* cust_id between 100001 AND 104500. +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* 1. Common item removal: common items are candidates for removal during model +* build, because if a majority of customers have bought those items, the +* resulting rules do not have much value. Since the dataset is small, we will +* skip common item removal. +* +* 2. Data format transformation: market basket or sales datasets are +* transactional in nature, and form dimension tables in a typical DW. We +* present such transactional data to the API using an Object View that +* contains a nested table column holding a collection of items that correspond +* to a given case id. +* +* 3. Binning transformation: it is used to reduce the cardinality of higher +* cardinality attributes. The prepareData() method in this demo program +* illustrates the preparation of the build data. We skip binning +* transformation in this demo. See dmabdemo.java for an example of quantile +* binning. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build an Association model by using the Apriori algorithm. +* +* Test Model: +* Association rules do not have a predefined test metric. Two indirect +* measures of modeling success are: +* +* 1. Number of Rules generated: The optimal number of rules is application +* dependent. In general, an overwhelming number of rules is undesirable for +* user interpretation. More rules take longer to compute, and also consume +* storage and CPU cycles. You should avoid too many rules by increasing the +* value for support. +* +* 2. Relevance of rules: This can be determined only by +* user inspection of rules, since it is application dependent. Ideally, we +* want to find rules with high confidence and with non-obvious patterns. The +* value for confidence is an indicator of the strength of the rule - so you +* could set the confidence value high in conjunction with support and see if +* you get high quality rules. +* +* 3. Frequent itemsets provide an insight into co-occurrence of items. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic Java api imports +// Java Data Mining (JDM) standard api imports +// Oracle Java Data Mining (JDM) implemented api imports +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to build an Association model by using Apriori (AR) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Find the associations between items bought by customers. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from a small subset of sales transactions +* from base tables in the Sales History (SH) Schema. The SH schema is an Oracle Database +* Sample Schema that has customer demographics, purchasing, and +* response details for the previous affinity card programs. Data +* exploration and preparing the data is a common step before doing data mining. +* Here in this demo, the following views are created in the user schema using +* SALES and PRODUCT tables. +* +* SALES_TRANS_CUST_V: +* This view collects the previous customers' purchasing details for building the +* model. This view will contain purchasing details for customers who have a +* cust_id between 100001 AND 104500. +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Create input view: +* In this demo we illustrate creation of a nested table based view, that +* has sales transaction data as a nested structure for each customer. This +* view is used as input for AR model build. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build an Association model by using the Apriori algorithm. +* +* Test Model: +* Association rules do not have a predefined test metric. Two indirect +* measures of modeling success are: +* +* 1. Number of Rules generated: The optimal number of rules is application +* dependent. In general, an overwhelming number of rules is undesirable for +* user interpretation. More rules take longer to compute, and also consume +* storage and CPU cycles. You should avoid too many rules by increasing the +* value for support. +* +* 2. Relevance of rules: This can be determined only by +* user inspection of rules, since it is application dependent. Ideally, we +* want to find rules with high confidence and with non-obvious patterns. The +* value for confidence is an indicator of the strength of the rule - so you +* could set the confidence value high in conjunction with support and see if +* you get high quality rules. +* +* 3. Frequent itemsets provide an insight into co-occurrence of items. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +public class + +dmardemo + extends Object +{ + //Connection related data members + private static Connection m_dmeConn; + private static ConnectionFactory m_dmeConnFactory; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static AssociationSettingsFactory m_assoFactory; + private static RulesFilterFactory m_filterFactory; + private static BuildTaskFactory m_buildFactory; + private static String m_pdsName = "arBuildData_jdm"; + private static String m_settingsName = "arSettings_jdm"; + private static String m_modelName = "arModel_jdm"; + private static String m_taskName = "arBuildTask_jdm"; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + // Default settings + private static int m_maxRuleLength = 20; + private static double m_minSupport = 0.1; + private static double m_minConfidence = 0.1; + + public static void main(String[] args) + { + try + { + if ((args.length != 0) & (args.length != 3)) + { + System.out.println("Usage: java dmardemo "); + System.out.println(" or: java dmardemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Create input view + createInputView(); + // 5. Build a model + buildModel(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + //6. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + } //Ignore + } + } + + public static void initFactories() + throws JDMException + { + m_pdsFactory = + (PhysicalDataSetFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalDataSet"); + m_paFactory = + (PhysicalAttributeFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalAttribute"); + m_assoFactory = + (AssociationSettingsFactory) m_dmeConn.getFactory("javax.datamining.association.AssociationSettings"); + m_buildFactory = + (BuildTaskFactory) m_dmeConn.getFactory("javax.datamining.task.BuildTask"); + m_filterFactory = + (RulesFilterFactory) m_dmeConn.getFactory("javax.datamining.association.RulesFilter"); + } + + /** + * This method illustrates preparation of the data for build operations by + * using Common item removal, Data format transformation, and binning + * transformations. + * + * Transformations: + * 1. Common item removal: Skipped since the dataset is small. + * + * 2. Column format transformation: Converted a table column into a nested + * table column format, so each record contains a nested table column + * holding a collection of items that correspond to a given customer id. + * + * The following table illustrates customer attributes available for building + * the mining model and data characteristics. + * + * COLUMN_NAME DATA_TYPE DISTINCT NUMBER OF ROWS + * ------------------ --------- -------- -------------- + * CUST_ID NUMBER 940 2804 + * PROD_NAME VARCHAR2(50) 14 2804 + * HAS_IT NUMBER 1 2804 + * + * Unprepared Data ---> Prepared(nested table column) Data + * -------------------- ---------------------------------- + * SALES_TRANS_CUST_V SALES_TRANS_CUST_AR_V + */ + public static void createInputView() + throws JDMException + { + System.out.println("--- Create AR model build input view 'SALES_TRANS_CUST_V' ---"); + boolean isOutputAsView = false; + String inputDataURI = null; + String outputDataURI = null; + + // 1. Create the database view in a transactional format + // that joins customers sales transactions table SH.SALES + // with the products table SH.PRODUCTS that contains + // the product name. In this example 4500 customers transactions + // are taken as input. + isOutputAsView = true; + inputDataURI = "SH.SALES a, SH.PRODUCTS b"; + outputDataURI = "SALES_TRANS_CUST_V"; + String createView = + "CREATE VIEW SALES_TRANS_CUST_V AS " + " SELECT cust_id, prod_name, 1 has_it " + + " FROM (SELECT a.cust_id, b.prod_name " + + " FROM SH.SALES a, SH.PRODUCTS b " + + " WHERE a.prod_id = b.prod_id AND " + + " a.cust_id between 100001 AND 104500) " + + " GROUP BY cust_id, prod_name "; + + // Execute the sql statement + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + try + { + pStmt = dbConn.prepareStatement(createView); + pStmt.executeQuery(); + } + catch (Exception anySqlExp) + { + anySqlExp.printStackTrace(); // Ignore + } + finally + { + try + { + pStmt.close(); + } + catch (Exception ex) + { + } + ; // Ignore + } + + // 2. Convert the transactional view created in the previous step + // "SALES_TRANS_CUST_V" to a nested table based view that + // represents the transactions by a customer is stored as a + // nested table, in this new view there will be one record per + // customer in the main view and this record contains the + // products purchased as a nested view + isOutputAsView = true; + inputDataURI = "SALES_TRANS_CUST_V"; + outputDataURI = "SALES_TRANS_CUST_AR_V"; + String caseId = "CUST_ID"; + String originalColumn = "PROD_NAME"; + String newNestedColumn = "CUSTPRODS"; + String createNestedColumn = + "CREATE VIEW SALES_TRANS_CUST_AR_V AS " + "SELECT CUST_ID, " + + "CAST(COLLECT( " + + " DM_Nested_Numerical(SUBSTR(PROD_NAME, 1, 30), has_it) " + + " ) AS DM_Nested_Numericals) CUSTPRODS " + + "FROM SALES_TRANS_CUST_V " + "GROUP BY CUST_ID"; + + // Execute the sql statement + try + { + pStmt = dbConn.prepareStatement(createNestedColumn); + pStmt.executeQuery(); + } + catch (Exception anySqlExp) + { + anySqlExp.printStackTrace(); // Ignore + } + finally + { + try + { + pStmt.close(); + } + catch (Exception ex) + { + } + ; // Ignore + } + } + + /** + * This method illustrates how to build an association mining model + * using SALES_TRANS_CUST_AR_V dataset and mining function settings. + */ + public static void buildModel() + throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("SALES_TRANS_CUST_AR_V", false); + PhysicalAttribute pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + buildData.addAttribute(pa); + m_dmeConn.saveObject(m_pdsName, buildData, false); + // 2. Create & save Mining Function Settings + // Create AssociationSettings + AssociationSettings buildSettings = m_assoFactory.create(); + // + // Association Rules in ODM works best on sparse data - i.e. data where + // the average number of attributes/items associated with a given case is + // a small percentage of the total number of possible attributes/items. + // This is true of most market basket datasets where an average customer + // purchases only a small subset of items from a fairly large inventory + // in the store. + // + // In this demo data set, we will compute density of data and + // average number of products purchased per customer, to determine + // the algorithm settings value. + // + // Compute the density of data + // COUNT(*) / COUNT(DISTINCT CUST_ID) * COUNT(DISTINCT PROD_NAME) + // 2804 / 940 * 14 --> 2.2 (22%) + // + // Compute the average number of products purchased per customer + // AVG (SELECT COUNT(PROD_NAME) + // FROM SALES_TRANS_CUST_AR_V + // GROUP BY CUST_ID) --> 2.98 (3 items) + // + // For sparse data, it is common to have a density below 1%, and AR + // typically performs well with sparse data. The above dataset, + // SALES_TRANS_CUST_AR_V, is moderately dense, 22%, (because of the + // aggregation), and we have to tune the AR parameters in accordance. + // + // Start with + // + m_minSupport = 10.0f; // 10% + m_minConfidence = 10.0f; // 10% + // Since the average number of products purchased per customer is 2.98, so + // we will set Max Rule Length (i.e. Items) = 3 + m_maxRuleLength = 3; + buildSettings.setMinSupport(m_minSupport); + buildSettings.setMinConfidence(m_minConfidence); + buildSettings.setMaxRuleLength(m_maxRuleLength); + m_dmeConn.saveObject(m_settingsName, buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = //Build data specification + //Mining function settings name + //Mining model name + m_buildFactory.create(m_pdsName, m_settingsName, m_modelName); + buildTask.setDescription(m_taskName); + executeTask(buildTask, m_taskName); + // 4. Restore the model from the data mining server + AssociationModel model = + (AssociationModel) m_dmeConn.retrieveObject(m_modelName, + NamedObject.model); + // 5. Explore the details of the restored model + // Display model build settings + AssociationSettings retrievedBuildSettings = + (AssociationSettings) model.getBuildSettings(); + if (buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, m_settingsName); + // Display the rules + displayAssociationRules(model); + } + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException + { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = + execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if (isTaskSuccess) + { + //Task completed successfully + System.out.println(taskName + " is successful."); + } + else + { //Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription()); + } + return isTaskSuccess; + } + + private static void displayBuildSettings(AssociationSettings assocSettings, + String buildSettingsName) + { + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + System.out.println("BuildSettings Details from the " + + buildSettingsName + + " model build settings object:"); + String objName = assocSettings.getName(); + if (objName != null) + System.out.println("Name = " + objName); + String objDescription = assocSettings.getDescription(); + if (objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = assocSettings.getCreationDate(); + String creator = assocSettings.getCreatorInfo(); + AlgorithmSettings algoSettings = assocSettings.getAlgorithmSettings(); + if (algoSettings == null) + System.out.println("Failure: assocSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if (algo != null) + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = assocSettings.getMiningFunction(); + if (function == null) + System.out.println("Failure: assocSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + // List of association settings + int intValue = assocSettings.getMaxRuleLength(); + System.out.println("Max Number of Rules: " + intValue); + Double doubleValue = assocSettings.getMinConfidence(); + System.out.println("Min Confidence: " + + m_df.format(doubleValue.doubleValue())); + doubleValue = assocSettings.getMinSupport(); + System.out.println("Min Support: " + + m_df.format(doubleValue.doubleValue())); + } + + private static void displayTable(String tableName, String whereCause, + String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = + dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for (int iCol = 1; iCol <= colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while (rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for (int iCol = 1; iCol <= colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if (obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal) obj; + if (bd.scale() > 5) + { + colContent = m_df.format(obj); + } + else + { + colContent = bd.toString(); + } + } + catch (Exception anyExp) + { + colContent = m_df.format(obj); + } + } + else + { + if (obj == null) + colContent = "NULL"; + else + { + colContent = obj.toString(); + try + { + Double testDouble = new Double(colContent); + colContent = m_df.format(testDouble); + } + catch (Exception e) + { + } + } + } + rowContent.append(" " + + emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } + catch (Exception anySqlExp) + { + anySqlExp.printStackTrace(); + } // Ignore + finally + { + try + { + rs.close(); + pStmt.close(); + } + catch (Exception ex) + { + } + ; // Ignore + } + } + + /** + * Displays rules from association model. + */ + private static void displayAssociationRules(AssociationModel model) + throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + // DISPLAY TOP-10 FREQUENT ITEMSETS + // + System.out.println("================================"); + System.out.println("Display Top-10 frequent itemsets"); + System.out.println("================================"); + // 1. Retrieve item sets collection that is already sorted internally: + // Order by support desc, + // itemset_id asc, + // column_value asc, + // number_of_items asc + Collection itemSets = model.getItemsets(); + Iterator iItemSets = itemSets.iterator(); + // 2. Display the top 10 item sets + int count = 0; + while (iItemSets.hasNext()) + { + if (count > 10) + break; + else + count = count + 1; + + OraItemset itemSet = (OraItemset) iItemSets.next(); + Object[] items = itemSet.getItems(); + String itemList = ""; + for (int i = 0; i < items.length; i++) + itemList = items[i] + ","; + System.out.println(itemList + " (support=" + + m_df.format(itemSet.getSupport()) + + ", number of items=" + itemSet.getSize() + ")"); + } + + // DISPLAY TOP-10 ASSOCIATION RULES + // + System.out.println("================================"); + System.out.println("Display Top-10 association rules"); + System.out.println("================================"); + // 1. Set order by confidence DESC, support DESC + OraRulesFilter filter = (OraRulesFilter) m_filterFactory.create(); + filter.setOrderingCondition(new RuleProperty[] + { RuleProperty.confidence, RuleProperty.support }, new SortOrder[] + { SortOrder.descending, SortOrder.descending }); + // 2. Set to return the first 10 rules only + filter.setMaxNumberOfRules(10); + // 3. Retrieve rules + Collection rules = model.getRules(filter); + Iterator iRules = rules.iterator(); + while (iRules.hasNext()) + { + OraAssociationRule rule = (OraAssociationRule) iRules.next(); + Itemset antecedent = rule.getAntecedent(); + Object[] ante_items = antecedent.getItems(); + // sort the items in antecedent to produce deterministic order of items + TreeSet sortedSet = new TreeSet(); + for (int i = 0; i < ante_items.length; i++) + sortedSet.add(ante_items[i]); + Iterator sortedI = sortedSet.iterator(); + while (sortedI.hasNext()) + System.out.print(sortedI.next() + " "); + Itemset consequent = rule.getConsequent(); + Object[] cons_items = consequent.getItems(); + System.out.println("==> " + cons_items[0] + " (support=" + + m_df.format(rule.getSupport()) + ", confidence=" + + m_df.format(rule.getConfidence()) + ")"); + } + } + + public static void clean() + { + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + // Drop prepared views + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW SALES_TRANS_CUST_V"); + } + catch (SQLException anySqlExp) + { + } // Ignore + finally + { + try + { + stmt.close(); + } + catch (Exception anySqlExp) + { + } + } + // Drop prepared views + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW SALES_TRANS_CUST_AR_V"); + } + catch (SQLException anySqlExp) + { + } // Ignore + finally + { + try + { + stmt.close(); + } + catch (Exception anySqlExp) + { + } + } + //Drop the model + try + { + m_dmeConn.removeObject(m_modelName, NamedObject.model); + } + catch (JDMException jdmExp) + { + } + // drop the build settings + try + { + m_dmeConn.removeObject(m_settingsName, NamedObject.buildSettings); + } + catch (JDMException jdmExp) + { + } + // drop the PDS + try + { + m_dmeConn.removeObject(m_pdsName, NamedObject.physicalDataSet); + } + catch (JDMException jdmExp) + { + } + // drop the build task + try + { + m_dmeConn.removeObject(m_taskName, NamedObject.task); + } + catch (JDMException jdmExp) + { + } + } +} diff --git a/dmardemo.sql b/dmardemo.sql new file mode 100644 index 0000000..9b3792c --- /dev/null +++ b/dmardemo.sql @@ -0,0 +1,497 @@ +Rem +Rem $Header: dmardemo.sql 04-feb-2008.19:09:11 ramkrish Exp $ +Rem +Rem dmardemo.sql +Rem +Rem Copyright (c) 2003, 2008, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmardemo.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates an association model +Rem using the Apriori algorithm +Rem and data in the SH (Sales History) schema in the RDBMS. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 02/04/08 - Add Transactional Input samples +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem dmukhin 12/13/06 - bug 5557333: AR scoping +Rem ktaylor 07/11/05 - minor edits to comments +Rem ramkrish 03/04/05 - 4222328: fix sales_trans queries for dupl custids +Rem jcjeon 01/18/05 - add column format +Rem ramkrish 09/16/04 - add data analysis and comments/cleanup +Rem ramkrish 07/30/04 - lrg 1726339 - comment out itemsetid +Rem hash-based group by no longer guarantees +Rem ordered itemset ids +Rem xbarr 06/25/04 - xbarr_dm_rdbms_migration +Rem mmcracke 12/11/03 - Remove RuleID from results display +Rem ramkrish 10/20/03 - ramkrish_txn109085 +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET linesize 140 +SET echo ON + +-- ODM API now accepts data both in relational (2D) form, and +-- transactional form for Association Rules (only). + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM USING RELATIONAL (i.e. 2D) INPUT +----------------------------------------------------------------------- +-- Find the associations between items bought by customers + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +-- Cleanup old dataset for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP VIEW sales_trans_cust'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW sales_trans_cust_ar'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------- +-- DATA +------- +-- The data for this sample is composed from a small subset of +-- sales transactions in the SH schema - listing the (multiple) +-- items bought by a set of customers with ids in the range +-- 100001-104500. Note that this data is based on customer id, +-- not basket id (as in the case of true market basket data). +-- But in either case, it is useful to remove duplicate occurrences +-- (e.g. customer buys two cans of milk in the same visit, or buys +-- boxes of the same cereal in multiple, independent visits) +-- of items per customer or per basket, since what we care about +-- is just the presence/absence of a given item per customer/basket +-- id to compute the rules. Hence the DISTINCT in the view definition. +-- +-- Market basket or sales datasets are transactional in nature, +-- and form dimension tables in a typical data warehouse. +-- +-- ODM API now accepts data both in relational (2D) form, and +-- transactional form for Association Rules (only, not for other algorithms). +-- +-- We present such transactional data to the API using an Object View +-- that contains a nested table column holding a collection of items +-- that correspond to a given customer id. +-- +-- For clarity, these views are shown just before the model build statement. +-- +CREATE VIEW sales_trans_cust AS +SELECT DISTINCT cust_id, prod_name, 1 has_it +FROM (SELECT a.cust_id, b.prod_name + FROM sh.sales a, sh.products b + WHERE a.prod_id = b.prod_id AND + a.cust_id between 100001 AND 104500) +ORDER BY cust_id, prod_name; + +----------- +-- ANALYSIS +----------- +-- Association Rules in ODM works best on sparse data - i.e. data where +-- the average number of attributes/items associated with a given case is +-- a small percentage of the total number of possible attributes/items. +-- This is true of most market basket datasets where an average customer +-- purchases only a small subset of items from a fairly large inventory +-- in the store. +-- +-- This section provides a rough outline of the analysis to be performed +-- on data used for Association Rules model build. +-- +-- 1. Compute the cardinality of customer id and product (940, 11) +SELECT COUNT(DISTINCT cust_id) cc, COUNT(DISTINCT prod_name) cp + FROM sales_trans_cust; + +-- 2. Compute the density of data (27.08) +column density format a18 +SELECT TO_CHAR((100 * ct)/(cc * cp), 99.99) density + FROM (SELECT COUNT(DISTINCT cust_id) cc, + COUNT(DISTINCT prod_name) cp, + COUNT(*) ct + FROM sales_trans_cust); + +-- 3. Common items are candidates for removal during model build, because +-- if a majority of customers have bought those items, the resulting +-- rules do not have much value. Find out most common items. For example, +-- the query shown below determines that Mouse_Pad is most common (303). +-- +-- Since the dataset is small, we will skip common item removal. +-- +column prod_name format a40 +SELECT prod_name, count(prod_name) cnt + FROM sales_trans_cust +GROUP BY prod_name +ORDER BY cnt DESC, prod_name DESC; + +-- 4. Compute the average number of products purchased per customer (2.98) +-- 3 out of 11 corresponds to the density we computed earlier. +-- +column avg_num_prod format a16 +SELECT TO_CHAR(AVG(cp), 999.99) avg_num_prod + FROM (SELECT COUNT(prod_name) cp + FROM sales_trans_cust + GROUP BY cust_id); + +-- 5. For sparse data, it is common to have a density below 1%, and +-- AR typically performs well with sparse data. The above dataset +-- is moderately dense (because of the aggregation), and we have +-- to tune the AR parameters in accordance. Start with +-- +-- - Min Support = 0.1 +-- - Min Confidence = 0.1 +-- - Max Rule Length (i.e. Items) = 3 + +-- 6. Market basket or sales datasets are transactional in nature, +-- and form dimension tables in a typical DW. We present such +-- transactional data to the API using an Object View that contains +-- a nested table column holding a collection of items that +-- correspond to a given customer id. +-- +CREATE VIEW sales_trans_cust_ar AS +SELECT cust_id, + CAST(COLLECT(DM_Nested_Numerical( + prod_name, has_it)) + AS DM_Nested_Numericals) custprods + FROM sales_trans_cust +GROUP BY cust_id; + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- +-- Data for AR modeling may need binning if it contains numerical +-- data, and categorical data with high cardinality. See dmabdemo.sql +-- for an example on quantile binning. + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE ar_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- The default (and only) algorithm for association rules is +-- Apriori AR. However, we need a settings table because we +-- intend to override the default Min Support, Min Confidence, +-- Max items +-- +set echo off +CREATE TABLE ar_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on + +BEGIN + INSERT INTO ar_sh_sample_settings VALUES + (dbms_data_mining.asso_min_support,0.1); + INSERT INTO ar_sh_sample_settings VALUES + (dbms_data_mining.asso_min_confidence,0.1); + INSERT INTO ar_sh_sample_settings VALUES + (dbms_data_mining.asso_max_rule_length,3); + COMMIT; +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Cleanup old model with same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('AR_SH_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Build a new AR model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'AR_SH_sample', + mining_function => DBMS_DATA_MINING.ASSOCIATION, + data_table_name => 'sales_trans_cust_ar', + case_id_column_name => 'cust_id', + settings_table_name => 'ar_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'AR_SH_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +-- NOT APPLICABLE +-- The model signature is applicable only for predictive models. +-- Association models are descriptive models that are summaries of data. + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +-- Association rules do not have a predefined test metric. +-- +-- Two indirect measures of modeling success are: +-- +-- 1. Number of Rules generated: The optimal number of rules is +-- application dependent. In general, an overwhelming number of +-- rules is undesirable for user interpretation. More rules take +-- longer to compute, and also consume storage and CPU cycles. +-- You avoid too many rules by increasing the value for support. +-- +-- 2. Relevance of rules +-- This can be determined only by user inspection of rules, since +-- it is application dependent. Ideally, we want to find rules with +-- high confidence and with non-obvious patterns. The value for +-- confidence is an indicator of the strength of the rule - so +-- you could set the confidence value high in conjunction with +-- support and see if you get high quality rules. +-- +-- 3. Frequent itemsets provide an insight into co-occurrence of items. + +----------------------------------------------------------------------- +-- DISPLAY MODEL CONTENT +----------------------------------------------------------------------- + +----------------------------------- +-- DISPLAY TOP-10 FREQUENT ITEMSETS +-- +break on itemset_id skip 1; +column item format a40 +SELECT item, support, number_of_items + FROM (SELECT I.attribute_subname AS item, + F.support, + F.number_of_items + FROM TABLE(DBMS_DATA_MINING.GET_FREQUENT_ITEMSETS( + 'AR_SH_sample', + 10)) F, + TABLE(F.items) I + ORDER BY number_of_items, support, item); + +----------------------------------- +-- DISPLAY TOP-10 ASSOCIATION RULES +-- ordered by confidence DESC, support DESC +-- +SET line 300 +column antecedent format a140 +column consequent format a140 +SELECT ROUND(rule_support,4) support, +-- rule_id, + ROUND(rule_confidence,4) confidence, + antecedent, + consequent + FROM TABLE(DBMS_DATA_MINING.GET_ASSOCIATION_RULES('AR_SH_sample', 10)) + ORDER BY confidence DESC, support DESC; + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM USING TRANSACTIONAL (tuple/triple) INPUT +----------------------------------------------------------------------- + +-- ODM API accepts data both in relational (2D) form, and +-- transactional form for Association Rules (only). +-- +-- The transactional input is a two column table of the form: +-- (case_id, item_id) +-- or a three column table of the form: +-- (item_id, transaction_id, transaction_value) +-- +-- case_id can be a string/categorical or Numerical +-- Item Id can be categorical or numerical +-- Item Value can be categorical or numerical +-- +-- Example of a two column transactional table is: +-- (case_id, item_id) +-- (1, 1) +-- (1, 4) +-- (2, 2) +-- or +-- (1, apple) +-- (1, pear) +-- (2, banana) +-- +-- Example of a three column transactional table is: +-- (case_id, item_id, item_val) +-- (1, apple, 2) +-- (1, apple, 4) +-- (2, banana, 1) +-- (2, banana, 2) +-- or +-- (1, wine, red) +-- (1, wine, white) +-- (2, cheese, swiss) +-- (2, cheese, provolone) +-- which allows you to treat different (item_id, val) pairings +-- against a given case-id essentially as different, unique items +-- in the itemset +-- + +BEGIN EXECUTE IMMEDIATE 'DROP VIEW sales_str_xnal'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW sales_xnal_cat_sval'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN DBMS_DATA_MINING.DROP_MODEL('AR_SH_Sample_str_xnal'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN DBMS_DATA_MINING.DROP_MODEL('AR_SH_Sample_xnal_sval'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +--------------------------------------------------------- +-- Add settings for Transaction Input - the presence +-- of an Item Id column specification indicates to the +-- API that the input is transactional +-- +BEGIN + INSERT INTO ar_sh_sample_settings VALUES + (dbms_data_mining.odms_item_id_column_name, 'ITEM_ID'); +END; +/ + +----------------------------------------- +-- Transactional input (case_id, item_id) +-- String Case-ID, Categorical Item_id +-- +CREATE VIEW sales_str_xnal AS +SELECT (TO_CHAR(cust_id) || '_String') AS cust_id, + prod_name AS item_id + FROM sales_trans_cust; + +---------------------------------------------- +-- Build AR model with transactional input +-- With String Case-ID, Categorical Item-Id +-- +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'AR_SH_Sample_str_xnal', + mining_function => DBMS_DATA_MINING.ASSOCIATION, + data_table_name => 'sales_str_xnal', + case_id_column_name => 'cust_id', + settings_table_name => 'ar_sh_sample_settings' + ); +END; +/ + +------------------------------------------------------------- +-- Display Top-10 Frequent Itemsets +-- Transactional input - String Case-Id, Categorical Item-Id +-- +break on itemset_id skip 1; +column item format a40 +SELECT item, support, number_of_items + FROM (SELECT I.attribute_subname AS item, + F.support, + F.number_of_items + FROM TABLE(DBMS_DATA_MINING.GET_FREQUENT_ITEMSETS( + 'AR_SH_Sample_str_xnal', + 10)) F, + TABLE(F.items) I + ORDER BY number_of_items, support, item); + +---------------------------------------------------------- +-- Display Top-10 Association Rules - Transactional input +-- Transactional input - String Case-Id, Categorical Item-Id +-- ordered by confidence DESC, support DESC +-- (Rule ID has been commented out because it is not a +-- repeatable ID - uncomment rule id in your run if needed) +-- +SET line 300 +column antecedent format a140 +column consequent format a140 +SELECT ROUND(rule_support,4) support, +-- rule_id, + ROUND(rule_confidence,4) confidence, + antecedent, + consequent + FROM TABLE(DBMS_DATA_MINING.GET_ASSOCIATION_RULES( + 'AR_SH_Sample_str_xnal', 10)) + ORDER BY confidence DESC, support DESC; + +--------------------------------------------------------- +-- Add settings for item Value +-- +BEGIN + INSERT INTO ar_sh_sample_settings VALUES + (dbms_data_mining.odms_item_value_column_name, 'ITEM_VAL'); + COMMIT; +END; +/ + +------------------------------------------------------------------ +-- Transactional input (case_id, item_id) with categorical item_id +-- Numeric Case_id, Categorical item_id, Categorical item_val +-- +CREATE VIEW sales_xnal_cat_sval AS +SELECT cust_id, + prod_name AS item_id, + prod_name AS item_val + FROM sales_trans_cust; + +---------------------------------------------- +-- Build AR model with transactional input +-- Numeric Case-Id, Categorical Item-Id, Categorical Item-val +-- +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'AR_SH_Sample_xnal_sval', + mining_function => DBMS_DATA_MINING.ASSOCIATION, + data_table_name => 'sales_xnal_cat_sval', + case_id_column_name => 'cust_id', + settings_table_name => 'ar_sh_sample_settings' + ); +END; +/ + +------------------------------------------------------------- +-- Display Top-10 Frequent Itemsets +-- Transactional input - Numeric Case-Id, Categorical Item-Id +-- +break on itemset_id skip 1; +column item format a40 +SELECT item, support, number_of_items + FROM (SELECT I.attribute_subname AS item, + F.support, + F.number_of_items + FROM TABLE(DBMS_DATA_MINING.GET_FREQUENT_ITEMSETS( + 'AR_SH_Sample_xnal_sval', + 10)) F, + TABLE(F.items) I + ORDER BY number_of_items, support, item); + +---------------------------------------------------------- +-- Display Top-10 Association Rules - Transactional input +-- Transactional input - +-- Numeric Case-Id, Categorical Item-Id, Categorical Item-val +-- ordered by confidence DESC, support DESC +-- (Rule ID has been commented out because it is not a +-- repeatable ID - uncomment rule id in your run if needed) +-- +SET line 300 +column antecedent format a140 +column consequent format a140 +SELECT ROUND(rule_support,4) support, +-- rule_id, + ROUND(rule_confidence,4) confidence, + antecedent, + consequent + FROM TABLE(DBMS_DATA_MINING.GET_ASSOCIATION_RULES( + 'AR_SH_Sample_xnal_sval', 10)) + ORDER BY confidence DESC, support DESC; diff --git a/dmdtdemo.sql b/dmdtdemo.sql new file mode 100644 index 0000000..00ee589 --- /dev/null +++ b/dmdtdemo.sql @@ -0,0 +1,334 @@ +Rem +Rem $Header: dmdtdemo.sql 25-oct-2007.11:35:28 ramkrish Exp $ +Rem +Rem dmdtdemo.sql +Rem +Rem Copyright (c) 2004, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmdtdemo.sql - Sample program for the DBMS_DATA_MINING package +Rem +Rem DESCRIPTION +Rem This script creates a classification model +Rem using the Decision Tree algorithm +Rem and data from the SH (Sales History) schema in the RDBMS. +Rem +Rem This program uses the PREDICTION_* functions for model scoring. +Rem +Rem NOTES +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem jiawang 11/10/06 - Set pretty print +Rem ktaylor 07/11/05 - minor edits to comments +Rem ramkrish 01/28/05 - prediction column format fixes +Rem jcjeon 01/18/05 - add column format +Rem ramkrish 10/27/04 - add data analysis and comments/cleanup +Rem mjaganna 11/20/04 - remove the use of priors +Rem amozes 08/04/04 - singular dtree, plural prediction_details +Rem amozes 07/13/04 - amozes_bug-3756145 +Rem amozes 07/09/04 - Created +Rem + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET linesize 320 +SET echo ON +SET long 2000000000 + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic data about a set of customers, predict the +-- customer response to an affinity card program using a classifier +-- based on Decision Trees algorithm. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- +-- The data for this sample is composed from base tables in SH Schema +-- (See Sample Schema Documentation) and presented through these views: +-- mining_data_build_v (build data) +-- mining_data_test_v (test data) +-- mining_data_apply_v (apply data) +-- (See dmsh.sql for view definitions). + +----------- +-- ANALYSIS +----------- +-- These are the factors to consider for data analysis in decision trees: +-- +-- 1. Missing Value Treatment for Predictors +-- +-- See dmsvcdem.sql for a definition of missing values, and the +-- steps to be taken for missing value imputation. +-- +-- Sparse data is not suitable for decision trees, but it will +-- accept sparse data nevertheless. +-- +-- Decision Tree implementation in ODM handles missing predictor +-- values (by penalizing predictors which have missing values) +-- and missing target values (by simply discarding records with +-- missing target values). +-- +-- 2. Outlier Treatment for Predictors for Build data +-- +-- See dmsvcdem.sql for a discussion on outlier treatment. +-- For decision trees, outlier treatment is not really necessary. +-- +-- 3. Binning high cardinality data +-- No data preparation for the types we accept is necessary - even +-- for high cardinality predictors. Preprocessing to reduce the +-- cardinality (e.g., binning) can improve the performance of the build, +-- but it could penalize the accuracy of the resulting model. +-- +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old model with same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('DT_SH_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- +-- The decision tree algorithm is very capable of handling data which +-- has not been specially prepared. For this example, no data preparation +-- will be performed. +-- + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE dt_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE dt_sh_sample_cost'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------- +-- CREATE A SETTINGS TABLE +-- +-- The default classification algorithm is Naive Bayes. In order to override +-- this, create and populate a settings table to be used as input for +-- CREATE_MODEL. +-- +set echo off +CREATE TABLE dt_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on + +-- CREATE AND POPULATE A COST MATRIX TABLE +-- +-- A cost matrix is used to influence the weighting of misclassification +-- during model creation (and scoring). +-- See Oracle Data Mining Concepts Guide for more details. +-- +CREATE TABLE dt_sh_sample_cost ( + actual_target_value NUMBER, + predicted_target_value NUMBER, + cost NUMBER); +INSERT INTO dt_sh_sample_cost VALUES (0,0,0); +INSERT INTO dt_sh_sample_cost VALUES (0,1,1); +INSERT INTO dt_sh_sample_cost VALUES (1,0,8); +INSERT INTO dt_sh_sample_cost VALUES (1,1,0); + +BEGIN + -- Populate settings table + INSERT INTO dt_sh_sample_settings VALUES + (dbms_data_mining.algo_name, dbms_data_mining.algo_decision_tree); + INSERT INTO dt_sh_sample_settings VALUES + (dbms_data_mining.clas_cost_table_name, 'dt_sh_sample_cost'); + + -- Examples of other possible settings are: + --(dbms_data_mining.tree_impurity_metric, 'TREE_IMPURITY_ENTROPY') + --(dbms_data_mining.tree_term_max_depth, 5) + --(dbms_data_mining.tree_term_minrec_split, 5) + --(dbms_data_mining.tree_term_minpct_split, 2) + --(dbms_data_mining.tree_term_minrec_node, 5) + --(dbms_data_mining.tree_term_minpct_node, 0.05) +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Build a DT model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'DT_SH_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 'mining_data_build_v', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + settings_table_name => 'dt_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'DT_SH_CLAS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'DT_SH_CLAS_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- NOTE: The """ characters in this XML output are owing to +-- SQL*Plus behavior. Cut and paste this XML into a file, +-- and open the file in a browser to see correctly formatted XML. +-- +column dt_details format a320 +exec dbms_xdb_print.setPrintMode(dbms_xdb_print.PRINT_PRETTY, 2); +SELECT + dbms_data_mining.get_model_details_xml('DT_SH_Clas_sample') + AS DT_DETAILS +FROM dual; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +-------------------- +-- PREPARE TEST DATA +-- +-- If the data for model creation has been prepared, then the data used +-- for testing the model must be prepared to the same scale in order to +-- obtain meaningful results. +-- In this case, no data preparation is necessary since model creation +-- was performed on the raw (unprepared) input. +-- + +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- +-- Other demo programs demonstrate how to use the PL/SQL API to +-- compute a number of metrics, including lift and ROC. This demo +-- only computes a confusion matrix and accuracy, but it does so +-- using the SQL data mining functions. +-- +-- In this example, we experiment with using the cost matrix +-- that was provided to the create routine. In this example, the +-- cost matrix reduces the problematic misclassifications, but also +-- negatively impacts the overall model accuracy. + +-- DISPLAY CONFUSION MATRIX WITHOUT APPLYING COST MATRIX +-- +SELECT affinity_card AS actual_target_value, + PREDICTION(DT_SH_Clas_sample USING *) AS predicted_target_value, + COUNT(*) AS value + FROM mining_data_test_v +GROUP BY affinity_card, PREDICTION(DT_SH_Clas_sample USING *) +ORDER BY 1,2; + +-- DISPLAY CONFUSION MATRIX APPLYING THE COST MATRIX +-- +SELECT affinity_card AS actual_target_value, + PREDICTION(DT_SH_Clas_sample COST MODEL USING *) + AS predicted_target_value, + COUNT(*) AS value + FROM mining_data_test_v +GROUP BY affinity_card, PREDICTION(DT_SH_Clas_sample COST MODEL USING *) +ORDER BY 1,2; + +-- DISPLAY ACCURACY WITHOUT APPLYING COST MATRIX +-- +SELECT ROUND(SUM(correct)/COUNT(*),4) AS accuracy + FROM (SELECT DECODE(affinity_card, + PREDICTION(DT_SH_Clas_sample USING *), 1, 0) AS correct + FROM mining_data_test_v); + +-- DISPLAY ACCURACY APPLYING THE COST MATRIX +-- +SELECT ROUND(SUM(correct)/COUNT(*),4) AS accuracy + FROM (SELECT DECODE(affinity_card, + PREDICTION(DT_SH_Clas_sample COST MODEL USING *), + 1, 0) AS correct + FROM mining_data_test_v); + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- + +------------------ +-- BUSINESS CASE 1 +-- Find the 10 customers who live in Italy that are least expensive +-- to be convinced to use an affinity card. +-- +WITH +cust_italy AS ( +SELECT cust_id + FROM mining_data_apply_v + WHERE country_name = 'Italy' +ORDER BY PREDICTION_COST(DT_SH_Clas_sample, 1 COST MODEL USING *) ASC, 1 +) +SELECT cust_id + FROM cust_italy + WHERE rownum < 11; + +------------------ +-- BUSINESS CASE 2 +-- Find the average age of customers who are likely to use an +-- affinity card. +-- Include the build-time cost matrix in the prediction. +-- Only take into account CUST_MARITAL_STATUS, EDUCATION, and +-- HOUSEHOLD_SIZE as predictors. +-- Break out the results by gender. +-- +column cust_gender format a12 +SELECT cust_gender, COUNT(*) AS cnt, ROUND(AVG(age)) AS avg_age + FROM mining_data_apply_v + WHERE PREDICTION(dt_sh_clas_sample COST MODEL + USING cust_marital_status, education, household_size) = 1 +GROUP BY cust_gender +ORDER BY cust_gender; + +------------------ +-- BUSINESS CASE 3 +-- List ten customers (ordered by their id) along with likelihood and cost +-- to use or reject the affinity card (Note: while this example has a +-- binary target, such a query is useful in multi-class classification - +-- Low, Med, High for example). +-- +column prediction format 9; +SELECT T.cust_id, S.prediction, S.probability, S.cost + FROM (SELECT cust_id, + PREDICTION_SET(dt_sh_clas_sample COST MODEL USING *) pset + FROM mining_data_apply_v + WHERE cust_id < 100011) T, + TABLE(T.pset) S +ORDER BY cust_id, S.prediction; + +------------------ +-- BUSINESS CASE 4 +-- Find the segmentation (resulting tree node) for customers who +-- work in Tech support and are under 25. +-- +column education format a30; +column treenode format a40; +SELECT cust_id, education, + PREDICTION_DETAILS(dt_sh_clas_sample USING *) treenode + FROM mining_data_apply_v + WHERE occupation = 'TechSup' AND age < 25 +ORDER BY 1; diff --git a/dmdtxvlddemo.sql b/dmdtxvlddemo.sql new file mode 100644 index 0000000..66a2c7a --- /dev/null +++ b/dmdtxvlddemo.sql @@ -0,0 +1,246 @@ +Rem +Rem $Header: dmdtxvlddemo.sql 15-jun-2007.18:38:59 ramkrish Exp $ +Rem +Rem dmdtxvlddemo.sql +Rem +Rem Copyright (c) 2005, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmdtxvlddemo.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script demonstrates the use of cross-validation for evaluating +Rem decision tree models when the amount of data available for training +Rem and testing is relatively small. Also demonstrates the desirability +Rem of using as much +Rem of the data as possible for building as well as testing models. +Rem +Rem Cross validation is a generic technique, and can be utilized for +Rem evaluating other algorithms as well with suitable modifications +Rem to settings. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ktaylor 07/11/05 - Minor edits to comments +Rem mjaganna 02/10/05 - mjaganna_xvalidate_demo +Rem mjaganna 01/28/05 - Created +Rem + +SET SERVEROUTPUT ON +SET ECHO OFF +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET long 2000000000 + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic data about a set of customers, compute the accuracy +-- of predictions for customer response to an affinity card program +-- using a classifier based on Decision Trees algorithm. +-- +-- This demo should be viewed as an extension of the scenario +-- described in dmdtdemo.sql. We perform 10 fold cross-validation +-- using the training data set alone. + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE dt_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------- +-- CREATE A SETTINGS TABLE +-- +-- The default classification algorithm is Naive Bayes. In order to override +-- this, create and populate a settings table to be used as input for +-- CREATE_MODEL. +-- +CREATE TABLE dt_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); + +DECLARE + nfolds NUMBER; + maxbucket NUMBER; -- max buckets for ORA_HASH() + iter NUMBER; -- loop itarator + tgtname VARCHAR2(30); -- target column name + tgtval NUMBER; -- class value (same type as target column) + case_id VARCHAR2(30); -- case_id column name + tabname VARCHAR2(30); -- training data + tabname_p VARCHAR2(30); -- "partitioned" training data + model_name VARCHAR2(30); -- model_name + sqltxt VARCHAR2(32767); + type dmdtcurtyp IS REF CURSOR; + tgtcur dmdtcurtyp; +BEGIN + nfolds := 10; -- number of folds (typically 10 fold) + maxbucket := nfolds-1; -- max buckets for ORA_HASH(); max of 9 means + -- 10 buckets in all 0..9 + + model_name := 'DT_SH_Clas_Xvld_tmp'; + tgtname := 'affinity_card'; + + --Training data, can be parametrized for general usage + tabname := 'mining_data_build_v'; + case_id := 'cust_id'; + + -- "partitioned" table + tabname_p := tabname || '_P'; + + -- Populate settings table + INSERT INTO dt_sh_sample_settings VALUES + (dbms_data_mining.algo_name, dbms_data_mining.algo_decision_tree); + + -- Examples of other possible settings are: + --(dbms_data_mining.tree_impurity_metric, 'TREE_IMPURITY_ENTROPY') + --(dbms_data_mining.tree_term_max_depth, 5) + --(dbms_data_mining.tree_term_minrec_split, 5) + --(dbms_data_mining.tree_term_minpct_split, 2) + --(dbms_data_mining.tree_term_minrec_node, 5) + --(dbms_data_mining.tree_term_minpct_node, 0.05) + BEGIN EXECUTE IMMEDIATE 'DROP TABLE dmdtxvld_c'; + EXCEPTION WHEN OTHERS THEN NULL; END; + + -- The column type of the actual and predicted should be the same as the + -- target column, in this case it happens to be NUMBER + EXECUTE IMMEDIATE + 'CREATE TABLE dmdtxvld_c (' || + 'iter NUMBER, actual NUMBER(10), predicted NUMBER(10), count NUMBER)'; + + -- Create "partitioned" table. A new table is created which tags the rows + -- with a partition number using column 'pn' + -- + -- Drop if already exists + BEGIN EXECUTE IMMEDIATE 'DROP TABLE '|| tabname_p; + EXCEPTION WHEN OTHERS THEN NULL; END; + + -- Instances of each class are partitioned nfolds ways + sqltxt := 'CREATE TABLE ' || tabname_p || ' AS '; + + -- Open tgtcur using tgtname,tabname; + OPEN tgtcur FOR 'SELECT DISTINCT(' || tgtname || ') FROM '|| tabname; + + -- Form SQL statement with as many UNION ALL's as distinct target values + FETCH tgtcur INTO tgtval; + sqltxt := sqltxt || + 'SELECT t1.*, MOD(ROWNUM,' || nfolds ||') pn ' || + 'FROM (SELECT t.*, ORA_HASH(rownum) randrow ' || + 'FROM ' || tabname || ' t ' || + 'WHERE ' || tgtname || ' = '''|| tgtval ||''' ORDER BY randrow) t1 '; + LOOP + FETCH tgtcur INTO tgtval; + EXIT WHEN tgtcur%NOTFOUND; + + sqltxt := sqltxt || + 'UNION ALL ' || + 'SELECT t1.*, MOD(ROWNUM,' || nfolds || ') pn ' || + 'FROM (SELECT t.*, ORA_HASH(rownum) randrow ' || + 'FROM ' || tabname || ' t ' || + 'WHERE ' || tgtname || ' = '''|| tgtval||''' ORDER BY randrow) t1 '; + END LOOP; + CLOSE tgtcur; + + -- execute the statement + EXECUTE IMMEDIATE sqltxt; + + -- Iterate nfolds times. Each time we use (nfolds-1)*R/nfolds rows for build + -- and the remaining R/nfolds rows for testing where R is the number of + -- training rows (instances) + -- + FOR iter IN 0..(nfolds-1) + LOOP + + -- Create the build view + -- All rows except those in current partition + EXECUTE IMMEDIATE + 'CREATE OR REPLACE VIEW xvld_tmp_bld_v AS ' || + 'SELECT * FROM ' || tabname_p || ' WHERE pn != '|| iter; + + -- We will test using rows in current partition + EXECUTE IMMEDIATE + 'CREATE OR REPLACE VIEW xvld_tmp_tst_v AS ' || + 'SELECT * FROM ' || tabname_p || ' WHERE pn = '|| iter; + + -- Build a model with this subset of data + BEGIN + -- Cleanup old model with same name for repeat runs + BEGIN DBMS_DATA_MINING.DROP_MODEL(model_name); + EXCEPTION WHEN OTHERS THEN NULL; END; + + -- Build a DT model + BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => model_name, + mining_function => dbms_data_mining.classification, + data_table_name => 'xvld_tmp_bld_v', + case_id_column_name => case_id, + target_column_name => tgtname, + settings_table_name => 'dt_sh_sample_settings'); + END; + + -- Apply the model, and compute confusion matrix + -- Confusion matrix is saved away in dmdtxvld_c table tagged by + -- iteration number iter + EXECUTE IMMEDIATE + 'INSERT INTO dmdtxvld_c ' || + 'SELECT ' || iter || ',' || tgtname || ' AS actual_target_value,' || + 'PREDICTION('|| model_name || ' USING *) ' || + 'AS predicted_target_value,' || + 'COUNT(*) AS value ' || + 'FROM xvld_tmp_tst_v ' || + 'GROUP BY ' || tgtname || ', PREDICTION('|| model_name|| ' USING *) ' || + 'ORDER BY 1,2'; + END; + END LOOP; + + -- Drop the model and partitioned table + -- remaining from the last iteration + BEGIN DBMS_DATA_MINING.DROP_MODEL(model_name); + EXCEPTION WHEN OTHERS THEN NULL; END; + + BEGIN EXECUTE IMMEDIATE 'DROP TABLE '|| TABNAME_P; + EXCEPTION WHEN OTHERS THEN NULL; END; + + BEGIN EXECUTE IMMEDIATE 'DROP VIEW XVLD_TMP_BLD_V'; + EXCEPTION WHEN OTHERS THEN NULL; END; + + BEGIN EXECUTE IMMEDIATE 'DROP VIEW XVLD_TMP_TST_V'; + EXCEPTION WHEN OTHERS THEN NULL; END; + +END; +/ + +-- Compute accuracy per iteration and the average for nfolds +-- from the confusion matrix +-- +EXEC DBMS_OUTPUT.PUT_LINE('Model accuracy by iteration'); + +SELECT a.iter, AVG(ROUND(correct/total,4)) AS accuracy + FROM (SELECT iter, SUM(count) AS correct + FROM dmdtxvld_c + WHERE actual = predicted + GROUP BY iter) a, + (SELECT iter, SUM(count) AS total + FROM dmdtxvld_c + GROUP BY iter) b + WHERE a.iter = b.iter +GROUP BY ROLLUP (a.iter); + +-- Show confusion matrix by iteration and rolled up across iterations +EXEC DBMS_OUTPUT.PUT_LINE('Confusion Matrix by iteration'); +SELECT * + FROM (SELECT iter, actual, predicted, SUM(count) count + FROM dmdtxvld_c + GROUP BY ROLLUP (actual, predicted, iter)) + WHERE predicted IS NOT NULL +ORDER BY iter, actual, predicted; diff --git a/dmexpimpdemo.java b/dmexpimpdemo.java new file mode 100644 index 0000000..dc208b2 --- /dev/null +++ b/dmexpimpdemo.java @@ -0,0 +1,388 @@ +// Copyright (c) 2001, 2006, Oracle. All rights reserved. +// File: dmexpimpdemo.java + +/** + * This sample program describes how to use the ODM Java API for importing + * an ODM model to the Data Mining Server(DMS) and exporting an ODM model from + * the DMS in the native format. + * To illustrate import/export, this program builds a NaiveBayes model + * using "IE_BINNED_DATA_BUILD_JDM" prepared dataset. After building the model, it + * exports the model to "nbexport.dump" file. After exporting the model + * it imports the exported model. + * + * NOTE: + * You need to create a writable directory called dm_dump before executing + * this demo program. + * For example: + * CREATE OR REPLACE DIRECTORY dm_dump AS '/user/temp'; + * GRANT READ, WRITE ON DIRECTORY dm_dump TO ; + *------------------------------------------------------------------------------ + * EXECUTING DEMO PROGRAM + *------------------------------------------------------------------------------ + * Refer to Oracle Data Mining Administrator's Guide + * for guidelines for executing this demo program. + */ +// Generic Java Imports +import java.sql.Statement; + +import java.util.HashMap; +import java.util.Map; +// Java Data Mining (JDM) standard imports +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.NamedObject; +import javax.datamining.algorithm.naivebayes.NaiveBayesSettings; +import javax.datamining.algorithm.naivebayes.NaiveBayesSettingsFactory; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.ExportTask; +import javax.datamining.task.ExportTaskFactory; +import javax.datamining.task.ImportTask; +import javax.datamining.task.ImportTaskFactory; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.binning.OraBinningTransformFactory; +import oracle.dmt.jdm.transform.binning.OraBinningTransformImpl; +import oracle.dmt.jdm.transform.binning.OraCategoricalBinningType; +import oracle.dmt.jdm.transform.binning.OraNumericalBinningType; + +/** + * This sample program describes how to use the ODM Java API for importing + * an ODM model to the Data Mining Server(DMS) and exporting an ODM model from + * the DMS in the native format. + * To illustrate import/export, this program builds a NaiveBayes model + * using "IE_BINNED_DATA_BUILD_JDM" prepared dataset. After building the model, it + * exports the model to "nbexport.dump" file. After exporting the model + * it imports the exported model. + * + * NOTE: + * You need to create a writable directory called dm_dump before executing + * this demo program. + * For example: + * CREATE OR REPLACE DIRECTORY dm_dump AS '/user/temp'; + * GRANT READ, WRITE ON DIRECTORY dm_dump TO ; + *------------------------------------------------------------------------------ + * EXECUTING DEMO PROGRAM + *------------------------------------------------------------------------------ + * Refer to Oracle Data Mining Administrator's Guide + * for guidelines for executing this demo program. + */ +public class + +dmexpimpdemo + extends Object +{ + + //Connection related data members + private static javax.datamining.resource.Connection m_dmeConn = null; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory = + null; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory = null; + private static PhysicalAttributeFactory m_paFactory = null; + private static ClassificationSettingsFactory m_clasFactory = null; + private static NaiveBayesSettingsFactory m_nbFactory = null; + private static BuildTaskFactory m_buildFactory = null; + private static ExportTaskFactory m_exportFactory = null; + private static ImportTaskFactory m_importFactory = null; + private static OraBinningTransformFactory m_binningXformFactory = null; + private static OraTransformationTaskFactory m_xformTaskFactory = null; + + public static void main(String[] args) + { + try + { + if ((args.length != 0) & (args.length != 3)) + { + System.out.println("Usage: java dmexpimpdemo "); + System.out.println(" or: java dmexpimpdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Create and save task to build a naive bayes model + buildModel(); + // 6. Create and save task to export the built model + exportModel(); + // 7. Create and save task to import the exported model + importModel(); + // 8. Execute the model build to start executing the sequenece of tasks + m_dmeConn.execute("nbExpImpBuildTask_jdm"); + // 9. Monitor process + monitorTaskExecutionProcess(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + } //Ignore + } + } + + public static void initFactories() + throws JDMException + { + m_pdsFactory = + (PhysicalDataSetFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalDataSet"); + m_paFactory = + (PhysicalAttributeFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalAttribute"); + m_clasFactory = + (ClassificationSettingsFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationSettings"); + m_nbFactory = + (NaiveBayesSettingsFactory) m_dmeConn.getFactory("javax.datamining.algorithm.naivebayes.NaiveBayesSettings"); + m_buildFactory = + (BuildTaskFactory) m_dmeConn.getFactory("javax.datamining.task.BuildTask"); + m_exportFactory = + (ExportTaskFactory) m_dmeConn.getFactory("javax.datamining.task.ExportTask"); + m_importFactory = + (ImportTaskFactory) m_dmeConn.getFactory("javax.datamining.task.ImportTask"); + m_binningXformFactory = + (OraBinningTransformFactory) m_dmeConn.getFactory("oracle.dmt.jdm.transform.binning.OraBinningTransform"); + m_xformTaskFactory = + (OraTransformationTaskFactory) m_dmeConn.getFactory("oracle.dmt.jdm.task.OraTransformationTask"); + } + + /** + * This method builds a mining model. The build operation requires the training + * dataset location details and the mining function settings. + * In this example, we will build a classification model using the + * build dataset "IE_BINNED_DATA_BUILD_JDM" in the user schema, with the + * NaiveBayes algorithm. This model can be used to predict which customer + * would respond to a promotion campaign. After completing the build task, the + * model named "nbModel_jdm" will be created in the DMS. + */ + public static void buildModel() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + buildData.addAttribute(pa); + m_dmeConn.saveObject("nbExpImpBuildData_jdm", buildData, true); + //2. Create & save Mining Function Settings + //Create NB algorithm settings + NaiveBayesSettings nbAlgo = m_nbFactory.create(); + nbAlgo.setPairwiseThreshold(0.01f); + nbAlgo.setSingletonThreshold(0.01f); + //Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(nbAlgo); + buildSettings.setTargetAttributeName("affinity_card"); + //Set target prior probabilities + Map priorMap = new HashMap(); + priorMap.put(new Double(0), new Double(0.7)); + priorMap.put(new Double(1), new Double(0.3)); + buildSettings.setPriorProbabilitiesMap("affinity_card", priorMap); + //Use auto data prep + ((OraBuildSettings) buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject("nbExpImpBuildSettings_jdm", buildSettings, true); + //3. Create, save & execute Build Task + BuildTask buildTask = //Build data specification + //Mining function settings name + //Mining model name + m_buildFactory.create("nbExpImpBuildData_jdm", + "nbExpImpBuildSettings_jdm", + "nbExpImpModel_jdm"); + buildTask.setDescription("nbExpImpBuildTask_jdm"); + saveTask(buildTask, "nbExpImpBuildTask_jdm", null); + } + + /** + * This method exports the mining model into a dump file. + * In this example, we will export "nbExpImpModel_jdm" and store the exported + * model into a "nbExport" dump file in "DM_DUMP" directory. + */ + public static void exportModel() + throws JDMException + { + ExportTask exportTask = m_exportFactory.create(); + exportTask.addObjectName("nbExpImpModel_jdm", NamedObject.model); + exportTask.setURI("DM_DUMP/nbExport"); + saveTask(exportTask, "nbExportTask_jdm", "nbExpImpBuildTask_jdm"); + } + + /** + * This method imports the mining model from a dump file. + * In this example, we will import the model "nbExpImpModel_jdm" from + * "nbExport" dump file in "DM_DUMP" directory. + */ + public static void importModel() + throws JDMException + { + //Drop the built model + try + { + m_dmeConn.removeObject("nbExpImpModel_jdm", NamedObject.model); + } + catch (Exception jdmExp) + { + } + + ImportTask importTask = m_importFactory.create(); + importTask.setURI("DM_DUMP/nbExport%U"); + saveTask(importTask, "nbImportTask_jdm", "nbExportTask_jdm"); + } + + /** + * Cleanup the previously created objects if any. + */ + private static void clean() + { + //Drop the imported model + try + { + m_dmeConn.removeObject("nbExpImpModel_jdm", NamedObject.model); + } + catch (Exception jdmExp) + { + } + } + + /** + * This method monitor task execution initiated by the first task + * in the sequence of dependent tasks. In addition, this method displays + * task output results (if any). + * @throws JDMException + */ + public static void monitorTaskExecutionProcess() + throws JDMException + { + //BuildTask + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of nbExpImpBuildTask_jdm. "); + ExecutionStatus buildTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("nbExpImpBuildTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(buildTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + + //If model build is successful, then do export model task + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of nbExportTask_jdm. "); + ExecutionStatus modelExportTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("nbExportTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(modelExportTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + //If model export is successful, then wait for import task completion + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of nbImportTask_jdm. "); + ExecutionStatus modelImportTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("nbImportTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(modelImportTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + } + else + { + System.out.println("It is at state:" + + modelImportTaskCompletionStatus.getState().name() + + ((modelImportTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + modelImportTaskCompletionStatus.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + modelExportTaskCompletionStatus.getState().name() + + ((modelExportTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + modelExportTaskCompletionStatus.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + buildTaskCompletionStatus.getState().name() + + ((buildTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + buildTaskCompletionStatus.getDescription())); + } + } + + /** + * This method saves the given task with the specified task name and task + * dependency (parent task) in the DME. + * + * @param taskObj task object + * @param taskName name of the task + * @param parentTaskName name of the parent task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static void saveTask(Task taskObj, String taskName, + String parentTaskName) + throws JDMException + { + if (parentTaskName != null) + ((OraTask) taskObj).addDependency(parentTaskName); //Since OJDM 11.1 + //if (!(taskObj instanceof BuildTask)) + ((OraTask) taskObj).overwriteOutput(true); //Since OJDM 11.1 + m_dmeConn.saveObject(taskName, taskObj, true); + } + + public static void trackTaskExecution(String taskName, + ExecutionHandle execHandle) + throws JDMException + { + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = + execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + boolean isTaskSuccess = + status.getState().equals(ExecutionState.success); + if (isTaskSuccess) //Task completed successfully + System.out.println(taskName + " is successful."); + else //Task failed + System.out.println(taskName + " failed.\nFailure Description: " + + status.getDescription()); + } + +} diff --git a/dmglcdem.sql b/dmglcdem.sql new file mode 100644 index 0000000..ef67cf4 --- /dev/null +++ b/dmglcdem.sql @@ -0,0 +1,461 @@ +Rem +Rem $Header: dmglcdem.sql 22-jan-2008.14:06:04 ramkrish Exp $ +Rem +Rem dmglcdem.sql +Rem +Rem Copyright (c) 2003, 2008, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmglcdem.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a classification model using GLM based on +Rem data in the SH (Sales History) schema in the RDBMS and +Rem demonstrates the use of SQL prediction functions to test +Rem the model and apply it to new data. +Rem +Rem NOTES +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 01/22/08 - add prediction_bounds +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem bmilenov 05/08/07 - Change case_id column in row diagnostics table +Rem bmilenov 12/13/06 - Turn ADP on +Rem bmilenov 12/05/06 - Change row diagnostic query +Rem jyarmus 11/21/06 - Change ridge regression constant +Rem jyarmus 10/18/06 - reduce precision of accuracy and AUC +Rem jyarmus 10/13/06 - drop diagnostics table prior to second model +Rem build +Rem jyarmus 10/12/06 - Run with and without ridge +Rem bmilenov 10/04/06 - Remove multicolinear columns +Rem bmilenov 08/22/06 - Drop class weight table +Rem bmilenov 08/18/06 - Cleanup +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic and purchase data about a set of customers, predict +-- customer's response to an affinity card program using a GLM classifier. +-- + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +------- +-- DATA +------- +-- The data for this sample is composed from base tables in SH Schema +-- (See Sample Schema Documentation) and presented through these views: +-- mining_data_build_v (build data) +-- mining_data_test_v (test data) +-- mining_data_apply_v (apply data) +-- (See dmsh.sql for view definitions). +-- + +----------- +-- ANALYSIS +----------- +-- Data preparation in GLM is performed internally +-- + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old model with the same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('GLMC_SH_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------ +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE glmc_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +-- Cleanup class weights +BEGIN EXECUTE IMMEDIATE 'DROP TABLE glmc_sh_sample_clas_weights'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Cleanup diagnostics table +BEGIN EXECUTE IMMEDIATE 'DROP TABLE glmc_sh_sample_diag'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- CREATE AND POPULATE A CLASS WEIGHTS TABLE +-- +-- A class weights table is used to influence the weighting of target classes +-- during model creation. +-- +CREATE TABLE glmc_sh_sample_clas_weights ( + target_value NUMBER, + prior_probability NUMBER); +INSERT INTO glmc_sh_sample_clas_weights VALUES (0,0.35); +INSERT INTO glmc_sh_sample_clas_weights VALUES (1,0.65); + +-- CREATE AND POPULATE A SETTINGS TABLE +-- +set echo off +CREATE TABLE glmc_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on + +-- The default classification algorithm is Naive Bayes. So override +-- this choice to GLM logistic regression using a settings table. +-- +BEGIN +-- Populate settings table + INSERT INTO glmc_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.algo_name, dbms_data_mining.algo_generalized_linear_model); + INSERT INTO glmc_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.glms_diagnostics_table_name, 'GLMC_SH_SAMPLE_DIAG'); + INSERT INTO glmc_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.prep_auto, dbms_data_mining.prep_auto_on); + -- Examples of other possible overrides are: + --(dbms_data_mining.glms_ridge_regression, dbms_data_mining.glms_ridge_reg_enable); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Build a new GLM Model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'GLMC_SH_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 'mining_data_build_v', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + settings_table_name => 'glmc_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'GLMC_SH_CLAS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'GLMC_SH_CLAS_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Global statistics +SELECT * + FROM TABLE(dbms_data_mining.get_model_details_global('GLMC_SH_Clas_sample')) +ORDER BY global_detail_name; + +-- We see from the global details that the covariance matrix was invalid: +-- VALID_COVARIANCE_MATRIX is 0 +-- As a result we only get a limited set of diagnostics, a sample of which +-- are shown below. +-- +-- Another important consequence of an invalid covariance matrix is that +-- the model cannot predict confidence bounds - i.e. the result of +-- PREDICTION_BOUNDS function in a SQL query is NULL. +-- +-- We also note that RIDGE REGRESSION has been enabled. It may happen that +-- the ridge regression model built on multicollinear predictors is better +-- than a non-ridge model built on a subset of the predictors where the +-- multicollinearity has been reduced sufficiently to produce a valid +-- covariance matrix. +-- + +-- Coefficient statistics +SET line 120 +column class format a20 +column attribute_name format a20 +column attribute_subname format a20 +column attribute_value format a20 + +SELECT * + FROM (SELECT * + FROM TABLE(dbms_data_mining.get_model_details_glm( + 'GLMC_SH_Clas_sample')) + ORDER BY class, attribute_name, attribute_value) + WHERE ROWNUM < 11; + +-- Row diagnostics +SELECT * + FROM (SELECT * + FROM glmc_sh_sample_diag + ORDER BY case_id) + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- +-- The queries shown below demonstrate the use of new SQL data mining functions +-- along with analytic functions to compute the various test metrics. +-- +-- Modelname: glmc_sh_clas_sample +-- Target attribute: affinity_card +-- Positive target value: 1 +-- (Change as appropriate for a different example) + +-- Compute CONFUSION MATRIX +-- +-- This query demonstates how to generate a confusion matrix using the new +-- SQL prediction functions for scoring. The returned columns match the +-- schema of the table generated by COMPUTE_CONFUSION_MATRIX procedure. +-- +SELECT affinity_card AS actual_target_value, + PREDICTION(glmc_sh_clas_sample USING *) AS predicted_target_value, + COUNT(*) AS value + FROM mining_data_test_v + GROUP BY affinity_card, PREDICTION(glmc_sh_clas_sample USING *) + ORDER BY 1, 2; + +-- Compute ACCURACY +-- +column accuracy format 9.99 + +SELECT SUM(correct)/COUNT(*) AS accuracy + FROM (SELECT DECODE(affinity_card, + PREDICTION(glmc_sh_clas_sample USING *), 1, 0) AS correct + FROM mining_data_test_v); + +-- Compute AUC (Area Under the roc Curve) +-- (See notes on ROC Curve and AUC computation in dmsvcdem.sql) +-- +column auc format 9.99 +WITH +pos_prob_and_counts AS ( +SELECT PREDICTION_PROBABILITY(glmc_sh_clas_sample, 1 USING *) pos_prob, + DECODE(affinity_card, 1, 1, 0) pos_cnt + FROM mining_data_test_v +), +tpf_fpf AS ( +SELECT pos_cnt, + SUM(pos_cnt) OVER (ORDER BY pos_prob DESC) / + SUM(pos_cnt) OVER () tpf, + SUM(1 - pos_cnt) OVER (ORDER BY pos_prob DESC) / + SUM(1 - pos_cnt) OVER () fpf + FROM pos_prob_and_counts +), +trapezoid_areas AS ( +SELECT 0.5 * (fpf - LAG(fpf, 1, 0) OVER (ORDER BY fpf, tpf)) * + (tpf + LAG(tpf, 1, 0) OVER (ORDER BY fpf, tpf)) area + FROM tpf_fpf + WHERE pos_cnt = 1 + OR (tpf = 1 AND fpf = 1) +) +SELECT SUM(area) auc + FROM trapezoid_areas; + +----------------------------------------------------------------------- +-- BUILD THE NEW MODEL +----------------------------------------------------------------------- + +-- Further analysis (i.e. inspecting data for constants, correlations) +-- showed that excluding the columns PRINTER_SUPPLIES, CUST_INCOME_level and +-- BOOKKEEPING_APPLICATION avoid singularities in the data that lead to +-- the invalid covariance matrix. For example, PRINTER_SUPPLIES has a +-- constant 1 as the value in all rows, and the other two columns were +-- found to be strongly correlated with yet another column. + +-- So, in order to demo a full set of diagnostics, we create a new view +-- that excludes the problematic columns, and build a new model against +-- this training data. + +-- Cleanup diagnostics table +BEGIN EXECUTE IMMEDIATE 'DROP TABLE glmc_sh_sample_diag'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Cleanup old build view +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_build_v2'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- CREATE a view that excludes columns PRINTER_SUPPLIES, CUST_INCOME_level +-- and BOOKKEEPING_APPLICATION +CREATE VIEW mining_data_build_v2 AS +SELECT CUST_id, CUST_gender, age, CUST_MARITAL_status, COUNTRY_name, + education, occupation, HOUSEHOLD_size, YRS_residence, AFFINITY_card, + BULK_PACK_diskettes, FLAT_PANEL_monitor, HOME_THEATER_package, + Y_BOX_games, OS_DOC_SET_kanji + FROM mining_data_build_v; + +--------------------- +-- CREATE A NEW MODEL +-- +-- Cleanup old model with the same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('GLMC_SH_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Build a new GLM Model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'GLMC_SH_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 'mining_data_build_v2', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + settings_table_name => 'glmc_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'GLMC_SH_CLAS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'GLMC_SH_CLAS_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Global statistics +SELECT * + FROM TABLE(dbms_data_mining.get_model_details_global('GLMC_SH_Clas_sample')) +ORDER BY global_detail_name; + +-- Coefficient statistics +SET line 120 +column class format a20 +column attribute_name format a20 +column attribute_subname format a20 +column attribute_value format a20 + +SELECT * + FROM (SELECT * + FROM TABLE(dbms_data_mining.get_model_details_glm( + 'GLMC_SH_Clas_sample')) + ORDER BY class, attribute_name, attribute_value) + WHERE ROWNUM < 11; + +-- Row diagnostics +SELECT * + FROM (SELECT * + FROM glmc_sh_sample_diag + ORDER BY case_id) + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- TEST THE NEW MODEL +----------------------------------------------------------------------- +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- +-- The queries shown below demonstrate the use of new SQL data mining functions +-- along with analytic functions to compute various test metrics. +-- +-- Modelname: glmc_sh_clas_sample +-- Target attribute: affinity_card +-- Positive target value: 1 +-- (Change these as appropriate for a different example) + +-- Compute CONFUSION MATRIX +-- +-- This query demonstates how to generate a confusion matrix using the new +-- SQL prediction functions for scoring. The returned columns match the +-- schema of the table generated by COMPUTE_CONFUSION_MATRIX procedure. +-- +SELECT affinity_card AS actual_target_value, + PREDICTION(glmc_sh_clas_sample USING *) AS predicted_target_value, + COUNT(*) AS value + FROM mining_data_test_v + GROUP BY affinity_card, PREDICTION(glmc_sh_clas_sample USING *) + ORDER BY 1, 2; + +-- Compute ACCURACY +-- +column accuracy format 9.99 + +SELECT SUM(correct)/COUNT(*) AS accuracy + FROM (SELECT DECODE(affinity_card, + PREDICTION(glmc_sh_clas_sample USING *), 1, 0) AS correct + FROM mining_data_test_v); + +-- Compute AUC (Area Under the roc Curve) +-- +-- See notes on ROC Curve and AUC computation above +-- +column auc format 9.99 +WITH +pos_prob_and_counts AS ( +SELECT PREDICTION_PROBABILITY(glmc_sh_clas_sample, 1 USING *) pos_prob, + DECODE(affinity_card, 1, 1, 0) pos_cnt + FROM mining_data_test_v +), +tpf_fpf AS ( +SELECT pos_cnt, + SUM(pos_cnt) OVER (ORDER BY pos_prob DESC) / + SUM(pos_cnt) OVER () tpf, + SUM(1 - pos_cnt) OVER (ORDER BY pos_prob DESC) / + SUM(1 - pos_cnt) OVER () fpf + FROM pos_prob_and_counts +), +trapezoid_areas AS ( +SELECT 0.5 * (fpf - LAG(fpf, 1, 0) OVER (ORDER BY fpf, tpf)) * + (tpf + LAG(tpf, 1, 0) OVER (ORDER BY fpf, tpf)) area + FROM tpf_fpf + WHERE pos_cnt = 1 + OR (tpf = 1 AND fpf = 1) +) +SELECT SUM(area) auc + FROM trapezoid_areas; + +-- Judging from the accuracy and AUC, the ridge regression model is +-- marginally superior to the model produced on the reduced predictor set. + +-------------------------------------------------------------------------- +-- SCORE DATA +-------------------------------------------------------------------------- + +-- now that the model has a valid covariance matrix, it is possible +-- to obtain confidence bounds. +SELECT * + FROM (SELECT CUST_ID, + PREDICTION(GLMC_SH_Clas_sample USING *) pr, + PREDICTION_PROBABILITY(GLMC_SH_Clas_sample USING *) pb, + PREDICTION_BOUNDS(GLMC_SH_Clas_sample USING *).lower pl, + PREDICTION_BOUNDS(GLMC_SH_Clas_sample USING *).upper pu + FROM mining_data_apply_v + ORDER BY CUST_ID) + WHERE ROWNUM < 11 +ORDER BY CUST_ID; diff --git a/dmglcdemo.java b/dmglcdemo.java new file mode 100644 index 0000000..6b48d37 --- /dev/null +++ b/dmglcdemo.java @@ -0,0 +1,968 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmglcdemo.java +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; + +import java.sql.Statement; + +import java.text.DecimalFormat; + +import java.text.MessageFormat; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; + +import java.util.Map; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.classification.ClassificationApplySettings; +import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.supervised.classification.ClassificationTestMetricOption; +import javax.datamining.supervised.classification.ClassificationTestMetrics; +import javax.datamining.supervised.classification.ClassificationTestMetricsTask; +import javax.datamining.supervised.classification.ClassificationTestMetricsTaskFactory; +import javax.datamining.supervised.classification.ClassificationTestTaskFactory; +import javax.datamining.supervised.classification.ConfusionMatrix; +import javax.datamining.supervised.classification.Lift; +import javax.datamining.supervised.classification.ReceiverOperatingCharacterics; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; + +import javax.datamining.task.apply.DataSetApplyTaskFactory; + +import oracle.dmt.jdm.algorithm.glm.OraGLMClassificationSettings; +import oracle.dmt.jdm.algorithm.glm.OraGLMSettingsFactory; +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.modeldetail.glm.OraGLMModelDetail; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.supervised.classification.OraClassificationSettings; +import oracle.dmt.jdm.supervised.classification.OraLift; +import oracle.dmt.jdm.task.OraBuildTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.OraExpressionTransform; +import oracle.dmt.jdm.transform.OraTransformationFactory; +import oracle.dmt.jdm.transform.OraTransformationSequence; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformImpl; +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmsvcdemo.java +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using Support Vector Machines (SVM) +* algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* How to predict whether a customer responds or not to the new affinity card +* program using a classifier based on SVM algorithm? +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created in the user +* schema using CUSTOMERS, COUNTRIES, and SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics and purchasing +* details for predicting response for the new affinity card program. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* 1. Missing Value treatment for Predictors in Build, Test, and Apply data +* +* "Missing Value" here implies "Missing at Random" values, that is, +* there is no pattern to the missing data, a NULL value does not have a +* special meaning, and there is no correlation either direct or indirect +* with the target or other predictor values. +* +* Missing value imputation is recommended when the fraction of missing +* at random values is high compared to the overall attribute value set. +* +* Contrast this with a "sparse" dataset - where a NULL value for +* an attribute encodes a zero/non-present. Typical examples of domains +* with sparse data are market basket and text mining. Missing value +* imputation should not be used on sparse data. By default, SVM +* interprets all NULL values for a given attribute as "sparse". +* +* Based on the business problem, one should designate the NULL value +* for a given attribute to be "missing at random" or "sparse". For +* example, a NULL value for AGE in demographic data can be missing +* at random if omitting this information is a random occurrence. +* In contrast, a shopping cart record with NULL values for certain +* items is usually considered sparse - because a customer cannot +* buy the entire inventory of items in a store. +* +* Here we are showing a simple approach to missing value treatment: +* +* 1.1. Compute the mean for numerical attributes, and mode for +* categoricals. Store them away in a table for use with +* Test and Apply data. +* +* 1.2. Replace the NULLs in the build, and test and apply, data +* with the computed mean (for numerical), mode (for categorical). +* +* 2. Outlier/Clipping Treatment for Predictors for Build data +* +* For SVM, we recommended that the data be normalized (individual +* attributes need to be on a similar scale) to achieve faster +* convergence of model builds and more accurate models. Large outliers +* in individual attributes can result in sub-optimal normalization +* output and sub-optimal models. Note that outlier/clipping treatment would +* be also beneficial for algorithms that use equi-width-binning +* (e.g., O-Cluster) since outliers in the data would produce sub-optimal bin +* boundaries. +* +* Here we winsorize the tail elements of the data as a preparatory step to +* normalization. +* +* We recommend the use of winsorizing to reduce the influence of outliers on +* the normalization computation. The normalization parameters are computed +* on the winsorized data. Once the normalization parameters are computed, +* they can be used directly on the original data. Winsorizing is not needed +* at test and apply time - it only affects the specification of the +* normalization parameters. +* +* 3. Normalize Predictors in Build, Test, and Apply data, unlike Regression +* using SVM, the target attribute is NOT normalized. +* +* The PrepareData() method in this demo program illustrates the preparation of the +* build, test, and apply data. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification model using SVM algorithm. +* +* Test Model: +* Classification models' performance can be evaluated by computing test +* metrics like accuracy, confusion matrix, lift and ROC. The testModel() or +* computeTestMetrics() method illustrates how to perform a test operation to +* compute various metrics. +* +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification models. The applyModel() method illustrates how to +* predict the customer response for an affinity card program. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic Java api imports + + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using Support Vector Machines (SVM) +* algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* How to predict whether a customer responds or not to the new affinity card +* program using a classifier based on SVM algorithm? +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created in the user +* schema using CUSTOMERS, COUNTRIES, and SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics and purchasing +* details for predicting response for the new affinity card program. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* 1. Missing Value treatment for Predictors in Build, Test, and Apply data +* +* "Missing Value" here implies "Missing at Random" values, that is, +* there is no pattern to the missing data, a NULL value does not have a +* special meaning, and there is no correlation either direct or indirect +* with the target or other predictor values. +* +* Missing value imputation is recommended when the fraction of missing +* at random values is high compared to the overall attribute value set. +* +* Contrast this with a "sparse" dataset - where a NULL value for +* an attribute encodes a zero/non-present. Typical examples of domains +* with sparse data are market basket and text mining. Missing value +* imputation should not be used on sparse data. By default, SVM +* interprets all NULL values for a given attribute as "sparse". +* +* Based on the business problem, one should designate the NULL value +* for a given attribute to be "missing at random" or "sparse". For +* example, a NULL value for AGE in demographic data can be missing +* at random if omitting this information is a random occurrence. +* In contrast, a shopping cart record with NULL values for certain +* items is usually considered sparse - because a customer cannot +* buy the entire inventory of items in a store. +* +* Here we are showing a simple approach to missing value treatment: +* +* 1.1. Compute the mean for numerical attributes, and mode for +* categoricals. Store them away in a table for use with +* Test and Apply data. +* +* 1.2. Replace the NULLs in the build, and test and apply, data +* with the computed mean (for numerical), mode (for categorical). +* +* 2. Outlier/Clipping Treatment for Predictors for Build data +* +* For SVM, we recommended that the data be normalized (individual +* attributes need to be on a similar scale) to achieve faster +* convergence of model builds and more accurate models. Large outliers +* in individual attributes can result in sub-optimal normalization +* output and sub-optimal models. Note that outlier/clipping treatment would +* be also beneficial for algorithms that use equi-width-binning +* (e.g., O-Cluster) since outliers in the data would produce sub-optimal bin +* boundaries. +* +* Here we winsorize the tail elements of the data as a preparatory step to +* normalization. +* +* We recommend the use of winsorizing to reduce the influence of outliers on +* the normalization computation. The normalization parameters are computed +* on the winsorized data. Once the normalization parameters are computed, +* they can be used directly on the original data. Winsorizing is not needed +* at test and apply time - it only affects the specification of the +* normalization parameters. +* +* 3. Normalize Predictors in Build, Test, and Apply data, unlike Regression +* using SVM, the target attribute is NOT normalized. +* +* The PrepareData() method in this demo program illustrates the preparation of the +* build, test, and apply data. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification model using SVM algorithm. +* +* Test Model: +* Classification models' performance can be evaluated by computing test +* metrics like accuracy, confusion matrix, lift and ROC. The testModel() or +* computeTestMetrics() method illustrates how to perform a test operation to +* compute various metrics. +* +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification models. The applyModel() method illustrates how to +* predict the customer response for an affinity card program. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Java Data Mining (JDM) standard api imports +// Oracle Java Data Mining (JDM) implemented api imports + +public class dmglcdemo extends Object { + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClassificationSettingsFactory m_clasFactory; + private static OraGLMSettingsFactory m_glmcFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClassificationTestTaskFactory m_testFactory; + private static ClassificationApplySettingsFactory m_applySettingsFactory; + private static ClassificationTestMetricsTaskFactory m_testMetricsTaskFactory; + private static OraTransformationFactory m_xformFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.##"); + // Global data members + private static boolean m_displayModelDetails = false; + private static boolean m_displayTestMetricsDetails = false; + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmglcdemo "); + System.out.println(" or: java dmglcdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build a model with supplied prior probability + buildModel(); + // 6. Test model - To compute accuracy and confusion matrix, lift result + // and ROC for the model from an apply output data. + // Please see dnnbdemo.java to see how to test the model + // with a test input data and cost matrix. In SVM, we + // recommend that any known costs be provided to the + // algorithm during build via the prior mechanism. + computeTestMetrics(); + // 7. Apply the model + applyModel(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { } // Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_clasFactory = (ClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationSettings"); + m_glmcFactory = (OraGLMSettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.algorithm.glm.OraGLMSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_testFactory = (ClassificationTestTaskFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationTestTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = (ClassificationApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationApplySettings"); + m_testMetricsTaskFactory = (ClassificationTestMetricsTaskFactory) m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationTestMetricsTask"); + m_xformFactory = (OraTransformationFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.OraTransformation" ); + } + + /** + * This method illustrates how to build mining model using + * MINING_DATA_BUILD_V dataset and classification settings with + * SVM algorithm. + * + * By default SVM algorithm chooses an kernel type automatically. This + * choice can be overriden by the user. Linear kernel is preferred high + * dimensional data, and Gaussian kernel for low dimensional data. Here we use + * linear kernel to demonstrate the getModelDetail() API, which applies only + * for models. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("glmcBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + //Create GLMC algorithm settings + OraGLMClassificationSettings glmcAlgo = m_glmcFactory.createGLMClassificationSettings(); + glmcAlgo.setDiagnosticsTableName("GLMC_DIAGNOSTICS_TABLE_JDM"); + glmcAlgo.setReferenceCategory(new Integer(1)); + + //Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(glmcAlgo); + buildSettings.setTargetAttributeName("AFFINITY_CARD"); + ((OraBuildSettings)buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject("glmcBuildSettings_jdm", buildSettings, true); + + //Create TransformationSequence + OraExpressionTransform exprXform = m_xformFactory.createExpressionTransform(); + //Exclude PRINTER_SUPPLIES, CUST_INCOME_LEVEL and BOOKKEEPING_APPLICATION + //to avoid singularities in the data that lead to invalid covariance matrix. + //(When expression is specified as null those attributes will be excluded) + exprXform.addAttributeExpression("PRINTER_SUPPLIES", null, null); + exprXform.addAttributeExpression("CUST_INCOME_LEVEL", null, null); + exprXform.addAttributeExpression("BOOKKEEPING_APPLICATION", null, null); + //Output view can be specified a null in this case, because we are + //not intended to create a view but embed the expression transformations + //with the model + OraTransformationSequence xformSeq = m_xformFactory.createTransformationSequence( + "MINING_DATA_BUILD_V", exprXform, null ); + m_dmeConn.saveObject("glmcTSExcludeAttrs_jdm", xformSeq, true); + + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "glmcBuildData_jdm", //Build data specification + "glmcBuildSettings_jdm", //Mining function settings name + "glmcModel_jdm" //Mining model name + ); + buildTask.setDescription("glmcBuildTask_jdm"); + //Specify expression transformations that are defined to exclude attributes + //as an embedded transformation to the model build + ((OraBuildTask)buildTask).setTransformationSequenceName("glmcTSExcludeAttrs_jdm"); + executeTask(buildTask, "glmcBuildTask_jdm"); + //4. Restore the model from the DME and explore the details of the model + ClassificationModel model = + (ClassificationModel)m_dmeConn.retrieveObject( + "glmcModel_jdm", NamedObject.model); + // Display model build settings + ClassificationSettings retrievedBuildSettings = + (ClassificationSettings)model.getBuildSettings(); + if(buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "glmcBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + displayGLMCModelDetails((Model)model); + } + + + /** + * This method illustrates how to compute test metrics using + * an apply output table that has actual and predicted target values. Here + * apply operation is done on MINING_DATA_TEST_V dataset which creates + * an apply output table with actual and predicted target values. Using + * ClassificationTestMetricsTask, test metrics are computed. This produces + * the same test metrics results as ClassificationTestTask. + * + * @exception JDMException if model test failed + */ + public static void computeTestMetrics() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using apply output table ---"); + System.out.println("---------------------------------------------------"); + // 1. Do the apply on test data to create an apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_TEST_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "glmcTestApplyData_jdm", applyData, true ); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + HashMap srcDestMap = new HashMap(); + srcDestMap.put("AFFINITY_CARD", "AFFINITY_CARD"); + clasAS.setSourceDestinationMap( srcDestMap ); + m_dmeConn.saveObject( "glmcTestApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "glmcTestApplyData_jdm", "glmcModel_jdm", + "glmcTestApplySettings_jdm", + "GLMC_TEST_APPLY_OUTPUT_JDM"); + if(executeTask(applyTask, "glmcTestApplyTask_jdm")) { + // 4. Generate test metrics on the above new created apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyOutputData = m_pdsFactory.create( + "GLMC_TEST_APPLY_OUTPUT_JDM", false ); + applyOutputData.addAttribute( pa ); + m_dmeConn.saveObject( "glmcTestApplyOutput_jdm", applyOutputData, true ); + // 5. Create a ClassificationTestMetricsTask + ClassificationTestMetricsTask testMetricsTask = + m_testMetricsTaskFactory.create( "glmcTestApplyOutput_jdm", // apply output data used as input + "AFFINITY_CARD", // actual target column + "PREDICTION", // predicted target column + "svcComputeTestMetrics_jdm" // test metrics result name + ); + testMetricsTask.computeMetric( // enable confusion matrix computation + ClassificationTestMetricOption.confusionMatrix, true ); + testMetricsTask.computeMetric( // enable lift computation + ClassificationTestMetricOption.lift, true ); + testMetricsTask.computeMetric( // enable ROC computation + ClassificationTestMetricOption.receiverOperatingCharacteristics, true ); + testMetricsTask.setPositiveTargetValue( new Integer(1) ); + testMetricsTask.setNumberOfLiftQuantiles( 10 ); + testMetricsTask.setPredictionRankingAttrName( "PROBABILITY" ); + // 6. Store & execute the task + boolean isTaskSuccess = executeTask(testMetricsTask, "glmcTestMetricsTask_jdm"); + if( isTaskSuccess ) { + // 7. Restore & display test metrics + ClassificationTestMetrics testMetrics = + (ClassificationTestMetrics)m_dmeConn.retrieveObject( + "svcComputeTestMetrics_jdm", + NamedObject.testMetrics ); + // Display classification test metrics + displayTestMetricDetails(testMetrics); + } + } + } + + /** + * This method illustrates how to apply the mining model on the + * GLMC_NORM_DATA_APPLY_JDM dataset to predict customer + * response. After completion of the task, the apply output table with the + * predicted results is created at the user specified location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_APPLY_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "glmcApplyData_jdm", applyData, true ); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "glmcApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "glmcApplyData_jdm", "glmcModel_jdm", + "glmcApplySettings_jdm", "GLMC_APPLY_OUTPUT_JDM"); + executeTask(applyTask, "glmcApplyTask_jdm"); + // 4. Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + displayTable("GLMC_APPLY_OUTPUT_JDM", + "where ROWNUM < 11", + "order by CUST_ID"); + } + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException { + boolean isTaskSuccess = false; + ((OraTask)taskObj).overwriteOutput(true); + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful."); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() ); + } + return isTaskSuccess; + } + + private static void displayBuildSettings( + ClassificationSettings clasSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " model build settings object:"); + String objName = clasSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = clasSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = clasSettings.getCreationDate(); + String creator = clasSettings.getCreatorInfo(); + String targetAttrName = clasSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = clasSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: clasSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = clasSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: clasSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + + try { + Map map = ((OraClassificationSettings)clasSettings).getTargetWeightsMap(); + if(map != null) System.out.println("Target Weights Map: " + map.toString()); + } catch(Exception jdmExp) + { + System.out.println("Failure: clasSettings.getTargetWeightsMap()throws exception"); + jdmExp.printStackTrace(); + } + + // List of GLM algorithm settings availabe in linear kernel + String diagnsticsTableName = ((OraGLMClassificationSettings)algoSettings).getDiagnosticsTableName(); + System.out.println("Diagnostics Table Name: " + diagnsticsTableName); + + Object refCategory = ((OraGLMClassificationSettings)algoSettings).getReferenceCategory(); + System.out.println("Reference category: " + refCategory); + + boolean useRidge = ((OraGLMClassificationSettings)algoSettings).useRidgeRegression(); + System.out.println("Use Ridge Regression: " + useRidge); + + } + + /** + * This method displayes GLMC model signature. + * + * @param model model object + * @exception JDMException if failed to retrieve model signature + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + /** + * This method displayes GLMC model details. The coefficient indicates the + * relative influence of a given (attribute, value) pair on the target value. + * A negative coefficient value indicates a negative influence. + * + * @param glmcModelDetails svm classification model details object + * @exception JDMException if failed to retrieve model details + */ + public static void displayGLMCModelDetails( + Model model) throws JDMException + { + // Obtains model details + OraGLMModelDetail glmcModelDetails = + (OraGLMModelDetail)model.getModelDetail(); + //Get computer high-level statitics of the model + Map glblDetails = glmcModelDetails.getGlobalDetails(); + if(m_displayModelDetails) { + System.out.println("Global Model details:"); + System.out.println(glblDetails.toString()); + } + //Get all attribute coefficients without any filters + ResultSet rsGLM = glmcModelDetails.getAttributeCoefficients(null, null, null, null); + //Display first coeficcient record + try { + rsGLM.next(); + //To display model details enable explicitely by setting m_displayModelDetails to true + if(m_displayModelDetails) { + System.out.println("Target value " + rsGLM.getString("CLASS") ); + System.out.println("Attribute name " + rsGLM.getString("ATTRIBUTE_NAME")); + System.out.println("Attribute value " + rsGLM.getString("ATTRIBUTE_VALUE")); + System.out.println("Coefficient " + rsGLM.getDouble("COEFFICIENT")); + System.out.println("Standard Error " + rsGLM.getDouble("STD_ERROR")); + System.out.println("Test static " + rsGLM.getDouble("TEST_STATISTIC")); + System.out.println("P Value " + rsGLM.getDouble("P_VALUE")); + System.out.println("Variance Inflation Factor " + rsGLM.getDouble("VIF")); + System.out.println("Std. Coefficient " + rsGLM.getDouble("STD_COEFFICIENT")); + System.out.println("Lower Coefficient Limit " + rsGLM.getDouble("LOWER_COEFF_LIMIT")); + System.out.println("Upper Coefficient Limit " + rsGLM.getDouble("UPPER_COEFF_LIMIT")); + System.out.println("Exp Coefficient " + rsGLM.getDouble("EXP_COEFFICIENT")); + System.out.println("Exp Lower Coefficient " + rsGLM.getDouble("EXP_LOWER_COEFF_LIMIT")); + System.out.println("Exp Upper Coefficient " + rsGLM.getDouble("EXP_UPPER_COEFF_LIMIT")); + } + } catch(SQLException anyExp) { + anyExp.printStackTrace(); + } + //After using the details must close the statement associated with the resultset and the resultset + Statement stmtGLM = null; + try { + stmtGLM = rsGLM.getStatement(); + rsGLM.close(); + stmtGLM.close(); + } catch(SQLException anyExp) { + + } finally { + try { if(rsGLM != null) rsGLM.close(); } catch(SQLException sqlExp) {} + } + } + + /** + * Display classification test metrics object + * + * @param testMetrics classification test metrics object + * @exception JDMException if failed to retrieve test metric details + */ + public static void displayTestMetricDetails( + ClassificationTestMetrics testMetrics) throws JDMException + { + // Retrieve Oracle SVMC model test metrics deatils extensions + // Test Metrics Name + System.out.println("Test Metrics Name = " + testMetrics.getName()); + // Model Name + System.out.println("Model Name = " + testMetrics.getModelName()); + // Test Data Name + System.out.println("Test Data Name = " + testMetrics.getTestDataName()); + // Accuracy + System.out.println("Accuracy = " + m_df.format(testMetrics.getAccuracy().doubleValue())); + // Confusion Matrix + ConfusionMatrix confusionMatrix = testMetrics.getConfusionMatrix(); + Collection categories = confusionMatrix.getCategories(); + Iterator xIterator = categories.iterator(); + System.out.println("Confusion Matrix: Accuracy = " + m_df.format(confusionMatrix.getAccuracy())); + System.out.println("Confusion Matrix: Error = " + m_df.format(confusionMatrix.getError())); + if(m_displayTestMetricsDetails) + System.out.println("Confusion Matrix:( Actual, Prection, Value )"); + MessageFormat mf = new MessageFormat(" ( {0}, {1}, {2} )"); + String[] vals = new String[3]; + while(xIterator.hasNext()) + { + Object actual = xIterator.next(); + vals[0] = actual.toString(); + Iterator yIterator = categories.iterator(); + while(yIterator.hasNext()) + { + Object predicted = yIterator.next(); + vals[1] = predicted.toString(); + long number = confusionMatrix.getNumberOfPredictions(actual, predicted); + vals[2] = Long.toString(number); + if(m_displayTestMetricsDetails) + System.out.println(mf.format(vals)); + } + } + // Lift + Lift lift = testMetrics.getLift(); + String targetAttrName = lift.getTargetAttributeName(); + Object positiveTargetVal = lift.getPositiveTargetValue(); + long totalCases = lift.getTotalCases(); + long totalPositiveCases = lift.getTotalPositiveCases(); + int numberOfQuantiles = lift.getNumberOfQuantiles(); + if(m_displayTestMetricsDetails) { + System.out.println("Lift Details:"); + System.out.println("Lift: Target Attribute Name = " + targetAttrName); + System.out.println("Lift: Positive Target Value = " + positiveTargetVal); + System.out.println("Lift: Total Cases = " + totalCases); + System.out.println("Lift: Total Positive Cases = " + totalPositiveCases); + System.out.println("Lift: Number Of Quantiles = " + numberOfQuantiles); + System.out.println("Lift: ( QUANTILE_NUMBER, TOTAL_CASES, QUANTILE_PERCENT_SIZE, POSITIVE_CASES, NEGATIVE_CASES, PROBABILITY_THRESHOLD, LIFT, CUMULATIVE_LIFT, GAIN, CUMULATIVE_GAIN, TARGET_DENSITY, CUMULATIVE_TARGET_DENSITY)"); + } + MessageFormat mfLift = + new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10} )"); + + double[] totalCasesPerQuantile = ((OraLift)lift).getCases();//Total cases per quantile + double[] quantilePercentageSize = ((OraLift)lift).getPercentageSize();//Quantile pecentage size + double[] positiveCasesPerQuantile = ((OraLift)lift).getNumberOfPositiveCases();//Positive target cases per quantile + double[] negativeCasesPerQuantile = ((OraLift)lift).getNumberOfNegativeCases();//Negative target cases per quantile + double[] probabilityOrCostThresholdPerQuantile = ((OraLift)lift).getProbabilityOrCostThreshold();//Probability or cost threshold per quantile + double[] liftPerQuantile = ((OraLift)lift).getLift();//Lift values for all quantiles + double[] targetDensityPerQuantile = ((OraLift)lift).getTargetDensity();//Target densities per quantile + + double[] cumulativeLift = ((OraLift)lift).getCumulativeLift(); + double[] cumulativeGain = ((OraLift)lift).getCumulativeGain(); + double[] cumulativeTargetDensity = ((OraLift)lift).getCumulativeTargetDensity(); + + String[] messageParams = new String[11]; + + for (int iQuantile = 0; iQuantile < numberOfQuantiles; iQuantile++) + { + //Assign message parameters + messageParams[0] = Integer.toString(iQuantile+1); //QUANTILE_NUMBER + messageParams[1] = m_df.format(totalCasesPerQuantile[iQuantile]); //TOTAL_CASES + messageParams[2] = m_df.format(quantilePercentageSize[iQuantile]);//QUANTILE_PERCENT_SIZE + messageParams[3] = m_df.format(positiveCasesPerQuantile[iQuantile]); //POSITIVE_CASES + messageParams[4] = m_df.format(negativeCasesPerQuantile[iQuantile]); //NEGATIVE_CASES + messageParams[5] = m_df.format(probabilityOrCostThresholdPerQuantile[iQuantile]); //PROBABILITY_THRESHOLD + messageParams[6] = m_df.format(liftPerQuantile[iQuantile]); //LIFT + messageParams[7] = m_df.format(cumulativeLift[iQuantile]); //CUMULATIVE_LIFT + messageParams[8] = m_df.format(cumulativeGain[iQuantile]); //CUMULATIVE_GAIN + messageParams[9] = m_df.format(targetDensityPerQuantile[iQuantile]); //TARGET_DENSITY + messageParams[10] = m_df.format(cumulativeTargetDensity[iQuantile]); //CUMULATIVE_TARGET_DENSITY + if(m_displayTestMetricsDetails) + System.out.println(mfLift.format(messageParams)); + } + // ROC + ReceiverOperatingCharacterics roc = testMetrics.getROC(); + double areaUnderCurve = roc.getAreaUnderCurve(); + int nROCThresh = roc.getNumberOfThresholdCandidates(); + if(m_displayTestMetricsDetails) { + System.out.println("ROC Details:"); + System.out.println("ROC: Area Under Curve = " + m_df.format(areaUnderCurve)); + System.out.println("ROC: Number Of Threshold Candidates = " + nROCThresh); + System.out.println("ROC: ( INDEX, PROBABILITY, TRUE_POSITIVES, FALSE_NEGATIVES, FALSE_POSITIVES, TRUE_NEGATIVES, TRUE_POSITIVE_FRACTION, FALSE_POSITIVE_FRACTION )"); + } + MessageFormat mfROC = new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7} )"); + String[] rocVals = new String[8]; + for(int iROC=1; iROC <= nROCThresh; iROC++) + { + rocVals[0] = Integer.toString(iROC); //INDEX + rocVals[1] = m_df.format(roc.getProbabilityThreshold(iROC));//PROBABILITY + rocVals[2] = Long.toString(roc.getPositives(iROC, true));//TRUE_POSITIVES + rocVals[3] = Long.toString(roc.getNegatives(iROC, false));//FALSE_NEGATIVES + rocVals[4] = Long.toString(roc.getPositives(iROC, false));//FALSE_POSITIVES + rocVals[5] = Long.toString(roc.getNegatives(iROC, true));//TRUE_NEGATIVES + rocVals[6] = m_df.format(roc.getHitRate(iROC));//TRUE_POSITIVE_FRACTION + rocVals[7] = m_df.format(roc.getFalseAlarmRate(iROC));//FALSE_POSITIVE_FRACTION + if(m_displayTestMetricsDetails) + System.out.println(mfROC.format(rocVals)); + } + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while(rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + private static void clean() + { + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + //Drop prepared tables + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE GLMC_DIAGNOSTICS_TABLE_JDM PURGE"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop the model + try { + m_dmeConn.removeObject("glmcModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + } +} diff --git a/dmglrdem.sql b/dmglrdem.sql new file mode 100644 index 0000000..c925e45 --- /dev/null +++ b/dmglrdem.sql @@ -0,0 +1,346 @@ +Rem +Rem $Header: dmglrdem.sql 22-jan-2008.14:06:12 ramkrish Exp $ +Rem +Rem dmglrdem.sql +Rem +Rem Copyright (c) 2003, 2008, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmglrdem.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a regression model using GLM based on +Rem data in the SH (Sales History) schema in the RDBMS and +Rem demonstrates the use of SQL prediction functions to test +Rem the model and apply it to new data. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 01/22/08 - add prediction_bounds +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem bmilenov 05/08/07 - Change case_id column in row diagnostics table +Rem bmilenov 12/13/06 - Turn ADP on +Rem bmilenov 12/05/06 - Change row diagnostic query +Rem jyarmus 11/21/06 - Change ridge regression constant +Rem jyarmus 10/13/06 - drop diagnostics table prior to second model +Rem build +Rem jyarmus 10/12/06 - build with and without columns causing +Rem a singularity in covariance matrix +Rem bmilenov 10/04/06 - Remove multicolinear columns +Rem bmilenov 08/22/06 - Remove filtered view +Rem bmilenov 08/18/06 - Cleanup +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic, purchase, and affinity card membership data for a +-- set of customers, predict customer's age. Since age is a continuous +-- variable, this is a regression problem. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE DATA +----------------------------------------------------------------------- + +-- The data for this sample is composed from base tables in the SH Schema +-- (See Sample Schema Documentation) and presented through these views: +-- mining_data_build_v (build data) +-- mining_data_test_v (test data) +-- mining_data_apply_v (apply data) +-- (See dmsh.sql for view definitions). +-- +----------- +-- ANALYSIS +----------- +-- Data preparation for GLM is performed internally + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old model with same name (if any) +BEGIN + DBMS_DATA_MINING.DROP_MODEL('GLMR_SH_Regr_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE glmr_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Cleanup diagnostic table +BEGIN EXECUTE IMMEDIATE 'DROP TABLE glmr_sh_sample_diag'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +CREATE TABLE glmr_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); + +BEGIN +-- Populate settings table + INSERT INTO glmr_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.algo_name, dbms_data_mining.algo_generalized_linear_model); + INSERT INTO glmr_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.glms_diagnostics_table_name, 'GLMR_SH_SAMPLE_DIAG'); + INSERT INTO glmr_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.prep_auto, dbms_data_mining.prep_auto_on); + -- Examples of other possible overrides are: + --(dbms_data_mining.glms_ridge_regression, + -- dbms_data_mining.glms_ridge_reg_enable); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'GLMR_SH_Regr_sample', + mining_function => dbms_data_mining.regression, + data_table_name => 'mining_data_build_v', + case_id_column_name => 'cust_id', + target_column_name => 'age', + settings_table_name => 'glmr_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'GLMR_SH_REGR_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'GLMR_SH_REGR_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Global statistics +SELECT * + FROM TABLE(dbms_data_mining.get_model_details_global('GLMR_SH_Regr_sample')) +ORDER BY global_detail_name; + +-- We see from the global details that the covariance matrix was invalid: +-- VALID_COVARIANCE_MATRIX is 0 +-- As a result we only get a limited set of diagnostics, a sample of which +-- are shown below + +-- Coefficient statistics +SET line 120 +column class format a20 +column attribute_name format a20 +column attribute_subname format a20 +column attribute_value format a20 + +SELECT * + FROM (SELECT * + FROM TABLE(dbms_data_mining.get_model_details_glm( + 'GLMR_SH_Regr_sample')) + ORDER BY class, attribute_name, attribute_value) + WHERE ROWNUM < 11; + +-- Row diagnostics +SELECT * + FROM (SELECT * + FROM glmr_sh_sample_diag + ORDER BY case_id) + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- + +-- 1. Root Mean Square Error - Sqrt(Mean((x - x')^2)) +-- 2. Mean Absolute Error - Mean(|(x - x')|) +-- +column rmse format 9999.99 +column mae format 9999.99 +SELECT SQRT(AVG((A.pred - B.age) * (A.pred - B.age))) rmse, + AVG(ABS(a.pred - B.age)) mae + FROM (SELECT cust_id, prediction(GLMR_SH_Regr_sample using *) pred + FROM mining_data_test_v) A, + mining_data_test_v B + WHERE A.cust_id = B.cust_id; + +-- Further analysis showed that excluding the columns +-- PRINTER_SUPPLIES, CUST_INCOME_level and BOOKKEEPING_APPLICATION +-- avoid singularities in the data +-- that lead to the invalid covariance matrix. Below we create a new view +-- that excludes the problematic columns, thereby enabling computation of a +-- full set of diagnostics +-- (See notes in dmglcdem.sql) + +----------------------------------------------------------------------- +-- BUILD A NEW MODEL +----------------------------------------------------------------------- + +-- Cleanup old build view +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_build_v2'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- CREATE a view that excludes columns PRINTER_SUPPLIES, CUST_INCOME_level +-- and BOOKKEEPING_APPLICATION +CREATE VIEW mining_data_build_v2 AS +SELECT CUST_id, CUST_gender, age, CUST_MARITAL_status, COUNTRY_name, + education, occupation, HOUSEHOLD_size, YRS_residence, + AFFINITY_card, BULK_PACK_diskettes, FLAT_PANEL_monitor, + HOME_THEATER_package, Y_BOX_games, OS_DOC_SET_kanji + FROM mining_data_build_v; + +-- Cleanup diagnostic table +BEGIN EXECUTE IMMEDIATE 'DROP TABLE glmr_sh_sample_diag'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Cleanup old model with same name (if any) +BEGIN + DBMS_DATA_MINING.DROP_MODEL('GLMR_SH_Regr_sample'); +EXCEPTION WHEN OTHERS THEN + NULL; +END; +/ + +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'GLMR_SH_Regr_sample', + mining_function => dbms_data_mining.regression, + data_table_name => 'mining_data_build_v2', + case_id_column_name => 'cust_id', + target_column_name => 'age', + settings_table_name => 'glmr_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'GLMR_SH_REGR_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'GLMR_SH_REGR_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Global statistics +SELECT * + FROM TABLE(dbms_data_mining.get_model_details_global( + 'GLMR_SH_Regr_sample')) +ORDER BY global_detail_name; + +-- Coefficient statistics +SET line 120 +column class format a20 +column attribute_name format a20 +column attribute_subname format a20 +column attribute_value format a20 + +SELECT * + FROM (SELECT * + FROM TABLE(dbms_data_mining.get_model_details_glm( + 'GLMR_SH_Regr_sample')) + ORDER BY class, attribute_name, attribute_value) + WHERE ROWNUM < 11; + +-- Row diagnostics +SELECT * + FROM (SELECT * + FROM glmr_sh_sample_diag + ORDER BY case_id) + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- + +-- 1. Root Mean Square Error - Sqrt(Mean((x - x')^2)) +-- 2. Mean Absolute Error - Mean(|(x - x')|) +-- +column rmse format 9999.99 +column mae format 9999.99 +SELECT SQRT(AVG((A.pred - B.age) * (A.pred - B.age))) rmse, + AVG(ABS(a.pred - B.age)) mae + FROM (SELECT cust_id, prediction(GLMR_SH_Regr_sample using *) pred + FROM mining_data_test_v) A, + mining_data_test_v B + WHERE A.cust_id = B.cust_id; + +-- 3. Residuals +-- If the residuals show substantial variance between +-- the predicted value and the actual, you can consider +-- changing the algorithm parameters. +-- +SELECT TO_CHAR(ROUND(pred, 4)) prediction, residual + FROM (SELECT A.pred, (A.pred - B.age) residual + FROM (SELECT cust_id, prediction(GLMR_SH_Regr_sample using *) pred + FROM mining_data_test_v) A, + mining_data_test_v B + WHERE A.cust_id = B.cust_id + ORDER BY A.pred ASC) + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- SCORE NEW DATA +----------------------------------------------------------------------- + +-- now that the model has a valid covariance matrix, it is possible +-- to obtain confidence bounds. +SELECT * + FROM (SELECT CUST_ID, + PREDICTION(GLMR_SH_Regr_sample USING *) pr, + PREDICTION_BOUNDS(GLMR_SH_Regr_sample USING *).lower pl, + PREDICTION_BOUNDS(GLMR_SH_Regr_sample USING *).upper pu + FROM mining_data_apply_v + ORDER BY CUST_ID) + WHERE ROWNUM < 11 +ORDER BY CUST_ID; diff --git a/dmglrdemo.java b/dmglrdemo.java new file mode 100644 index 0000000..aff7f6d --- /dev/null +++ b/dmglrdemo.java @@ -0,0 +1,787 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmglmrdemo.java +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a regression problem using Support Vector Machines (GLM) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Given demographic, purchase, and affinity card membership data for a set of +* customers, predict customer's age. Since age is a continuous variable, this +* is a regression problem. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the +* previous affinity card programs. Data exploration and preparing the data is a +* common step before doing data mining. Here in this demo, the following views are +* created in the user schema using CUSTOMERS, COUNTRIES, and +* SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics, purchasing, +* and affinity card response details for predicting customer's age. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* 1. Missing Value treatment for Predictors in Build, Test, and Apply data +* See dmsvcdemo.java for a definition of missing values, and the steps to be +* taken for missing value imputation. GLM interprets all NULL values for a +* given attribute as "sparse". We skip missing values treatment in this demo. +* +* 2. Outlier/Clipping Treatment for Predictors for Build data +* See dmsvcdemo.java for discussion on outlier treatment. We skip outlier +* treatment in this demo. +* +* 3. Normalize Predictors in Build, Test, and Apply data. +* See dmsvcdemo.java for discussion on normalization treatment. The target is +* also normalized for GLM regression to achieve convergence of model builds +* with better performance. +* +* NOTE: AGE is the only predictor with continuous values in this dataset. +* +* The PrepareData() method in this demo program illustrates the preparation of the +* build, test, and apply data. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a regression model using GLM algorithm. +* +* Test Model: +* Regression models performance can be evaluated by computing different types +* of error rates. The testModel() or computeTestMetrics() method illustrates how +* to perform the test operation to compute various error rates. +* +* Apply Model: +* Predicting the target attribute values is the prime function of regression +* models. The applyModel() method illustrates how to predict the customer's age. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic Java api imports +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; + +import java.text.DecimalFormat; +import java.text.MessageFormat; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.regression.RegressionApplySettings; +import javax.datamining.supervised.regression.RegressionApplySettingsFactory; +import javax.datamining.supervised.regression.RegressionModel; +import javax.datamining.supervised.regression.RegressionSettings; +import javax.datamining.supervised.regression.RegressionSettingsFactory; +import javax.datamining.supervised.regression.RegressionTestMetrics; +import javax.datamining.supervised.regression.RegressionTestMetricsTask; +import javax.datamining.supervised.regression.RegressionTestMetricsTaskFactory; +import javax.datamining.supervised.regression.RegressionTestTask; +import javax.datamining.supervised.regression.RegressionTestTaskFactory; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; + + +import oracle.dmt.jdm.algorithm.glm.OraGLMClassificationSettings; +import oracle.dmt.jdm.algorithm.glm.OraGLMRegressionSettings; +import oracle.dmt.jdm.algorithm.glm.OraGLMSettingsFactory; +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.modeldetail.glm.OraGLMModelDetail; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.supervised.regression.OraRegressionApplySettings; +import oracle.dmt.jdm.supervised.regression.OraRegressionTestMetrics; +import oracle.dmt.jdm.task.OraBuildTask; +import oracle.dmt.jdm.transform.OraExpressionTransform; +import oracle.dmt.jdm.transform.OraTransformationFactory; +import oracle.dmt.jdm.transform.OraTransformationSequence; + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a regression problem using Support Vector Machines (GLM) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Given demographic, purchase, and affinity card membership data for a set of +* customers, predict customer's age. Since age is a continuous variable, this +* is a regression problem. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the +* previous affinity card programs. Data exploration and preparing the data is a +* common step before doing data mining. Here in this demo, the following views are +* created in the user schema using CUSTOMERS, COUNTRIES, and +* SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics, purchasing, +* and affinity card response details for predicting customer's age. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* 1. Missing Value treatment for Predictors in Build, Test, and Apply data +* See dmsvcdemo.java for a definition of missing values, and the steps to be +* taken for missing value imputation. GLM interprets all NULL values for a +* given attribute as "sparse". We skip missing values treatment in this demo. +* +* 2. Outlier/Clipping Treatment for Predictors for Build data +* See dmsvcdemo.java for discussion on outlier treatment. We skip outlier +* treatment in this demo. +* +* 3. Normalize Predictors in Build, Test, and Apply data. +* See dmsvcdemo.java for discussion on normalization treatment. The target is +* also normalized for GLM regression to achieve convergence of model builds +* with better performance. +* +* NOTE: AGE is the only predictor with continuous values in this dataset. +* +* The PrepareData() method in this demo program illustrates the preparation of the +* build, test, and apply data. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a regression model using GLM algorithm. +* +* Test Model: +* Regression models performance can be evaluated by computing different types +* of error rates. The testModel() or computeTestMetrics() method illustrates how +* to perform the test operation to compute various error rates. +* +* Apply Model: +* Predicting the target attribute values is the prime function of regression +* models. The applyModel() method illustrates how to predict the customer's age. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +public class dmglrdemo extends Object { +// Java Data Mining (JDM) standard api imports +// Oracle Java Data Mining (JDM) implemented api imports + + + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static RegressionSettingsFactory m_regrFactory; + private static OraGLMSettingsFactory m_glmrFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static RegressionTestTaskFactory m_testFactory; + private static RegressionApplySettingsFactory m_applySettingsFactory; + private static RegressionTestMetricsTaskFactory m_testMetricsTaskFactory; + private static OraTransformationFactory m_xformFactory = null; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.##"); + // Global data members + private static boolean m_displayModelDetails = false; + + public static void main( String args[] ) { + try { + if ( args.length != 3 ) { + System.out.println("Usage: java dmglrdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build a model + buildModel(); + // 5a. Test model - To compute different type of error rates for the + // model from a test input data. + testModel(); + // 5b. Test model - To compute different type of error rates for the + // model from an apply output data. + //computeTestMetrics(); + // 6. Apply the model + applyModel(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { }//Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_regrFactory = (RegressionSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionSettings"); + m_glmrFactory = (OraGLMSettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.algorithm.glm.OraGLMSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_testFactory = (RegressionTestTaskFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionTestTask"); + m_applySettingsFactory = (RegressionApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionApplySettings"); + m_testMetricsTaskFactory = (RegressionTestMetricsTaskFactory) m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionTestMetricsTask"); + m_xformFactory = (OraTransformationFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.OraTransformation" ); + } + + /** + * This method illustrates how to build mining model using + * GLMR_NORM_DATA_BUILD_JDM dataset and regression settings with + * GLM algorithm. + * + * By default GLM algorithm chooses a kernel type automatically. This + * choice can be overriden by the user. Linear kernel is preferred for high + * dimensional data, and Gaussian kernel for low dimensional data. Here we use + * Gaussian kernel in this demo. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("glmrBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // 2. Create & save Mining Function Settings + // Create GLMC algorithm settings + OraGLMRegressionSettings glmrAlgo = m_glmrFactory.createGLMRegressionSettings(); + glmrAlgo.setDiagnosticsTableName("GLMR_DIAGNOSTICS_TABLE_JDM"); + + //Create TransformationSequence + OraExpressionTransform exprXform = m_xformFactory.createExpressionTransform(); + //Exclude PRINTER_SUPPLIES, CUST_INCOME_LEVEL and BOOKKEEPING_APPLICATION + //to avoid singularities in the data that lead to invalid covariance matrix. + //(When expression is specified as null those attributes will be excluded) + exprXform.addAttributeExpression("PRINTER_SUPPLIES", null, null); + exprXform.addAttributeExpression("CUST_INCOME_LEVEL", null, null); + exprXform.addAttributeExpression("BOOKKEEPING_APPLICATION", null, null); + //Output view can be specified a null in this case, because we are + //not intended to create a view but embed the expression transformations + //with the model + OraTransformationSequence xformSeq = m_xformFactory.createTransformationSequence( + "MINING_DATA_BUILD_V", exprXform, null ); + m_dmeConn.saveObject("glmrTSExcludeAttrs_jdm", xformSeq, true); + + // Create RegressionSettings + RegressionSettings buildSettings = m_regrFactory.create(); + buildSettings.setAlgorithmSettings(glmrAlgo); + buildSettings.setTargetAttributeName("AGE"); + ((OraBuildSettings)buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject("glmrBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "glmrBuildData_jdm", //Build data specification + "glmrBuildSettings_jdm", //Mining function settings name + "glmrModel_jdm" //Mining model name + ); + buildTask.setDescription("glmrBuildTask_jdm"); + //Specify expression transformations that are defined to exclude attributes + //as an embedded transformation to the model build + ((OraBuildTask)buildTask).setTransformationSequenceName("glmrTSExcludeAttrs_jdm"); + executeTask(buildTask, "glmrBuildTask_jdm"); + // 4. Restore the model from the DME and explore the details of the model + RegressionModel model = + (RegressionModel)m_dmeConn.retrieveObject( + "glmrModel_jdm", NamedObject.model); + // Display model build settings + RegressionSettings retrievedBuildSettings = + (RegressionSettings)model.getBuildSettings(); + if(buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "glmrBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + // To display model details enable explicitely by setting m_displayModelDetails to true + displayGLMRModelDetails(model); + } + + /** + * This method illustrates how to test the mining model with the + * GLMR_NORM_DATA_TEST_JDM dataset using regression test task. After + * completion of the task, a regression test metrics object is created + * in the DMS. Regression test metrics object encapsulates + * different types of error rates. + * + * @exception JDMException if model test failed + */ + public static void testModel() + throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using test input table ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet testData = m_pdsFactory.create( + "MINING_DATA_TEST_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + testData.addAttribute( pa ); + m_dmeConn.saveObject( "glmrTestData_jdm", testData, true ); + // 2. Create, store & execute Test Task + RegressionTestTask testTask = m_testFactory.create( + "glmrTestData_jdm", "glmrModel_jdm", "glmrTestMetrics_jdm" ); + // 3. Store & execute the task + boolean isTaskSuccess = executeTask(testTask, "glmrTestTask_jdm"); + if( isTaskSuccess ) { + // 4. Restore & display test metrics + RegressionTestMetrics testMetrics = + (RegressionTestMetrics)m_dmeConn.retrieveObject( + "glmrTestMetrics_jdm", + NamedObject.testMetrics ); + // 5. Display regression test metrics + displayTestMetricDetails(testMetrics); + } + } + + /** + * This method illustrates how to compute test metrics using + * an apply output table that has actual and predicted target values. Here the + * apply operation is done on the GLMR_NORM_DATA_TEST_JDM dataset. It creates + * an apply output table with actual and predicted target values. Using + * RegressionTestMetricsTask test metrics are computed. This produces + * the same test metrics results as RegressionTestTask. + * + * @exception JDMException if model test failed + */ + public static void computeTestMetrics() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using apply output table ---"); + System.out.println("---------------------------------------------------"); + // 1. Do the apply on test data to create an apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create( "MINING_DATA_TEST_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "glmrTestApplyData_jdm", applyData, true ); + // 2. Create & save RegressionApplySettings + RegressionApplySettings regreAS = m_applySettingsFactory.create(); + HashMap sourceAttrMap = new HashMap(); + sourceAttrMap.put( "AGE", "AGE" ); + regreAS.setSourceDestinationMap( sourceAttrMap ); + m_dmeConn.saveObject( "glmrTestApplySettings_jdm", regreAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "glmrTestApplyData_jdm", "glmrModel_jdm", "glmrTestApplySettings_jdm", + "GLMR_TEST_APPLY_OUTPUT_JDM"); + if(executeTask(applyTask, "glmrTestApplyTask_jdm")) { + // 4. Generate test metrics on the above new created apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyOutputData = m_pdsFactory.create( + "GLMR_TEST_APPLY_OUTPUT_JDM", false ); + applyOutputData.addAttribute( pa ); + m_dmeConn.saveObject( "glmrTestApplyOutput_jdm", applyOutputData, true ); + // 5. Create a RegressionTestMetricsTask + RegressionTestMetricsTask testMetricsTask = + m_testMetricsTaskFactory.create( "glmrTestApplyOutput_jdm", // apply output data used as input + "AGE", // actual target column + "PREDICTION", // predicted target column + "glrComputeTestMetrics_jdm" // test metrics result name + ); + // 6. Store & execute the task + boolean isTaskSuccess = executeTask(testMetricsTask, "glmrTestMetricsTask_jdm"); + if( isTaskSuccess ) { + // 7. Restore & display test metrics + RegressionTestMetrics testMetrics = + (RegressionTestMetrics)m_dmeConn.retrieveObject( + "glrComputeTestMetrics_jdm", + NamedObject.testMetrics ); + // 8. Display regression test metrics + displayTestMetricDetails(testMetrics); + } + } + } + + /** + * This method illustrates how to apply mining model on + * GLMR_NORM_DATA_APPLY_JDM dataset to predict customer's age. + * After completion of the task apply output table with the + * predicted results is created at the user specified location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "glmrApplyData_jdm", applyData, true ); + // 2. Create & save RegressionApplySettings + RegressionApplySettings regrAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "glmrApplySettings_jdm", regrAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "glmrApplyData_jdm", "glmrModel_jdm", "glmrApplySettings_jdm", + "GLMR_APPLY_OUTPUT_JDM"); + executeTask(applyTask, "glmrApplyTask_jdm"); + // 4. Display apply result + displayTable("GLMR_APPLY_OUTPUT_JDM", + "where ROWNUM < 11", + "order by CUST_ID"); + } + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException { + boolean isTaskSuccess = false; + ((OraTask)taskObj).overwriteOutput(true); + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful."); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() ); + } + return isTaskSuccess; + } + + private static void displayBuildSettings( + RegressionSettings regrSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " object:"); + String objName = regrSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = regrSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = regrSettings.getCreationDate(); + String creator = regrSettings.getCreatorInfo(); + String targetAttrName = regrSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = regrSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: regrSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = regrSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: regrSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + // List of GLM algorithm settings availabe + + String diagnsticsTableName = ((OraGLMRegressionSettings)algoSettings).getDiagnosticsTableName(); + System.out.println("Diagnostics Table Name: " + diagnsticsTableName); + + boolean useRidge = ((OraGLMRegressionSettings)algoSettings).useRidgeRegression(); + System.out.println("Use Ridge Regression: " + useRidge); + + } + + /** + * This method displayes GLMR model signature. + * + * @param model model object + * @exception JDMException if failed to retrieve model signature + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + /** + * This method displays GLMR model details. The coefficient indicates the + * relative influence of a given (attribute, value). A negative coefficient + * value indicates a negative influence. + * + * @param model glm regression model object + * @exception JDMException if failed to retrieve model details + */ + public static void displayGLMRModelDetails( + Model model) throws JDMException + { + // Obtains model details + OraGLMModelDetail glmrModelDetails = + (OraGLMModelDetail)model.getModelDetail(); + //Get computer high-level statitics of the model + Map glblDetails = glmrModelDetails.getGlobalDetails(); + if(m_displayModelDetails) { + System.out.println("Global Model details:"); + System.out.println(glblDetails.toString()); + } + //Get all attribute coefficients without any filters + ResultSet rsGLM = glmrModelDetails.getAttributeCoefficients(null, null, null, null); + //Display first coeficcient record + try { + rsGLM.next(); + if(m_displayModelDetails) { + System.out.println("Target value " + rsGLM.getString("CLASS") ); + System.out.println("Attribute name " + rsGLM.getString("ATTRIBUTE_NAME")); + System.out.println("Attribute value " + rsGLM.getString("ATTRIBUTE_VALUE")); + System.out.println("Coefficient " + rsGLM.getDouble("COEFFICIENT")); + System.out.println("Standard Error " + rsGLM.getDouble("STD_ERROR")); + System.out.println("Test static " + rsGLM.getDouble("TEST_STATISTIC")); + System.out.println("P Value " + rsGLM.getDouble("P_VALUE")); + System.out.println("Variance Inflation Factor " + rsGLM.getDouble("VIF")); + System.out.println("Std. Coefficient " + rsGLM.getDouble("STD_COEFFICIENT")); + System.out.println("Lower Coefficient Limit " + rsGLM.getDouble("LOWER_COEFF_LIMIT")); + System.out.println("Upper Coefficient Limit " + rsGLM.getDouble("UPPER_COEFF_LIMIT")); + System.out.println("Exp Coefficient " + rsGLM.getDouble("EXP_COEFFICIENT")); + System.out.println("Exp Lower Coefficient " + rsGLM.getDouble("EXP_LOWER_COEFF_LIMIT")); + System.out.println("Exp Upper Coefficient " + rsGLM.getDouble("EXP_UPPER_COEFF_LIMIT")); + } + } catch(SQLException anyExp) { + anyExp.printStackTrace(); + } + //After using the details must close the statement associated with the resultset and the resultset + Statement stmtGLM = null; + try { + stmtGLM = rsGLM.getStatement(); + rsGLM.close(); + stmtGLM.close(); + } catch(SQLException anyExp) { + + } finally { + try { if(rsGLM != null) rsGLM.close(); } catch(SQLException sqlExp) {} + } + } + + /** + * Display regression test metrics object + * + * @param testMetrics classification test metrics object + * @exception JDMException if failed to retrieve test metric details + */ + public static void displayTestMetricDetails( + RegressionTestMetrics testMetrics) throws JDMException + { + //Retrieve Oracle GLMR model test metrics deatils extensions + // Name + System.out.println("Test Metrics Name = " + testMetrics.getName()); + // Model Name + System.out.println("Model Name = " + testMetrics.getModelName()); + // Test Data Name + System.out.println("Test Data Name = " + testMetrics.getTestDataName()); + // Mean Absolute Error + System.out.println("Mean Absolute Error = " + m_df.format(testMetrics.getMeanAbsoluteError().doubleValue())); + // Mean Actual Value + System.out.println("Mean Actual Value = " + m_df.format(testMetrics.getMeanActualValue().doubleValue())); + // Mean Predicted Value + System.out.println("Mean Predicted Value = " + m_df.format(testMetrics.getMeanPredictedValue().doubleValue())); + // Root Mean Squared Error + System.out.println("Root Mean Squared Error = " + m_df.format(testMetrics.getRMSError().doubleValue())); + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while(rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + private static void clean() + { + //Drop prepared views + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE GLMR_DIAGNOSTICS_TABLE_JDM purge"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop the model + try { + m_dmeConn.removeObject("glmrModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + } +} diff --git a/dmhpdemo.sql b/dmhpdemo.sql new file mode 100644 index 0000000..08349bb --- /dev/null +++ b/dmhpdemo.sql @@ -0,0 +1,1885 @@ +Rem +Rem $Header: dmhpdemo.sql 08-oct-2006.20:42:26 sylin Exp $ +Rem +Rem dmhpdemo.sql +Rem +Rem Copyright (c) 2005, 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmhpdemo.sql - Demo for the Hierarchical Profiler package DBMS_HPROF +Rem +Rem DESCRIPTION +Rem dbmshpro_demo package demonstrates how to generate html reports from +Rem dbms hierarchical profiler tables. +Rem +Rem NOTES +Rem The Hierarchical Profiler produces hierarchical profiler information +Rem from the raw trace and stored them in the follwoing tables: +Rem dbmshp_runs - information on hierarchical profiler runs. +Rem dbmshp_function_info - information on each function profiled. +Rem dbmshp_parent_child_info - parent-child level profiler information. +Rem +Rem The analyze_reports procedures in dbmshpro_demo package produces +Rem a collection of html reports that present information derived from the +Rem raw profiler output stored in the hierarchical profiler tables. +Rem +Rem MODIFIED (MM/DD/YY) +Rem lvbcheng 09/18/06 - Add comments +Rem sylin 04/11/05 - Created +Rem + +/**************************************************************************** + * + * The following example illustrates how to use dbms hierarchical profiler + * package dbms_hprof to collect, analyze profile information, and then + * use this dbmshpro_demo package to produce useful html reports. + * + * Before start collecting any hierarchical profiler information, use + * dbmshptab.sql script in rdbms/admin directory to create the tables + * required for persistently storing the hierarchical profiler data. + * + * Profiling program. + * + * Example: + * + * 1. Create directory object for hierarchical profiler. + * - connect say SYS or someone else who can create + * directory objects. + * connect sys/ as sysdba; + * - create directory "plshprof_dir" as '/home/dbmshpdemo/plshprof'; + * - grant read on directory "plshprof_dir" to dbmshpdemo; + * - grant write on directory "plshprof_dir" to dbmshpdemo; + * + * 2. Profiling program + * sqlplus dbmshpdemo/dbmshpdemo + * execute dbms_hprof.start_profiling('plshprof_dir', 'test1.trc'); + * execute test; + * execute dbms_hprof.stop_profiling; + * + * 3. Analyzing the raw trace data generated by step 2 and get the runid from + * the dbms_hprof.analyze run. + * DECLARE + * runid number; + * BEGIN + * runid := dbms_hprof.analyze('plshprof_dir', 'test1.trc', + * run_comment =>'First run of test'); + * END; + * / + * + * 4. Use dbmshpro_demo.analyze to generate useful html reports. + * + * DECLARE + * runid1 number; + * BEGIN + * runid1 := dbms_hprof.analyze('plshprof_dir', 'test1.trc', + * run_comment =>'First run of test'); + * dbmshpro_demo.analyze_reports('plshprof_dir', 'test1', runid); + * END; + * / + * + * 6. Modify test program to improve performance. + * + * 7. Repeat step 2 to get a new raw trace output file, test2.trc. + * + * 8. Repeat step 3 with the new raw trace output file from step 6. + * + * 9. Use dbmshpro_demo.analyze to generate useful html diff reports for + * the 2 runs. + * + * BEGIN + * dbmshpro_demo.analyze_reports(location, 'testdif', runid1, runid2); + * END; + * / + ***************************************************************************/ + +CREATE OR REPLACE PACKAGE dbmshpro_demo AUTHID CURRENT_USER IS + /* analyze_reports takes a location, a file name and a run_id + * and generates a report based on data collected in the trace + * file located at directory object with run_id + * . + * + * ARGUMENTS: + * location - a directory object that points to a directory on the + * server file system where the trace file can be found. + * fname - file name of the trace file. + * run_id - target run id. + */ + PROCEDURE analyze_reports(location IN VARCHAR2, + fname IN VARCHAR2, + run_id IN NUMBER); + + /* This analyze_reports overload takes two run numbers to generate a diff + * report of the two runs. + */ + PROCEDURE analyze_reports(location IN VARCHAR2, + fname IN VARCHAR2, + run1_id IN NUMBER, + run2_id IN NUMBER); +END dbmshpro_demo; +/ +show errors + +CREATE OR REPLACE PACKAGE BODY dbmshpro_demo IS + + DBMSHP_SUBTREETIME CONSTANT PLS_INTEGER := 1; + DBMSHP_FUNCTIONTIME CONSTANT PLS_INTEGER := 2; + DBMSHP_CALLS CONSTANT PLS_INTEGER := 3; + DBMSHP_NAME CONSTANT PLS_INTEGER := 4; + DBMSHP_MEAN_SUBTREETIME CONSTANT PLS_INTEGER := 5; + DBMSHP_MEAN_FUNCTIONTIME CONSTANT PLS_INTEGER := 6; + DBMSHP_FILE_LINE_SIZE CONSTANT PLS_INTEGER := 32767; + + TYPE NumList IS TABLE OF NUMBER(38,1); + TYPE NumList2 IS TABLE OF NUMBER(38,0); + TYPE NameList IS TABLE OF VARCHAR2(4000); + TYPE RawList IS TABLE OF RAW(32); + CRLF VARCHAR2(2 char) := ' +'; + + runid NUMBER; + runid2 NUMBER; + namebuf VARCHAR2(200); + buf VARCHAR2(32767) := ''; + myclob CLOB; + page_size INTEGER; + sql_stmt VARCHAR2(4000); + total_time NUMBER; + total_calls NUMBER; + filelocation VARCHAR2(200); + filename VARCHAR2(200); + fullname VARCHAR2(300); + time_mode VARCHAR2(20); + units VARCHAR2(20) := ' (microsecs) '; + perf_time1 NUMBER(38,0); + perf_time2 NUMBER(38,0); + + /* Internal routine to write data to target file. + * IMPLEMENTATION NOTES: + * It uses two levels of buffering, one a string buffer, + * a second one a clob. One arguably could use just the clob. + */ + PROCEDURE write_data(data VARCHAR2, flush BOOLEAN) IS + BEGIN + + IF (length(buf) + length(data) > 32767) THEN + dbms_lob.writeappend(myclob, length(buf), buf); + buf := data; + ELSE + buf := buf || data; + END IF; + + IF (flush) THEN + dbms_lob.writeappend(myclob, length(buf), buf); + buf := ''; + END IF; + END; + + PROCEDURE write_plstinfo IS + Buffer VARCHAR2(32767); + Amount BINARY_INTEGER := page_size; + Position INTEGER := 1; + file_handle UTL_FILE.FILE_TYPE; + BEGIN + + -- Open file + file_handle := UTL_FILE.FOPEN(filelocation, fullname, 'wb', + DBMSHP_FILE_LINE_SIZE); + + BEGIN + LOOP + DBMS_LOB.READ(myclob, Amount, Position, Buffer); + Position := Position + Amount; + UTL_FILE.PUT_RAW(file_handle, UTL_RAW.CAST_TO_RAW(Buffer)); + END LOOP; + + EXCEPTION + WHEN NO_DATA_FOUND THEN + dbms_output.put_line(fullname || ': *created*'); + WHEN OTHERS THEN + dbms_output.put_line(fullname || ': *failed*'); + END; + + -- Reset myclob + dbms_lob.trim(myclob, 0); + + -- Close file + UTL_FILE.FCLOSE(file_handle); + + commit; + END; + + /* Generate everything up to the title line of the HTML page body. */ + PROCEDURE report_title(title varchar2) IS + BEGIN + write_data( + '' || CRLF || + '' || CRLF || + '' || title || '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '

' || title || '

' || CRLF, + FALSE); + END; + + /* Construct namebuf with ".. (Line )" */ + PROCEDURE get_name(line VARCHAR2, owner VARCHAR2, module VARCHAR2, + function VARCHAR2) IS + + BEGIN + + IF (line IS NULL OR line = 0) THEN + IF (module IS NULL) THEN + namebuf := SUBSTR(function,1,100); + ELSE + namebuf := SUBSTR + (owner || '.' || module || '.' || function, 1, 100); + END IF; + ELSE + IF (module IS NULL) THEN + namebuf := SUBSTR(function || ' (Line '||line||')',1,100); + ELSE + namebuf := SUBSTR + (owner||'.'||module||'.'||function||' (Line '||line||')',1,100); + END IF; + END IF; + END; + + /* Generate PL/SQL Time Analysis single run start page */ + PROCEDURE single_run_start_page IS + BEGIN + + write_data( + '' || CRLF || + 'PL/SQL ' || time_mode || ' Analysis for ' || filename || + '' || CRLF || + '' || CRLF || + '

PL/SQL ' || time_mode || ' Analysis for ' || filename || + '

' || CRLF || + '

' || total_time || units || time_mode || ' and '|| total_calls || + ' function calls

' || CRLF || + '

The Hierarchical Profiler produces a collection of ' || CRLF || + 'reports that present information derived from the raw ' || CRLF || + 'profiler output in a variety of formats. The following ' || CRLF || + 'reports have been found to be the most generally useful as ' || CRLF || + 'starting points for browsing:

' || CRLF || + '

' || time_mode || units || 'Summary Reports:

' || CRLF || + '' || CRLF || + '

In addition, the following reports are also available:' || + '

' || CRLF || + '' || CRLF || '' || CRLF || '', + TRUE); + + write_plstinfo; + END; + + /* Generate start page of a difference mode report using + * runid and runid2. + * Returns FALSE if the two runids have the same total run time. + */ + FUNCTION diff_mode_start_page RETURN BOOLEAN IS + fsum1 NUMBER(38,0); + fsum2 NUMBER(38,0); + timediff NUMBER(38,0); + percent NUMBER(38,0); + perform VARCHAR2(15) := ''; + fcount PLS_INTEGER; + BEGIN + + report_title('PL/SQL ' || time_mode || units || 'Analysis - Summary Page'); + + sql_stmt := + 'SELECT SUM(function_elapsed_time) FROM dbmshp_function_info ' || + 'WHERE runid = :b1'; + EXECUTE IMMEDIATE sql_stmt INTO fsum1 USING runid; + EXECUTE IMMEDIATE sql_stmt INTO fsum2 USING runid2; + + IF (fsum1 = fsum2) THEN + write_data('

No Differences Encountered

', TRUE); + write_plstinfo; + return FALSE; + END IF; + + timediff := ABS(fsum2 - fsum1); + percent := timediff/fsum1*100; + + IF (fsum2 > fsum1) THEN + perform := 'regression'; + ELSIF (fsum2 < fsum1) THEN + perform := 'improvement'; + END IF; + + -- dbmshp_t1 view contains function level profiler information from + -- dbmshp_function_info table for a particular run specified by runid. + sql_stmt := + 'CREATE OR REPLACE VIEW dbmshp_t1 AS ' || + 'SELECT calls, function_elapsed_time ftime, symbolid sid, ' || + 'SUBSTR(decode(owner, null, '''', owner||''.'')||' || + 'decode(module,null, '''', module),1,100) mname, ' || + 'SUBSTR(decode(owner, null, '''', owner||''.'')||' || + 'decode(module, null, '''', module||''.'')||' || + 'decode(function,null, '''', function),1,100) name, ' || + 'hash, line#, namespace, subtree_elapsed_time stime ' || + 'FROM dbmshp_function_info WHERE runid = ' || runid; + + EXECUTE IMMEDIATE sql_stmt; + + -- dbmshp_t2 view contains function level profiler information from + -- dbmshp_function_info table for a particular run specified by runid2. + sql_stmt := + 'CREATE OR REPLACE VIEW dbmshp_t2 AS ' || + 'SELECT calls, function_elapsed_time ftime, symbolid sid, ' || + 'SUBSTR(decode(owner, null, '''', owner||''.'')||' || + 'decode(module,null, '''', module),1,100) mname, ' || + 'SUBSTR(decode(owner, null, '''', owner||''.'')||' || + 'decode(module, null, '''', module||''.'')||' || + 'decode(function,null, '''', function),1,100) name, ' || + 'hash, line#, namespace, subtree_elapsed_time stime ' || + 'FROM dbmshp_function_info WHERE runid = ' || runid2; + + EXECUTE IMMEDIATE sql_stmt; + + -- dbmshp_diftab view contains function level profiler differences + -- information from dbmshp_t1 and dbmshp_t2 views. + sql_stmt := + 'CREATE OR REPLACE VIEW dbmshp_diftab AS SELECT ' || + 'dbmshp_t1.name, dbmshp_t1.sid sid, dbmshp_t1.calls c1, ' || + 'dbmshp_t2.calls c2, dbmshp_t1.ftime r1, dbmshp_t2.ftime r2, ' || + 'dbmshp_t1.stime s1, dbmshp_t2.stime s2, ' || + '(dbmshp_t1.stime-dbmshp_t1.ftime) d1, ' || + '(dbmshp_t2.stime-dbmshp_t2.ftime) d2, ' || + '(dbmshp_t2.calls-dbmshp_t1.calls) calls, ' || + '(dbmshp_t2.calls-dbmshp_t1.calls)/dbmshp_t1.calls*100 callsrels, ' || + 'dbmshp_t1.namespace, dbmshp_t1.mname mname, ' || + 'dbmshp_t1.name||decode(dbmshp_t1.line#,0,'''',' || + '''(Line ''||dbmshp_t1.line#||'')'') names, ' || + 'dbmshp_t1.hash, (dbmshp_t2.ftime-dbmshp_t1.ftime) ftime, ' || + '(dbmshp_t2.ftime-dbmshp_t1.ftime)/dbmshp_t1.ftime*100 ftimerel, ' || + '(dbmshp_t2.ftime/dbmshp_t2.calls)-' || + '(dbmshp_t1.ftime/dbmshp_t1.calls) mftime, ' || + '((dbmshp_t2.ftime/dbmshp_t2.calls)-' || + '(dbmshp_t1.ftime/dbmshp_t1.calls))/' || + '(dbmshp_t1.ftime/dbmshp_t1.calls)*100 mftimerel, ' || + '(dbmshp_t2.stime-dbmshp_t1.stime) stime ' || + 'FROM dbmshp_t1, dbmshp_t2 WHERE ' || + '(substr(dbmshp_t1.name||dbmshp_t1.hash,1,100) = ' || + 'substr(dbmshp_t2.name||dbmshp_t2.hash,1,100))' || + ' AND (dbmshp_t1.namespace = dbmshp_t2.namespace) AND ' || + '(dbmshp_t1.ftime <> 0) UNION SELECT ' || + 'name, sid, calls c1, calls c2, ' || + 'ftime r1, ftime r2, stime s1, stime s2, ' || + '(stime-ftime) d1, (stime-ftime) d2, ' || + '0, 0 callsrels, namespace, ' || + 'mname, ' || + 'name||decode(line#,0,'''',''(Line ''||line#||'')'') names, ' || + 'hash, 0, 0 ftimerel, 0 mftime, 0 mftimerel, 0 ' || + 'FROM dbmshp_t1 ' || + 'WHERE ftime = 0 ' || + 'UNION SELECT ' || + 'name, sid, 0 c1, calls c2, ' || + '0 r1, ftime r2, 0 s1, stime s2, ' || + '0 d1, (stime-ftime) d2, ' || + 'calls, 0 callsrels, namespace, ' || + 'mname, ' || + 'name||decode(line#,0,'''',''(Line ''||line#||'')'') names, ' || + 'hash, ftime, 0 ftimerel, 0 mftime, 0 mftimerel, stime ' || + 'FROM dbmshp_t2 ' || + 'WHERE name NOT IN (SELECT name from dbmshp_t1) ' || + 'UNION SELECT ' || + 'name, sid, calls c1, 0 c2, ' || + 'ftime r1, 0 r2, stime s1, 0 s2, ' || + '(stime-ftime) d1, 0 d2, ' || + '-calls, 0 callsrels, namespace, ' || + 'mname, ' || + 'name||''(Line ''||line#||'')'' names, ' || + 'hash, -ftime, 0 ftimerel, 0 mftime, 0 mftimerel, -stime ' || + 'FROM dbmshp_t1 ' || + 'WHERE name NOT IN (SELECT name from dbmshp_t2)'; + + EXECUTE IMMEDIATE sql_stmt; + + write_data( + 'This analysis finds a net ' || perform || ' of ' || + '' || timediff || ' microsecs (' || time_mode || ') or ' || + percent || '% (' || fsum1 || ' versus ' || + fsum2 || ').
' || CRLF, + FALSE); + + sql_stmt := + 'SELECT COUNT(*) FROM dbmshp_diftab'; + EXECUTE IMMEDIATE sql_stmt INTO fcount; + + write_data( + 'Here is a summary of the ' || fcount || ' most important ' || + 'individual function regressions and improvements.' || CRLF || + '

Function Level Difference Reports:

' || CRLF || + '' || CRLF || '

' || + 'In addition, the following reports are also available:

' || CRLF || + '' || CRLF || '' || CRLF || '', + TRUE); + + write_plstinfo; + RETURN TRUE; + END; + + /* Generate function level summary reports sorted on a particular + * attribute. + */ + PROCEDURE function_level_report(ordertype PLS_INTEGER, + mean_report BOOLEAN) IS + orderclause VARCHAR2(100); + sortedby VARCHAR2(100); + bstime VARCHAR2(30) := ''; + bftime VARCHAR2(30) := ''; + bmstime VARCHAR2(30) := ''; + bmftime VARCHAR2(30) := ''; + bcalls VARCHAR2(30) := ''; + bname VARCHAR2(30) := ''; + mstimes NumList2; + mftimes NumList2; + stimes NumList; + ftimes NumList; + dtimes NumList; + calls NumList; + owners NameList; + modules NameList; + fnames NameList; + lines NumList; + hashtab RawList; + stimeind NUMBER(38,1); + ftimeind NUMBER(38,1); + dtimeind NUMBER(38,1); + callsind NUMBER(38,1); + + BEGIN + + IF (ordertype = DBMSHP_SUBTREETIME) THEN + orderclause := 'subtree_elapsed_time desc'; + sortedby := 'Total Subtree Time'; + bstime := ''; + ELSIF (ordertype = DBMSHP_FUNCTIONTIME) THEN + orderclause := 'function_elapsed_time desc'; + sortedby := 'Total Function Time'; + bftime := ''; + ELSIF (ordertype = DBMSHP_CALLS) THEN + orderclause := 'calls desc'; + sortedby := 'Total Number of Calls'; + bcalls := ''; + ELSIF (ordertype = DBMSHP_NAME) THEN + orderclause := + 'SUBSTR(owner||''.''||module||''.''||function, 1, 100) asc'; + sortedby := 'Name'; + bname := ''; + ELSIF (ordertype = DBMSHP_MEAN_SUBTREETIME) THEN + orderclause := '(subtree_elapsed_time/calls) desc'; + sortedby := 'Mean Subtree Time'; + bmstime := ''; + ELSIF (ordertype = DBMSHP_MEAN_FUNCTIONTIME) THEN + orderclause := '(function_elapsed_time/calls) desc'; + sortedby := 'Mean Function Time'; + bmftime := ''; + END IF; + + report_title(time_mode || ' Report' || units || 'Sorted By ' || sortedby); + + write_data( + '' || CRLF || '' || CRLF, + FALSE); + + IF (mean_report = TRUE) THEN + write_data( + '' || CRLF || + '' || CRLF, FALSE); + END IF; + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + + sql_stmt := 'SELECT subtree_elapsed_time, function_elapsed_time, ' || + '(subtree_elapsed_time-function_elapsed_time), ' || + 'calls, owner, module, function, line#, hash, ' || + '(subtree_elapsed_time/calls), (function_elapsed_time/calls) ' || + 'FROM dbmshp_function_info ' || + 'WHERE runid = :b1 ' || + ' ORDER BY ' || orderclause; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + stimes, ftimes, dtimes, calls, owners, modules, fnames, + lines, hashtab, mstimes, mftimes + USING runid; + + FOR i in stimes.FIRST..stimes.LAST LOOP + + get_name(lines(i), owners(i), modules(i), fnames(i)); + + stimeind := stimes(i)/total_time*100; + ftimeind := ftimes(i)/total_time*100; + dtimeind := dtimes(i)/total_time*100; + callsind := calls(i)/total_calls*100; + + write_data('' || CRLF, FALSE); + + IF (mean_report = TRUE) THEN + write_data( + bmstime || mstimes(i) || '' || CRLF || + bmftime || mftimes(i) || '' || CRLF, FALSE); + END IF; + + write_data( + bstime || stimes(i) || '' || CRLF || + bstime || stimeind || '%' || CRLF || + bftime || ftimes(i) || '' || CRLF || + bftime || ftimeind || '%' || CRLF || + '' || CRLF || + '' || CRLF || + bcalls || calls(i) || '' || CRLF || + bcalls || callsind || '%' || CRLF || + bname || '' || namebuf || '' || CRLF || + '' || CRLF, FALSE); + END LOOP; + + write_data(CRLF || '
Mean Subtree TimeMean Function TimeSubtree TimeInd%Function TimeInd%Descendants TimeInd%CallsInd%Function Name
' || dtimes(i) || '' || dtimeind || '%
' || CRLF || '' || CRLF || '', + TRUE); + + write_plstinfo; + END; + + /* Generate namespace level summary report */ + PROCEDURE namespace_report IS + names NameList; + ftimes NumList; + calls Numlist; + ftimeind NUMBER(38,1); + callsind NUMBER(38,1); + BEGIN + + report_title(time_mode || ' Report' || units || ': Grouped By Namespace'); + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + + sql_stmt := 'SELECT namespace, sum(function_elapsed_time), sum(calls) ' || + 'FROM dbmshp_function_info ' || + 'WHERE runid = :b1 group by namespace'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + names, ftimes, calls USING runid; + + FOR i in ftimes.first..ftimes.last LOOP + ftimeind := ftimes(i)/total_time*100; + callsind := calls(i)/total_calls*100; + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + END LOOP; + + write_data('
NamespaceFunction TimeInd%CallsInd%
' || names(i) || '' || ftimes(i) || '' || ftimeind || '%' || calls(i) || '' || callsind || '%
' || CRLF || '' || CRLF || '', TRUE); + + write_plstinfo; + END; + + /* Generate parents and children report */ + PROCEDURE parent_child_report IS + stimes NumList; + ftimes NumList; + dtimes NumList; + calls NumList; + owners NameList; + modules NameList; + fnames NameList; + lines NumList; + hashtab RawList; + pstimes NumList; + pftimes NumList; + pcalls NumList; + sids NumList; + pids NumList; + x PLS_INTEGER; + dtime NUMBER; + stimeind NUMBER(38,1); + ftimeind NUMBER(38,1); + dtimeind NUMBER(38,1); + callsind NUMBER(38,1); + + BEGIN + + report_title('Parents and Children Report with ' || + time_mode || units); + + sql_stmt := 'SELECT subtree_elapsed_time, function_elapsed_time, ' || + 'calls, owner, module, function, line#, hash, symbolid, ' || + '(subtree_elapsed_time-function_elapsed_time) ' || + 'FROM dbmshp_function_info WHERE runid = :b1 ' || + 'ORDER BY symbolid'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + stimes, ftimes, calls, owners, modules, fnames, lines, hashtab, + sids, dtimes USING runid; + + FOR i in 1..sids.COUNT LOOP + get_name(lines(i), owners(i), modules(i), fnames(i)); + + stimeind := stimes(i)/total_time*100; + ftimeind := ftimes(i)/total_time*100; + dtimeind := dtimes(i)/total_time*100; + callsind := calls(i)/total_calls*100; + + -- Output name + write_data('' || namebuf || '' || CRLF, FALSE); + + -- Output table + write_data( + '' || CRLF || + '' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ''|| CRLF || + '' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || '' || CRLF, FALSE); + + -- output Parent info. + sql_stmt := 'SELECT parentsymid, ' || + 'subtree_elapsed_time, function_elapsed_time, calls ' || + 'FROM dbmshp_parent_child_info WHERE runid = :b1 AND ' || + 'childsymid = :b2 ORDER BY subtree_elapsed_time desc'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + pids, pstimes, pftimes, pcalls USING runid, sids(i); + + write_data( + '' || CRLF || + ' ' || CRLF || + '' || CRLF, FALSE); + + -- entry + IF (pids.COUNT = 0) THEN + write_data( + '' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + '' || CRLF, FALSE); + END IF; + + FOR j in 1..pids.COUNT LOOP + x := pids(j); + + get_name(lines(x), owners(x), modules(x), fnames(x)); + + dtime := pstimes(j)-pftimes(j); + + IF stimes(i) = 0 THEN + stimeind := 0; + ELSE + stimeind := pstimes(j)/stimes(i)*100; + END IF; + IF ftimes(i) = 0 THEN + ftimeind := 0; + ELSE + ftimeind := pftimes(j)/ftimes(i)*100; + END IF; + IF dtimes(i) = 0 THEN + dtimeind := 0; + ELSE + dtimeind := dtime/dtimes(i)*100; + END IF; + callsind := pcalls(j)/calls(i)*100; + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || '' || CRLF, FALSE); + END LOOP; + + -- output children info. + sql_stmt := 'SELECT childsymid, subtree_elapsed_time, ' || + 'function_elapsed_time, calls FROM dbmshp_parent_child_info ' || + 'WHERE runid = :b1 AND parentsymid = :b2 ' || + 'ORDER BY subtree_elapsed_time desc'; + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO pids, pstimes, + pftimes, pcalls USING runid, sids(i); + + IF pids.COUNT > 0 THEN + write_data('' || CRLF, FALSE); + END IF; + + FOR j in 1..pids.COUNT LOOP + x := pids(j); + get_name(lines(x), owners(x), modules(x), fnames(x)); + + dtime := pstimes(j)-pftimes(j); + + IF dtimes(i) = 0 THEN + stimeind := 0; + ELSE + stimeind := pstimes(j)/dtimes(i)*100; + END IF; + IF ftimes(x) = 0 THEN + ftimeind := 0; + ELSE + ftimeind := pftimes(j)/ftimes(x)*100; + END IF; + IF dtimes(x) = 0 THEN + dtimeind := 0; + ELSE + dtimeind := dtime/dtimes(x)*100; + END IF; + callsind := pcalls(j)/calls(x)*100; + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + END LOOP; + + write_data('
Subtree TimeInd%Function TimeInd%Descendants TimeInd%CallsInd%Function Name
' || stimes(i) || '' || stimeind || '%' || ftimes(i) || '' || ftimeind || '%' || dtimes(i) || '' || dtimeind || '%' || calls(i) || '' || callsind || '%' || CRLF || + ' ' || namebuf || '' || CRLF || + '
' || CRLF || + ' Parents:' || CRLF || + '
' || stimes(i) || '100%' || ftimes(i) || '100%' || dtimes(i) || '100%' || calls(i) || '100%' || CRLF || + ' root' || CRLF || + '
' || pstimes(j) || '' || stimeind || '%' || pftimes(j) || '' || ftimeind || '%' || dtime || '' || dtimeind || '%' || pcalls(j) || '' || callsind || '%' || CRLF || + ' ' || namebuf || + '
Children:
' || pstimes(j) || '' || stimeind || '%' || pftimes(j) || '' || ftimeind || '%' || dtime || '' || dtimeind || '%' || pcalls(j) || '' || callsind || '%' || CRLF || + ' ' || namebuf || '

'|| CRLF, FALSE); + END LOOP; + + write_data('' || CRLF || '', TRUE); + + write_plstinfo; + END; + + /* Generate module level summary reports */ + PROCEDURE module_report(ordertype PLS_INTEGER) IS + orderclause VARCHAR2(100); + sortedby VARCHAR2(100); + bftime VARCHAR2(30) := ''; + bcalls VARCHAR2(30) := ''; + bname VARCHAR2(30) := ''; + ftimes NumList; + calls NumList; + fnames NameList; + owners NameList; + modules NameList; + ftimeind NUMBER(38,1); + callsind NUMBER(38,1); + + BEGIN + + IF (ordertype = DBMSHP_FUNCTIONTIME) THEN + orderclause := 'sum(function_elapsed_time) desc'; + sortedby := '(Total Module Time)'; + bftime := ''; + ELSIF (ordertype = DBMSHP_CALLS) THEN + orderclause := 'sum(calls) desc'; + sortedby := '(Total Number of Calls)'; + bcalls := ''; + ELSIF (ordertype = DBMSHP_NAME) THEN + orderclause := 'substr(owner || ''.'' || module, 1, 100) asc'; + sortedby := '(Module Name)'; + bname := ''; + END IF; + + report_title(time_mode || ' Report:' || units || + 'Group by Module Name Sorted By ' || sortedby); + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + + sql_stmt := 'SELECT sum(function_elapsed_time), sum(calls), ' || + 'SUBSTR(owner||''.''||module, 1, 50) FROM dbmshp_function_info ' || + 'WHERE runid = :b1 ' || + 'GROUP BY module, owner ' || + ' ORDER BY ' || orderclause; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + ftimes, calls, fnames USING runid; + + FOR i in ftimes.first..ftimes.last LOOP + ftimeind := ftimes(i)/total_time*100; + callsind := calls(i)/total_calls*100; + + IF (fnames(i) = '.') THEN + fnames(i) := ''; + END IF; + + write_data( + '' || CRLF || + bftime || ftimes(i) || '' || CRLF || + bftime || ftimeind || '%' || CRLF || + bcalls || calls(i) || '' || CRLF || + bcalls || callsind || '%' || CRLF || + bname || fnames(i) || '' || CRLF || + '' || CRLF, FALSE); + END LOOP; + + write_data('
Module TimeInd%CallsInd%Module Name
' || CRLF || '' || CRLF || '', TRUE); + + write_plstinfo; + + END; + + /* Generate functions with performance improvements/regressions report */ + PROCEDURE performance_report(where_clause VARCHAR2, pmode VARCHAR2) IS + cumind NUMBER(38,1) := 0; + perf_time NUMBER(38,0); + ftimeind NUMBER(38,1); + stimes NumList; + ftimes NumList; + dtimes NumList; + calls NumList; + callrels NumList; + fnames NameList; + ftimerels NumList; + mftimes NumList2; + mtimerels NumList; + hashtab RawList; + + BEGIN + + sql_stmt := 'SELECT SUM(ftime) FROM dbmshp_diftab WHERE ' || where_clause; + EXECUTE IMMEDIATE sql_stmt INTO perf_time; + + sql_stmt := + 'SELECT calls, callsrels, names, hash, ftime, stime, (stime-ftime), ' || + 'ftimerel, mftime, mftimerel FROM dbmshp_diftab WHERE ' || + where_clause || ' ORDER BY ftime desc'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + calls, callrels, fnames, hashtab, ftimes, stimes, dtimes, ftimerels, + mftimes, mtimerels; + + write_data( + '' || CRLF || + 'Function with Performance ' || pmode || + ': Sorted by Function Time' || units || 'Delta' || CRLF || + '' || CRLF || + '

Function ' || time_mode || units || 'Data for Performance ' || + pmode || '

' || CRLF || + 'Total ' || pmode || ': ' || abs(perf_time) || ' microsecs ' || + time_mode || '' || CRLF || + '
' || CRLF ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' || CRLF,
+      FALSE);
+
+    FOR i in 1..fnames.COUNT LOOP
+      ftimeind := ftimes(i)/perf_time*100;
+      cumind := cumind + ftimeind;
+      IF (cumind > 100) THEN
+        cumind := 100;
+      END IF;
+      write_data(
+        '' || CRLF ||
+        '' || CRLF ||
+        '' || CRLF ||
+        ''
+          ELSE '' || ftimerels(i) || '%' END) || CRLF ||
+        '' || CRLF ||
+        '' || CRLF ||
+        '' || CRLF ||
+        '' || CRLF ||
+        ''
+          ELSE callrels(i) || '%' END) || CRLF ||
+        ''
+          ELSE mftimes(i) || '' END) || CRLF ||
+        ''
+          ELSE mtimerels(i) || '%' END) || CRLF ||
+        '' || CRLF,
+        FALSE);
+    END LOOP;
+
+    write_data('
Subtree TimeFunction Time DeltaRel%Ind%Cum%Descendants Time DeltaCalls DeltaRel%Mean Function Time DeltaRel%Function Name
' || stimes(i) || '' || ftimes(i) || '' || (CASE ftimerels(i) WHEN 0 THEN '' || ftimeind || '%' || cumind || '%' || dtimes(i) || '' || calls(i) || '' || (CASE callrels(i) WHEN 0 THEN '' || (CASE mftimes(i) WHEN 0 THEN '' || (CASE mtimerels(i) WHEN 0 THEN '' || CRLF || + '' || fnames(i) || + '
', TRUE); + write_plstinfo; + END; + + /* Generate function level difference reports sorted on a particular + * attribute. + */ + PROCEDURE diff_function_level_report(ordertype PLS_INTEGER) IS + orderclause VARCHAR2(100); + sortedby VARCHAR2(100); + bstime VARCHAR2(30) := ''; + bftime VARCHAR2(30) := ''; + bmstime VARCHAR2(30) := ''; + bmftime VARCHAR2(30) := ''; + bcalls VARCHAR2(30) := ''; + bname VARCHAR2(30) := ''; + calls NumList; + callrels NumList; + fnames NameList; + stimes NumList; + ftimes NumList; + dtimes NumList; + mftimes NumList2; + ftimerels NumList; + mtimerels NumList; + ftimeind NUMBER(38,1); + + BEGIN + IF (ordertype = DBMSHP_SUBTREETIME) THEN + orderclause := 'stime desc'; + sortedby := 'Total Subtree '; + bstime := ''; + ELSIF (ordertype = DBMSHP_FUNCTIONTIME) THEN + orderclause := 'ftime desc'; + sortedby := 'Total Function '; + bftime := ''; + ELSIF (ordertype = DBMSHP_CALLS) THEN + orderclause := 'calls desc'; + sortedby := 'Total Number of Calls '; + bcalls := ''; + ELSIF (ordertype = DBMSHP_NAME) THEN + orderclause := 'names asc'; + sortedby := 'Function Name '; + bname := ''; + END IF; + + report_title('Function ' || time_mode || units || 'Data Sorted By ' || + sortedby || time_mode || units || 'Delta for ' || filename); + + write_data( + '' || CRLF || '' || CRLF || + '' || + '' || + '' || + '' || CRLF, + FALSE); + + sql_stmt := 'SELECT SUM(ftime) FROM dbmshp_diftab WHERE ftime > 0'; + EXECUTE IMMEDIATE sql_stmt INTO perf_time1; + + sql_stmt := 'SELECT SUM(ftime) FROM dbmshp_diftab WHERE ftime < 0'; + EXECUTE IMMEDIATE sql_stmt INTO perf_time2; + + sql_stmt := + 'SELECT calls, callsrels, names, ftime, stime, (stime-ftime), ' || + 'ftimerel, mftime, mftimerel FROM dbmshp_diftab ' || + 'ORDER BY ' || orderclause; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + calls, callrels, fnames, ftimes, stimes, dtimes, ftimerels, + mftimes, mtimerels; + + FOR i in 1..fnames.COUNT LOOP + + IF (ftimes(i) < 0) THEN + ftimeind := ftimes(i)/perf_time2*100; + ELSE + ftimeind := ftimes(i)/perf_time1*100; + END IF; + + write_data( + '' || CRLF || + bstime || stimes(i) || '' || CRLF || + bftime || ftimes(i) || '' || CRLF || + bftime || (CASE ftimerels(i) WHEN 0 THEN '' + ELSE ftimerels(i) || '%' END) || CRLF || + bftime || (CASE ftimeind WHEN 0 THEN '' + ELSE ftimeind || '%' END) || CRLF || + '' || CRLF || + bcalls || calls(i) || '' || CRLF || + bcalls || (CASE callrels(i) WHEN 0 THEN '' + ELSE callrels(i) || '%' END) || CRLF || + '' + ELSE mftimes(i)|| '' END) || CRLF || + '' + ELSE mtimerels(i) || '%' END) || CRLF || + bname || '' || fnames(i) || + '' || CRLF, + FALSE); + END LOOP; + + write_data( + '
Subtree Time DeltaFunction Time DeltaRel%Ind%Descendants Time DeltaCalls DeltaRel%Mean Function Time DeltaRel%Function Name
' || dtimes(i) || '' || (CASE mftimes(i) WHEN 0 THEN '' || (CASE mtimerels(i) WHEN 0 THEN '
' || CRLF || CRLF || '' || CRLF || '', + TRUE); + + write_plstinfo; + END; + + /* Generate namespace level difference report */ + PROCEDURE diff_namespace_report IS + units VARCHAR2(20) := ' (in microsecs) '; + ftimes1 NumList; + ftimes2 NumList; + ftimes NumList; + calls NumList; + calls1 NumList; + calls2 NumList; + fnames NameList; + + BEGIN + + report_title(time_mode||' Report' || units || 'Group By Namespace'); + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + + sql_stmt := + 'SELECT sum(r1), sum(r2), sum(ftime), ' || + 'sum(c1), sum(c2), sum(calls), namespace ' || + 'FROM dbmshp_diftab GROUP BY namespace ' || + 'ORDER BY namespace'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + ftimes1, ftimes2, ftimes, calls1, calls2, calls, fnames; + + FOR i in ftimes.first..ftimes.last LOOP + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + END LOOP; + + write_data('
Namespace' || time_mode || 'Calls
First TraceSecond TraceDeltaFirst TraceSecond TraceDelta
' || fnames(i) || '' || ftimes1(i) || '' || ftimes2(i) || '' || ftimes(i) || '' || calls1(i) || '' || calls2(i) || '' || calls(i) || '
' || CRLF || '' || CRLF || '', TRUE); + write_plstinfo; + END; + + /* Generate module level difference report */ + PROCEDURE diff_module_report(ordertype PLS_INTEGER) IS + orderclause VARCHAR2(30); + sortedby VARCHAR2(30); + bftime VARCHAR2(30) := ''; + bcalls VARCHAR2(30) := ''; + bname VARCHAR2(30) := ''; + ftimes NumList; + fnames NameList; + calls NumList; + ftimes1 NumList; + ftimes2 NumList; + calls1 NumList; + calls2 NumList; + + BEGIN + + IF (ordertype = DBMSHP_FUNCTIONTIME) THEN + orderclause := 'delta desc'; + sortedby := 'Module Time' || units; + bftime := ''; + ELSIF (ordertype = DBMSHP_CALLS) THEN + orderclause := 'calls desc'; + sortedby := 'Call Count'; + bcalls := ''; + ELSIF (ordertype = DBMSHP_NAME) THEN + orderclause := 'mname'; + sortedby := 'Module Name'; + bname := ''; + END IF; + + report_title('Module Level Difference Report - Sorted by ' || sortedby); + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + + sql_stmt := + 'SELECT sum(r1), sum(r2), sum(ftime) delta, ' || + 'sum(c1), sum(c2), sum(calls) calls, mname ' || + 'FROM dbmshp_diftab GROUP BY mname ' || + 'ORDER BY ' || orderclause; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + ftimes1, ftimes2, ftimes, calls1, calls2, calls, fnames; + + FOR i in ftimes.first..ftimes.last LOOP + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + bftime || ftimes(i) || '' || CRLF || + '' || CRLF || + '' || CRLF || + bcalls || calls(i) || '' || CRLF || + bname || fnames(i) || '' || CRLF || + '' || CRLF, FALSE); + END LOOP; + + write_data('
Module TimeCallsModule Name
First TraceSecond TraceDeltaFirst TraceSecond TraceDelta
' || ftimes1(i) || '' || ftimes2(i) || '' || calls1(i) || '' || calls2(i) || '
' || CRLF || '' || CRLF || '', TRUE); + write_plstinfo; + END; + + /* Generate parents and children difference report */ + PROCEDURE diff_parent_child_report IS + fnames NameList; + pnames NameList; + cnames NameList; + stimes NumList; + ftimes NumList; + dtimes NumList; + mftimes NumList2; + calls NumList; + mtimerels NumList; + stimes1 NumList; + stimes2 NumList; + ftimes1 NumList; + ftimes2 NumList; + dtimes1 NumList; + dtimes2 NumList; + calls1 NumList; + calls2 NumList; + hashtab RawList; + hashtab2 RawList; + ftimeind NUMBER(38,1); + stimeind NUMBER(38,1); + dtimeind NUMBER(38,1); + callsind NUMBER(38,1); + pstimes NumList; + pftimes NumList; + pcalls NumList; + sids NumList; + pids NumList; + cids NumList; + x PLS_INTEGER; + dtime NUMBER; + perform VARCHAR2(50); + fsum1 NUMBER(38,0); + fsum2 NUMBER(38,0); + csum1 NUMBER(38,0); + csum2 NUMBER(38,0); + stimeind1 NUMBER(38,1); + stimeind2 NUMBER(38,1); + ftimeind1 NUMBER(38,1); + ftimeind2 NUMBER(38,1); + dtimeind1 NUMBER(38,1); + dtimeind2 NUMBER(38,1); + callsind1 NUMBER(38,1); + callsind2 NUMBER(38,1); + mftime1 NUMBER(38,1); + mftime2 NUMBER(38,1); + mstime NUMBER(38,1); + mstime1 NUMBER(38,1); + mstime2 NUMBER(38,1); + mstimeind NUMBER(38,1); + mdtime NUMBER(38,1); + mdtime1 NUMBER(38,1); + mdtime2 NUMBER(38,1); + mdtimeind NUMBER(38,1); + + BEGIN + + -- dbmshp_pct1 view contains parent-child level profiler information from + -- dbmshp_parent_child_info and dbmshp_function_info tables for a + -- particular run specified by runid. + sql_stmt := + 'CREATE OR REPLACE VIEW dbmshp_pct1 AS SELECT ' || + 'p.parentsymid pid, p.childsymid cid, ' || + 'p.subtree_elapsed_time stime, p.function_elapsed_time ftime, ' || + 'p.calls, f.namespace, f.hash, f.line#, ' || + 'x.hash phash, x.namespace pnamespace, x.line# pline, ' || + 'SUBSTR(decode(f.owner, null, '''', f.owner||''.'')||' || + 'decode(f.module, null, '''', f.module||''.'')||' || + 'decode(f.function,null, '''', f.function),1,100) name, ' || + 'SUBSTR(decode(x.owner, null, '''', x.owner||''.'')||' || + 'decode(x.module, null, '''', x.module||''.'')||' || + 'decode(x.function,null, '''', x.function),1,100) pname ' || + 'FROM dbmshp_parent_child_info p, dbmshp_function_info f, ' || + '(select * from dbmshp_function_info) x ' || + 'WHERE f.runid = ' || runid || ' AND p.runid = ' || runid || + ' AND x.runid = ' || runid || + ' AND p.childsymid = f.symbolid' || + ' AND p.parentsymid = x.symbolid'; + EXECUTE IMMEDIATE sql_stmt; + + -- dbmshp_pct2 view contains parent-child level profiler information from + -- dbmshp_parent_child_info and dbmshp_function_info tables for a + -- particular run specified by runid2. + sql_stmt := + 'CREATE OR REPLACE VIEW dbmshp_pct2 AS SELECT ' || + 'p.parentsymid pid, p.childsymid cid, ' || + 'p.subtree_elapsed_time stime, p.function_elapsed_time ftime, ' || + 'p.calls, f.namespace, f.hash, f.line#, ' || + 'x.hash phash, x.namespace pnamespace, x.line# pline, ' || + 'SUBSTR(decode(f.owner, null, '''', f.owner||''.'')||' || + 'decode(f.module, null, '''', f.module||''.'')||' || + 'decode(f.function,null, '''', f.function),1,100) name, ' || + 'SUBSTR(decode(x.owner, null, '''', x.owner||''.'')||' || + 'decode(x.module, null, '''', x.module||''.'')||' || + 'decode(x.function,null, '''', x.function),1,100) pname ' || + 'FROM dbmshp_parent_child_info p, dbmshp_function_info f, ' || + '(select * from dbmshp_function_info) x ' || + 'WHERE f.runid = ' || runid2 || ' AND p.runid = ' || runid2 || + ' AND x.runid = ' || runid2 || + ' AND p.childsymid = f.symbolid' || + ' AND p.parentsymid = x.symbolid'; + EXECUTE IMMEDIATE sql_stmt; + + -- dbmshp_pcdiftab view contains parent-child level profiler differences + -- information from dbmshp_pct1 and dbmshp_pct2 views. + sql_stmt := + 'CREATE OR REPLACE VIEW dbmshp_pcdiftab AS SELECT ' || + 'dbmshp_pct1.pid pid, dbmshp_pct1.cid cid, ' || + '(dbmshp_pct2.stime-dbmshp_pct1.stime) stime,' || + '(dbmshp_pct2.ftime-dbmshp_pct1.ftime) ftime, ' || + '(dbmshp_pct2.calls-dbmshp_pct1.calls) calls, ' || + 'dbmshp_pct1.namespace, dbmshp_pct1.hash, ' || + 'dbmshp_pct1.pname||decode(dbmshp_pct1.pline,0,'''',' || + '''(Line ''||dbmshp_pct1.pline||'')'') pname, dbmshp_pct1.phash, ' || + 'dbmshp_pct1.name||decode(dbmshp_pct1.line#,0,'''',' || + '''(Line ''||dbmshp_pct1.line#||'')'') ' || + 'names FROM dbmshp_pct1, dbmshp_pct2 WHERE ' || + '(substr(dbmshp_pct1.name||dbmshp_pct1.hash,1,100) = ' || + 'substr(dbmshp_pct2.name||dbmshp_pct2.hash,1,100)) AND ' || + '(dbmshp_pct1.namespace = dbmshp_pct2.namespace) AND ' || + '(substr(dbmshp_pct1.pname||dbmshp_pct1.phash,1,100) = ' || + 'substr(dbmshp_pct2.pname||dbmshp_pct2.phash,1,100)) AND ' || + '(dbmshp_pct1.pnamespace = dbmshp_pct2.pnamespace) ' || + 'UNION SELECT ' || + 'pid, cid, stime, ftime, calls, namespace, hash, ' || + 'pname||decode(pline,0,'''',''(Line ''||pline||'')'') ' || + 'pname, phash, ' || + 'name||decode(line#,0,'''',''(Line ''||line#||'')'') ' || + 'names FROM dbmshp_pct2 ' || + 'WHERE name NOT IN (SELECT name from dbmshp_pct1) ' || + 'OR pname NOT IN (SELECT pname from dbmshp_pct1) ' || + 'UNION SELECT ' || + 'pid, cid, -stime, -ftime, -calls, namespace, hash, ' || + 'pname||decode(pline,0,'''',''(Line ''||pline||'')'') ' || + 'pname, phash, ' || + 'name||decode(line#,0,'''',''(Line ''||line#||'')'') ' || + 'names FROM dbmshp_pct1 ' || + 'WHERE name NOT IN (SELECT name from dbmshp_pct2) ' || + 'OR pname NOT IN (SELECT pname from dbmshp_pct2)'; + + EXECUTE IMMEDIATE sql_stmt; + + report_title('Parents and Children Difference Report with ' || + time_mode || units); + + sql_stmt := 'SELECT SUM(ftime), SUM(calls) FROM dbmshp_t1'; + EXECUTE IMMEDIATE sql_stmt INTO fsum1, csum1; + + sql_stmt := 'SELECT SUM(ftime), SUM(calls) FROM dbmshp_t2'; + EXECUTE IMMEDIATE sql_stmt INTO fsum2, csum2; + + sql_stmt := + 'SELECT calls, names, hash, ftime, stime, sid, (stime-ftime), ' || + 'mftime, mftimerel, c1, c2, r1, r2, s1, s2, d1, d2 ' || + 'FROM dbmshp_diftab ORDER BY sid'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + calls, fnames, hashtab, ftimes, stimes, sids, dtimes, mftimes, mtimerels, + calls1, calls2, ftimes1, ftimes2, stimes1, stimes2, dtimes1, dtimes2; + + FOR i in 1..sids.COUNT LOOP + IF (ftimes(i) < 0) THEN + ftimeind := ftimes(i)/perf_time2*100; + perform := '(' || ftimeind || '% of total improvement)'; + ELSIF (ftimes(i) > 0) THEN + ftimeind := ftimes(i)/perf_time1*100; + perform := '(' || ftimeind || '% of total regression)'; + ELSE + perform := ''; + END IF; + + IF ftimes1(i) = 0 THEN + ftimeind := 0; + ELSE + ftimeind := ftimes(i)/ftimes1(i)*100; + END IF; + ftimeind1 := ftimes1(i)/fsum1*100; + ftimeind2 := ftimes2(i)/fsum2*100; + + IF stimes1(i) = 0 THEN + stimeind := 0; + ELSE + stimeind := stimes(i)/stimes1(i)*100; + END IF; + stimeind1 := stimes1(i)/fsum1*100; + stimeind2 := stimes2(i)/fsum2*100; + + IF dtimes1(i) = 0 THEN + dtimeind := 0; + ELSE + dtimeind := dtimes(i)/dtimes1(i)*100; + END IF; + dtimeind1 := dtimes1(i)/fsum1*100; + dtimeind2 := dtimes2(i)/fsum2*100; + + IF calls1(i) = 0 THEN + callsind := 0; + mftime1 := 0; + mstime1 := 0; + mdtime1 := 0; + ELSE + callsind := calls(i)/calls1(i)*100; + mftime1 := ftimes1(i)/calls1(i); + mstime1 := stimes1(i)/calls1(i); + mdtime1 := dtimes1(i)/calls1(i); + END IF; + callsind1 := calls1(i)/csum1*100; + callsind2 := calls2(i)/csum2*100; + + IF calls2(i) = 0 THEN + mftime2 := 0; + mstime2 := 0; + mdtime2 := 0; + ELSE + mftime2 := ftimes2(i)/calls2(i); + mstime2 := stimes2(i)/calls2(i); + mdtime2 := dtimes2(i)/calls2(i); + END IF; + + mstime := mstime2-mstime1; + mdtime := mdtime2-mdtime1; + + IF mstime1 = 0 THEN + mstimeind := 0; + ELSE + mstimeind := mstime/mstime1*100; + END IF; + + IF mdtime1 = 0 THEN + mdtimeind := 0; + ELSE + mdtimeind := mdtime/mdtime1*100; + END IF; + + write_data( + '

Comparision for ' || fnames(i) || '' || perform || + '

' || CRLF || + '' || CRLF || + '' || + '' || + '' || + '' || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + (CASE (ftimes1(i)+ftimes2(i)) WHEN 0 THEN '' ELSE + '' || + '' ELSE + ftimes1(i) || '' END) || + '' ELSE + ftimes2(i) || '' END) || + '' || CRLF || + '' || CRLF END) || + (CASE dtimes1(i) WHEN 0 THEN '' ELSE + '' || + '' || + '' || + '' || CRLF || + '' || CRLF || + '' || + '' || + '' || + '' || CRLF || + '' || CRLF END) || + '' || + '' ELSE + calls1(i) || '' END) || + '' ELSE + calls2(i) || '' END) || + '' || CRLF || + '' || CRLF || + (CASE (mftime1+mftime2) WHEN 0 THEN '' ELSE + '' || + '' ELSE + mftime1 || '' END) || '' || + '' ELSE + mftime2 || '' END) || '' || + '' ELSE + mftimes(i) || '' END) || + '' ELSE + mtimerels(i) || '%' END) || CRLF || + '' || CRLF END) || + (CASE mdtime1 WHEN 0 THEN '' ELSE + '' || + '' || + '' || + '' || CRLF || + '' || CRLF || + '' || + '' || + '' || + '' || CRLF || + '' || CRLF END) || '
' || fnames(i) || 'First TraceSecond TraceDiffDiff%
MeasureInd%MeasureInd%
' || + 'Function ' || time_mode || ' (microsecs)s' || (CASE ftimes1(i) WHEN 0 THEN '' || ftimeind1 || '%' || (CASE ftimes2(i) WHEN 0 THEN '' || ftimeind2 || '%' || ftimes(i) || '' || ftimeind || '%
' || + 'Descendants ' || time_mode || ' (microsecs)s' || dtimes1(i) || '' || dtimeind1 || '%' || dtimes2(i) || '' || dtimeind2 || '%' || dtimes(i) || '' || dtimeind || '%
' || + 'Subtree ' || time_mode || ' (microsecs)s' || stimes1(i) || '' || stimeind1 || '%' || stimes2(i) || '' || stimeind2 || '%' || stimes(i) || '' || stimeind || '%
' || + 'Function Calls' || (CASE calls1(i) WHEN 0 THEN '' || callsind1 || '%' || (CASE calls2(i) WHEN 0 THEN '' || callsind2 || '%' || calls(i) || '' || callsind || '%
' || + 'Mean Function ' || time_mode || ' (microsecs)s' || (CASE mftime1 WHEN 0 THEN '' || (CASE mftime2 WHEN 0 THEN '' || (CASE mftimes(i) WHEN 0 THEN '' || (CASE mtimerels(i) WHEN 0 THEN '
' || + 'Mean Descendants ' || time_mode || ' (microsecs)s' || mdtime1 || '' || mdtime2 || '' || mdtime || '' || mdtimeind || '%
' || + 'Mean Subtree ' || time_mode || ' (microsecs)s' || mstime1 || '' || mstime2 || '' || mstime || '' || mstimeind || '%

' || CRLF, + FALSE); + + -- Output name + write_data('' || fnames(i) || '' || CRLF, FALSE); + + -- Output table + write_data( + '' || CRLF || + '' || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ''|| CRLF || + '' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + '' || CRLF, FALSE); + + -- output Parent info. + sql_stmt := 'SELECT pid, stime, ftime, calls, pname, phash ' || + 'FROM dbmshp_pcdiftab WHERE names||hash = :b1 and cid = :b2 ' || + 'ORDER BY stime desc'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + pids, pstimes, pftimes, pcalls, pnames, hashtab2 + USING fnames(i)||hashtab(i), sids(i); + + write_data( + '' || CRLF || + ' ' || CRLF || + '' || CRLF, FALSE); + + -- entry + IF (pids.COUNT = 0) THEN + write_data( + '' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + '' || CRLF, FALSE); + END IF; + + FOR j in 1..pnames.COUNT LOOP + IF (pstimes(j) <> 0 OR pftimes(j) <> 0) THEN + dtime := pstimes(j)-pftimes(j); + + write_data( + '' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + '' || CRLF, FALSE); + END IF; + END LOOP; + + -- output children info. + sql_stmt := 'SELECT cid, stime, ftime, calls, names, hash ' || + 'FROM dbmshp_pcdiftab WHERE pname||phash = :b1 and pid = :b2 ' || + 'order by stime asc'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT + INTO cids, pstimes, pftimes, pcalls, cnames, hashtab2 + USING fnames(i)||hashtab(i), sids(i); + + IF cids.COUNT > 0 THEN + write_data('' || CRLF, FALSE); + END IF; + + FOR j in 1..cids.COUNT LOOP + IF (pstimes(j) <> 0 OR pftimes(j) <> 0) THEN + dtime := pstimes(j)-pftimes(j); + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + END IF; + END LOOP; + + write_data('
Subtree Time DeltaFunction Time DeltaDescendants Time DeltaCalls DeltaFunction Name
' || stimes(i) || '' || ftimes(i) || '' || dtimes(i) || '' || calls(i) || '' || CRLF || + ' ' || fnames(i) || '' || CRLF || '
' || CRLF || + ' Parents:' || CRLF || + '
' || stimes(i) || '' || ftimes(i) || '' || dtimes(i) || '' || calls(i) || '' || CRLF || + ' root' || CRLF || + '
' || pstimes(j) || '' || pftimes(j) || '' || dtime || '' || pcalls(j) || '' || CRLF || + ' ' || pnames(j) || '' || CRLF || '
Children:
' || pstimes(j) || '' || pftimes(j) || '' || dtime || '' || pcalls(j) || '' || CRLF || + ' ' || cnames(j) || '' || CRLF || '

'|| CRLF, FALSE); + END LOOP; + + write_data( + '' || CRLF || '', + TRUE); + write_plstinfo; + END; + + /* analyze_reports takes a location, a file name and a run_id + * and generates a report based on data collected in the trace + * file located at directory object with run_id + * . + * + * The report is composed of several HTML files including: + * 1. A time analysis report + * 2. A subtree time report + * 3. A function time report + * 4. A function call count report + * 5. A function name report + * 6. A mean subtree time report + * 7. A mean function time report + * 8. A group by namespace report + * 9. A group by module name report + * 10.A total function call count report + * 11.A module name report + * 12.A parent child diff report + * + * There are many other potential reports that one could wish + * to generate. These reports and their implementations demonstrate + * ways of leveraging the trace information left in the PL/SQL trace + * files. + */ + PROCEDURE analyze_reports(location IN VARCHAR2, + fname IN VARCHAR2, + run_id IN NUMBER) IS + BEGIN + + filename := fname; + filelocation := location; + runid := run_id; + + -- Get total number of time + time_mode := 'Elapsed Time'; + sql_stmt := + 'SELECT SUM(FUNCTION_ELAPSED_TIME) FROM dbmshp_function_info ' || + 'WHERE runid = :b1'; + EXECUTE IMMEDIATE sql_stmt INTO total_time USING runid; + + -- Get total number of function calls + sql_stmt := 'SELECT SUM(CALLS) FROM dbmshp_function_info ' || + 'WHERE runid = :b1'; + EXECUTE IMMEDIATE sql_stmt INTO total_calls USING runid; + + -- Generate PL/SQL Time Analysis report + fullname := filename||'.html'; + single_run_start_page; + + -- Generate Sort by Subtree Time report + fullname := filename||'_subtree.html'; + function_level_report(DBMSHP_SUBTREETIME, FALSE); + + -- Generate Sort by Function Time report + fullname := filename||'_function.html'; + function_level_report(DBMSHP_FUNCTIONTIME, FALSE); + + -- Generate Sort by Function Call Count report + fullname := filename||'_calls.html'; + function_level_report(DBMSHP_CALLS, FALSE); + + -- Generate Sort by Function Name report + fullname := filename||'_name.html'; + function_level_report(DBMSHP_NAME, FALSE); + + -- Generate Sort by Mean Subtree Time report + fullname := filename||'_mean_subtree.html'; + function_level_report(DBMSHP_MEAN_SUBTREETIME, TRUE); + + -- Generate Sort by Mean Function Time report + fullname := filename||'_mean_function.html'; + function_level_report(DBMSHP_MEAN_FUNCTIONTIME, TRUE); + + -- Generate Group by Namespace report + fullname := filename||'_namespace.html'; + namespace_report; + + -- Generate Group by Module Name reports + -- Sorted by Total Function Time + fullname := filename||'_module_function.html'; + module_report(DBMSHP_FUNCTIONTIME); + + -- Sorted by Total Function Call Count + fullname := filename||'_module_calls.html'; + module_report(DBMSHP_CALLS); + + -- Sorted by Module Name + fullname := filename||'_module_name.html'; + module_report(DBMSHP_NAME); + + -- Generate Parent Child Time report + fullname := filename||'_parent_child.html'; + parent_child_report; + END; + + PROCEDURE analyze_reports(location IN VARCHAR2, + fname IN VARCHAR2, + run1_id IN NUMBER, + run2_id IN NUMBER) IS + BEGIN + + filename := fname; + filelocation := location; + runid := run1_id; + runid2 := run2_id; + + time_mode := 'Elapsed Time'; + + -- Generate PL/SQL Time Diff Summary report + fullname := filename || '.html'; + + IF (diff_mode_start_page = TRUE) THEN + -- Generate performance regression report + fullname := filename || '_fr.html'; + performance_report('ftime > 0', 'Regressions'); + + -- Generate performance improvement report + fullname := filename || '_fi.html'; + performance_report('ftime < 0', 'Improvements'); + + -- Generate Sort by Total Subtree Time report + fullname := filename || '_ns.html'; + diff_function_level_report(DBMSHP_SUBTREETIME); + + -- Generate Sort by Total Function Time report + fullname := filename || '_nf.html'; + diff_function_level_report(DBMSHP_FUNCTIONTIME); + + -- Generate Sort by Function Call Count report + fullname := filename || '_nc.html'; + diff_function_level_report(DBMSHP_CALLS); + + -- Generate Sort by Function Name report + fullname := filename || '_nn.html'; + diff_function_level_report(DBMSHP_NAME); + + -- Generate Group by Namespace reports + fullname := filename || '_nsp.html'; + diff_namespace_report; + + -- Generate Group by Module Name reports + -- Sorted by Total Function Time + fullname := filename || '_2f.html'; + diff_module_report(DBMSHP_FUNCTIONTIME); + + -- Sorted by Total Function Call Count + fullname := filename || '_2c.html'; + diff_module_report(DBMSHP_CALLS); + + -- Sorted by Module Name + fullname := filename || '_2n.html'; + diff_module_report(DBMSHP_NAME); + + -- Generate Parent Child Difference reports + fullname := filename || '_pc.html'; + diff_parent_child_report; + + EXECUTE IMMEDIATE 'DROP VIEW dbmshp_t1'; + EXECUTE IMMEDIATE 'DROP VIEW dbmshp_t2'; + EXECUTE IMMEDIATE 'DROP VIEW dbmshp_diftab'; + EXECUTE IMMEDIATE 'DROP VIEW dbmshp_pct1'; + EXECUTE IMMEDIATE 'DROP VIEW dbmshp_pct2'; + EXECUTE IMMEDIATE 'DROP VIEW dbmshp_pcdiftab'; + END IF; + END; + +BEGIN + dbms_lob.createtemporary(myclob, true); + page_size := dbms_lob.getchunksize(myclob); + + -- Write a multiple of the page size that is closest to 32K + IF (page_size < 32767) THEN + page_size := 32767 / page_size * page_size; + END IF; + +END dbmshpro_demo; +/ +show errors + diff --git a/dmkmdemo.java b/dmkmdemo.java new file mode 100644 index 0000000..3b085d6 --- /dev/null +++ b/dmkmdemo.java @@ -0,0 +1,1011 @@ +// Copyright (c) 2001, 2006, Oracle. All rights reserved. +// File: dmkmdemo.java +// Generic api imports +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import java.util.Collection; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Set; +import java.util.TreeMap; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.NamedObject; +import javax.datamining.algorithm.kmeans.ClusteringDistanceFunction; +import javax.datamining.algorithm.kmeans.KMeansSettingsFactory; +import javax.datamining.base.Task; +import javax.datamining.clustering.Cluster; +import javax.datamining.clustering.ClusteringApplySettings; +import javax.datamining.clustering.ClusteringApplySettingsFactory; +import javax.datamining.clustering.ClusteringModel; +import javax.datamining.clustering.ClusteringSettings; +import javax.datamining.clustering.ClusteringSettingsFactory; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.AttributeType; +import javax.datamining.data.Interval; +import javax.datamining.data.IntervalClosure; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.rule.CompoundPredicate; +import javax.datamining.rule.Rule; +import javax.datamining.rule.SimplePredicate; +import javax.datamining.statistics.AttributeStatisticsSet; +import javax.datamining.statistics.UnivariateStatistics; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; + +import oracle.dmt.jdm.OraPLSQLMappings; +import oracle.dmt.jdm.algorithm.kmeans.OraKMeansSettings; +import oracle.dmt.jdm.algorithm.kmeans.OraSplitCriterion; +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.clustering.OraCluster; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.rule.OraSimplePredicate; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformImpl; +import oracle.dmt.jdm.transform.normalize.OraNormalizeType; + + +// Java Data Mining (JDM) standard imports +// Oracle Java Data Mining (JDM) implemented api imports + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to cluster data records based on their Eucledian distance similarity. +* The k-Means (KM) clustering model provides the user with insight about the +* discovered groups. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Segment the demographic data into 10 clusters and study the individual +* clusters. Apply clustering model to new data and rank the clusters on probability. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created +* in the user schema using CUSTOMERS, COUNTRIES and SUPPLIMENTARY_DEMOGRAPHICS +* tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics and purchasing +* details for scoring against the clustering model. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* In general, attributes need to be similar scale in order to be treated +* equally during the model build. Therefore normalization is required. +* The prepareData() method illustrates the normalization of the build and apply +* data. +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a clustering model using KM algorithm. +* Apply Model: +* The results of an APPLY operation will contain a list of the cluster +* identifiers for each case, and the associated probabilities. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +public class + +dmkmdemo + extends Object +{ + //Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClusteringSettingsFactory m_clusFactory; + private static KMeansSettingsFactory m_kmeansFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClusteringApplySettingsFactory m_applySettingsFactory; + private static OraNormalizeTransformFactory m_normalizeXformFactory; + private static OraTransformationTaskFactory m_xformTaskFactory; + // Global constants used for formatting output + private static String TAB = " "; + private static String CR = "\n"; + private static String CR_TAB = "\n "; + private static String HORZ_LINE = "----"; + private static String UNDERLINE = + "*************************************"; + private static String LEAF_CLUSTERS_HEADER = + "* Leaf clusters *"; + private static String RULES_CLUSTERS_HEADER = + "* Rules *"; + private static String RULES_CLUSTERS_HIERARCHY_HEADER = + "* Printing clusters hierarchy *"; + + public static void main(String[] args) + { + try + { + if ((args.length != 0) & (args.length != 3)) + { + System.out.println("Usage: java dmkmdemo "); + System.out.println(" or: java dmkmdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + //1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Save task to build a model + buildModel(); + // 5. Save task to apply a model + applyModel(); + // 6. Execute build task and apply task follows + m_dmeConn.execute("kmBuildTask_jdm"); + //7. Monitor execution of the tasks + monitorTaskExecutionProcess(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + // 7. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + } //Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() + throws JDMException + { + m_pdsFactory = + (PhysicalDataSetFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalDataSet"); + m_paFactory = + (PhysicalAttributeFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalAttribute"); + m_clusFactory = + (ClusteringSettingsFactory) m_dmeConn.getFactory("javax.datamining.clustering.ClusteringSettings"); + m_kmeansFactory = + (KMeansSettingsFactory) m_dmeConn.getFactory("javax.datamining.algorithm.kmeans.KMeansSettings"); + m_buildFactory = + (BuildTaskFactory) m_dmeConn.getFactory("javax.datamining.task.BuildTask"); + m_dsApplyFactory = + (DataSetApplyTaskFactory) m_dmeConn.getFactory("javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = + (ClusteringApplySettingsFactory) m_dmeConn.getFactory("javax.datamining.clustering.ClusteringApplySettings"); + m_normalizeXformFactory = + (OraNormalizeTransformFactory) m_dmeConn.getFactory("oracle.dmt.jdm.transform.normalize.OraNormalizeTransform"); + m_xformTaskFactory = + (OraTransformationTaskFactory) m_dmeConn.getFactory("oracle.dmt.jdm.task.OraTransformationTask"); + } + + /** + * This method illustrates how to build a clustering mining model using + * the kMeans algorithm. + * + * After completing the build task, the model named "kmModel_jdm" will + * be created. + * + * @exception JDMException if model build failed + */ + public static void buildModel() + throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + buildData.addAttribute(pa); + m_dmeConn.saveObject("kmBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // Create kMeans algorithm settings + OraKMeansSettings kmAlgo = + (OraKMeansSettings) m_kmeansFactory.create(); + kmAlgo.setDistanceFunction(ClusteringDistanceFunction.euclidean); + kmAlgo.setMaxNumberOfIterations(10); + kmAlgo.setMinErrorTolerance(0.01); + kmAlgo.setSplitCriterion(OraSplitCriterion.clusterVariance); + kmAlgo.setNumberOfBins(10); + kmAlgo.setBlockGrowth(2); + kmAlgo.setMinPercentageAtrrSupport(0.1); + + // 3. Create ClusteringSettings + ClusteringSettings buildSettings = m_clusFactory.create(); + buildSettings.setAlgorithmSettings(kmAlgo); + buildSettings.setMaxNumberOfClusters(10); + ((OraBuildSettings) buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject("kmBuildSettings_jdm", buildSettings, true); + // 4. Create, save & execute Build Task + BuildTask buildTask = //Build data specification + //Mining function settings name + //Mining model name + m_buildFactory.create("kmBuildData_jdm", "kmBuildSettings_jdm", + "kmModel_jdm"); + buildTask.setDescription("kmBuildTask_jdm"); + saveTask(buildTask, "kmBuildTask_jdm", null); + + } + + /** + * + * For a descriptive mining function like Clustering, "Scoring" involves + * providing the probability values for each cluster. + * After completing the apply task, an apply output table + * "km_apply_output_jdm" will be created at the user specfied location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("kmApplyData_jdm", applyData, true); + //2. Create & save ClassificationApplySettings + ClusteringApplySettings clusAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject("kmApplySettings_jdm", clusAS, true); + + //3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("kmApplyData_jdm", "kmModel_jdm", + "kmApplySettings_jdm", + "km_apply_output_jdm"); + saveTask(applyTask, "kmApplyTask_jdm", "kmBuildTask_jdm"); + } + + /** + * This method monitor task execution initiated by the first task + * in the sequence of dependent tasks. In addition, this method displays + * task output results (if any). + * @throws JDMException + */ + public static void monitorTaskExecutionProcess() + throws JDMException + { + //1. Monitor BuildTask + //Wait for the completion of the task + System.out.print("Waiting for the completion of kmBuildTask_jdm. "); + ExecutionStatus buildTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("kmBuildTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(buildTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + //Restore the model from the DME and explore the details of the model + ClusteringModel model = + (ClusteringModel) m_dmeConn.retrieveObject("kmModel_jdm", + NamedObject.model); + displayKMModelDetails(model); + //2. Monitor applyTask + //Wait for the completion of the task + { + System.out.print("Waiting for the completion of kmApplyTask_jdm. "); + ExecutionStatus applyTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("kmApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(applyTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + //Display results + displayScoringResults(); + } + else + { + System.out.println("It is at state:" + + applyTaskCompletionStatus.getState().name() + + ((applyTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + applyTaskCompletionStatus.getDescription())); + } + } + } + else + { + System.out.println("It is at state:" + + buildTaskCompletionStatus.getState().name() + + ((buildTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + buildTaskCompletionStatus.getDescription())); + } + } + + /** + * Shows scoring results. + * BUSINESS CASE 1: List the clusters into which the customers in this + * dataset have been grouped. + * BUSINESS CASE 2: List ten most representative (based on likelihood) + * customers of cluster 2. + */ + public static void displayScoringResults() + { + // BUSINESS CASE 1: List the clusters into which the customers in this + // dataset have been grouped. + String sqlCase1 = + "SELECT clus, COUNT(*) AS CNT FROM " + " (SELECT cluster_id CLUS, " + + " ROW_NUMBER() OVER " + + " (PARTITION BY CUST_ID ORDER BY PROBABILITY DESC) CLUS_RNK " + + " FROM km_apply_output_jdm) " + "WHERE CLUS_RNK = 1 " + + "GROUP BY CLUS ORDER BY CNT DESC"; + + Statement stmt = null; + ResultSet rs = null; + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + try + { + stmt = dbConn.createStatement(); + rs = stmt.executeQuery(sqlCase1); + System.out.println("Cluster ID Count"); + System.out.println("----------------------------"); + while (rs.next()) + { + int clus = rs.getInt(1); + int cnt = rs.getInt(2); + System.out.println(TAB + clus + TAB + TAB + cnt); + } + } + catch (SQLException anySqlExp) + { + System.out.println(anySqlExp); + } + finally + { + try + { + stmt.close(); + } + catch (Exception anySqlExp) + { + } + } + + // BUSINESS CASE 2: List ten most representative (based on likelihood) + // customers of cluster 2 + + String sqlCase2 = + "SELECT * from " + " (SELECT cust_id, probability from km_apply_output_jdm " + + " WHERE CLUSTER_ID = 2 ORDER BY probability DESC) " + + "WHERE ROWNUM < 11"; + + stmt = null; + rs = null; + try + { + stmt = dbConn.createStatement(); + rs = stmt.executeQuery(sqlCase2); + System.out.println("Cust_ID Probability"); + System.out.println("----------------------------"); + while (rs.next()) + { + int custid = rs.getInt(1); + String probability = rs.getString(2); + System.out.println(TAB + custid + TAB + TAB + probability); + } + } + catch (SQLException anySqlExp) + { + System.out.println(anySqlExp); + } + finally + { + try + { + stmt.close(); + } + catch (Exception anySqlExp) + { + } + } + } + + /** + * This method saves the given task with the specified task name and task + * dependency (parent task) in the DME. + * + * @param taskObj task object + * @param taskName name of the task + * @param parentTaskName name of the parent task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static void saveTask(Task taskObj, String taskName, + String parentTaskName) + throws JDMException + { + if (parentTaskName != null) + ((OraTask) taskObj).addDependency(parentTaskName); //Since OJDM 11.1 + ((OraTask) taskObj).overwriteOutput(true); //Since OJDM 11.1 + m_dmeConn.saveObject(taskName, taskObj, true); + } + + /** + * This method displayes KM model details. + * + * @param model to be presented + * + * @exception JDMException if failed to retrieve model details + */ + public static void displayKMModelDetails(ClusteringModel model) + throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + System.out.println("Clustering model details:"); + System.out.println(TAB + "Number of clusters: " + + model.getNumberOfClusters()); + System.out.println(TAB + "Number of tree levels: " + + model.getNumberOfLevels()); + Collection clusters = model.getClusters(); + if (clusters == null || clusters.isEmpty() == true) + { + System.out.println("Unable to retrieve clusters."); + return; + } + + // Display root cluster(s) + Collection vRootClusters = model.getRootClusters(); + Cluster[] rootCluster = null; + if (vRootClusters != null && vRootClusters.isEmpty() == false) + { + rootCluster = + (Cluster[]) vRootClusters.toArray(new Cluster[vRootClusters.size()]); + if (rootCluster != null) + System.out.println(TAB + "Root Cluster Id: " + + rootCluster[0].getClusterId()); + } + + // Display leaf clusters + Collection vLeafClusters = model.getLeafClusters(); + if (vLeafClusters != null && vLeafClusters.isEmpty() == false) + { + Cluster[] leafClusters = + (Cluster[]) vLeafClusters.toArray(new Cluster[vLeafClusters.size()]); + System.out.println(UNDERLINE); + System.out.println(LEAF_CLUSTERS_HEADER); + System.out.println(UNDERLINE); + for (int ni = 0; ni < leafClusters.length; ni++) + { + printSingleClusterDetails(leafClusters[ni]); + if (ni == 0) + { + // display first leaf cluster statistics + printClusterStatistics(model, leafClusters[ni], 1); + } + } + } + + // Display all model rules + Collection vRules = model.getRules(); + if (vRules != null && vRules.isEmpty() == false) + { + Rule[] rules = (Rule[]) vRules.toArray(new Rule[vRules.size()]); + System.out.println(CR + CR + UNDERLINE); + System.out.println(RULES_CLUSTERS_HEADER); + System.out.println(UNDERLINE); + for (int rl = 0; rl < rules.length; rl++) + { + printRuleNoDetails(rules[rl], 0); + } + } + + if (rootCluster != null) + { + // print hierarchy + System.out.println(CR + CR + UNDERLINE); + System.out.println(RULES_CLUSTERS_HIERARCHY_HEADER); + System.out.println(UNDERLINE); + // 1.print root + printRootClusterDetails(rootCluster[0]); + // 1.print children + Cluster[] children = rootCluster[0].getChildren(); + int indent = 0; + if (children != null) + { + for (int k = 0; k < children.length; k++) + { + printRecursiveClusterDetails(model, children[k], indent); + } + } + return; + } + + // print flat structure + Cluster[] arrayClusters = + (Cluster[]) clusters.toArray(new Cluster[clusters.size()]); + for (int ni = 0; ni < arrayClusters.length; ni++) + { + printSingleClusterDetails(arrayClusters[ni]); + } + System.out.println(CR + UNDERLINE + CR); + } + + + private static String getIndentation(int indent, String sText) + { + StringBuffer sbIndent = new StringBuffer(TAB); + for (int in = 0; in < indent; in++) + sbIndent.append(TAB); + + StringBuffer outPut = new StringBuffer(sbIndent.toString()); + outPut.append(sText); + return outPut.toString(); + } + + /** + * This method recursively displayes Cluster details. + * + * @param model model to be presented + * @param cluster current cluster which details are being presented + * @param indent indentation level to illustrate cluster parent-child relation + * + * @exception JDMException if failed to retrieve cluster details + */ + public static void printRecursiveClusterDetails(ClusteringModel model, + Cluster cluster, + int indent) + throws JDMException + { + indent++; + System.out.println(getIndentation(indent, + "Cluster Id: " + cluster.getClusterId()) + + CR + + getIndentation(indent, "Case Count: " + cluster.getCaseCount()) + + CR + + getIndentation(indent, "Tree Level: " + cluster.getLevel()) + + CR + + getIndentation(indent, "Dispersion: " + ((OraCluster) cluster).getDispersion()) + + CR + + getIndentation(indent, "Parent's id: " + (cluster.getParent() != + null? + String.valueOf(cluster.getParent().getClusterId()): + ""))); + + Cluster[] ancestors = cluster.getAncestors(); + if (ancestors != null) + { + StringBuffer sbTab = new StringBuffer("Anchestors"); + if (ancestors.length == 0) + sbTab.append(" : None"); + for (int j = 0; j < ancestors.length; j++) + { + for (int sp = 0; sp < j; sp++) + sbTab.append(":" + ancestors[j].getClusterId() + " "); + } + System.out.print(getIndentation(indent, sbTab.toString())); + } + + Cluster[] children = cluster.getChildren(); + if (children != null) + { + System.out.println(CR + getIndentation(indent, "Children:")); + for (int k = 0; k < children.length; k++) + { + Cluster childCluster = children[k]; + printRecursiveClusterDetails(model, childCluster, indent); + } + } + else + { + System.out.print(CR + + getIndentation(indent, "No child clusters" + CR)); + Rule rule = cluster.getRule(); + //Print Rule Details for leaf clusters only + printRuleDetails(rule, indent); + } + indent--; + } + + /** + * This method prints Rules details with antecedent and consequent information. + * + * @param rule rule which details are being presented + * @param indent indentation level to illustrate cluster parent-child relation + * + * @exception JDMException if failed to retrieve cluster details + */ + public static void printRuleDetails(Rule rule, int indent) + { + System.out.println(CR_TAB + + getIndentation(indent, "Rule number:" + rule.getRuleIdentifier()) + + CR_TAB + TAB + + getIndentation(indent, "Support: " + rule.getSupport()) + + CR_TAB + TAB + + getIndentation(indent, "Confidence: " + + rule.getConfidence())); + CompoundPredicate antecedent = + (CompoundPredicate) rule.getAntecedent(); + System.out.println(CR_TAB + TAB + + getIndentation(indent, ("Antecedent: "))); + printAntecedent(antecedent, indent); + + CompoundPredicate consequent = + (CompoundPredicate) rule.getConsequent(); + System.out.println(CR_TAB + TAB + + getIndentation(indent, ("Consequent: "))); + printConsequent(consequent, indent); + } + + /** + * This method prints Rules details without antecedent and consequent information. + * + * @param rule rule which details are being presented + * @param indent indentation level to illustrate cluster parent-child relation + */ + public static void printRuleNoDetails(Rule rule, int indent) + { + System.out.println(CR_TAB + + getIndentation(indent, "Rule number:" + rule.getRuleIdentifier()) + + CR_TAB + TAB + + getIndentation(indent, "Support: " + rule.getSupport()) + + CR_TAB + TAB + + getIndentation(indent, "Confidence: " + + rule.getConfidence())); + } + + /** + * This method prints antecedent information. + * + * @param predicate antecedent being presented + * @param indent indentation level to illustrate cluster parent-child relation + * + * @exception JDMException if failed to retrieve antecedent details + */ + public static void printAntecedent(CompoundPredicate predicate, + int indent) + { + try + { + SimplePredicate[] sps = + (SimplePredicate[]) predicate.getPredicates(); + if (sps == null) + return; + + // combine predicates by attribute name + Hashtable htNamePredicateMap = new Hashtable(); + for (int i = 0; i < sps.length; i++) + { + StringBuffer simplePredicate = printSimplePredicate(sps[i]); + String attrName = sps[i].getAttributeName(); + StringBuffer attrTotalPredicate = + (StringBuffer) htNamePredicateMap.get(attrName); + if (attrTotalPredicate == null) + htNamePredicateMap.put(attrName, simplePredicate); + else + { + attrTotalPredicate.append(" AND " + simplePredicate); + } + } + Enumeration en = htNamePredicateMap.keys(); + while (en.hasMoreElements()) + { + String name = (String) en.nextElement(); + StringBuffer sb = (StringBuffer) htNamePredicateMap.get(name); + System.out.println(getIndentation(indent, + (TAB + TAB + TAB + sb.toString()))); + } + } + catch (Exception e) + { + System.out.println("Error printing Antecedant"); + } + } + + /** + * This method prints consequent information. + * + * @param predicate consequent being presented + * @param indent indentation level to illustrate cluster parent-child relation + * + * @exception JDMException if failed to retrieve consequent details + */ + public static void printConsequent(CompoundPredicate predicate, + int indent) + { + try + { + SimplePredicate[] sps = + (SimplePredicate[]) predicate.getPredicates(); + if (sps == null) + return; + + for (int i = 0; i < sps.length; i++) + { + StringBuffer simplePredicate = printSimplePredicate(sps[i]); + if (i < sps.length - 1) + simplePredicate.append(" AND "); + System.out.println(getIndentation(indent, + TAB + TAB + TAB + simplePredicate.toString())); + } + } + catch (Exception e) + { + System.out.println("Error printing Consequent"); + } + } + + /** + * This method prints SimplePredicate information. + * + * @param predicate SimplePredicate being presented + * + * @exception JDMException if failed to retrieve SimplePredicate details + */ + public static StringBuffer printSimplePredicate(SimplePredicate predicate) + throws JDMException + { + StringBuffer sb = new StringBuffer(); + if (predicate.isNumericalValue()) + { + //((OraSimplePredicate)predicate).getComparisonOperatorValue() + " " + + sb.append(predicate.getAttributeName() + " " + + OraPLSQLMappings.getComparisonOperatorValue_tree(((OraSimplePredicate) predicate).getComparisonOperator()) + + " " + predicate.getNumericalValue()); + } + else + { + //((OraSimplePredicate)predicate).getComparisonOperatorValue() + " " + sb = + new StringBuffer(predicate.getAttributeName() + " " + OraPLSQLMappings.getComparisonOperatorValue_tree(((OraSimplePredicate) predicate).getComparisonOperator()) + + " "); + Object[] inValues = predicate.getCategoryValues(); + if (inValues != null) + { + for (int i = 0; i < inValues.length; i++) + { + sb.append(inValues[i]); + if (i != inValues.length - 1) + sb.append(","); + } + } + } + return sb; + } + + /** + * This method shows details of the root cluster. + * + * @param cluster root cluster + * + * @exception JDMException if failed to retrieve root cluster details + */ + public static void printRootClusterDetails(Cluster cluster) + throws JDMException + { + System.out.println(CR + "Root Cluster Id: " + cluster.getClusterId() + + CR_TAB + "Case Count: " + cluster.getCaseCount() + + CR_TAB + "Tree Level: " + cluster.getLevel() + + CR_TAB + "Dispersion: " + + ((OraCluster) cluster).getDispersion() + CR_TAB + + "Children:"); + } + + /** + * This method shows details of any cluster. + * + * @param cluster clusterbeing presented + * + * @exception JDMException if failed to retrieve this cluster details + */ + public static void printSingleClusterDetails(Cluster cluster) + throws JDMException + { + System.out.println(CR + "Cluster Id: " + cluster.getClusterId() + + CR_TAB + "Case Count: " + cluster.getCaseCount() + + CR_TAB + "Tree Level: " + cluster.getLevel() + + CR_TAB + "Dispersion: " + + ((OraCluster) cluster).getDispersion() + CR_TAB + + "Parent's id: " + + (cluster.getParent() != null? String.valueOf(cluster.getParent().getClusterId()): + "") + CR_TAB + "Is root Cluster: " + + cluster.isRoot() + CR_TAB + "Is leaf Cluster: " + + cluster.isLeaf()); + + Cluster[] ancestors = cluster.getAncestors(); + StringBuffer sbTab = new StringBuffer(TAB + "Anchestors "); + if (ancestors != null) + { + for (int j = 0; j < ancestors.length; j++) + { + for (int sp = 0; sp < j; sp++) + sbTab.append(":" + ancestors[j].getClusterId() + " "); + } + } + else + { + sbTab.append("None"); + } + System.out.print(sbTab.toString()); + + Cluster[] children = cluster.getChildren(); + System.out.println(CR_TAB + "Children:"); + if (children != null) + { + for (int k = 0; k < children.length; k++) + { + Cluster childCluster = children[k]; + System.out.print(TAB + TAB + "Child: " + + childCluster.getClusterId() + CR); + } + System.out.println(CR); + } + else + { + System.out.print(TAB + TAB + "None"); + } + } + + /** + * This method shows cluster statistics. + * + * @param model model being presented + * @param cluster cluster being presented + * @param indent indentation level to illustrate cluster parent-child relation + * + * @exception JDMException if failed to retrieve this cluster statistics + */ + public static void printClusterStatistics(ClusteringModel model, + Cluster cluster, int indent) + { + try + { + ModelSignature modelSignature = model.getSignature(); + + AttributeStatisticsSet attrStat = cluster.getStatistics(); + if (attrStat == null) + return; + TreeMap centroids = ((OraCluster) cluster).getCentroids(); + if (centroids == null || centroids.isEmpty()) + { + System.out.println("Error: cluster " + cluster.getClusterId() + + " does not contain statsitics"); + return; + } + Set centroidKeys = centroids.keySet(); + Iterator attributesNames = centroidKeys.iterator(); + while (attributesNames.hasNext()) + { + String attributeName = (String) attributesNames.next(); + SignatureAttribute sa = modelSignature.getAttribute(attributeName); + AttributeType aType = sa.getAttributeType(); + UnivariateStatistics stats = attrStat.getStatistics(attributeName); + double[] frequencies = stats.getProbabilities(); + System.out.println(CR_TAB + + getIndentation(indent, "Statistics for attribute: " + + attributeName)); + System.out.println(TAB + getIndentation(indent, UNDERLINE)); + if (aType.equals(AttributeType.numerical)) + { + Interval[] ranges = (Interval[]) stats.getValues(); + if (ranges != null) + { + System.out.println(TAB + TAB + + getIndentation(indent, "Bin Id" + TAB + + TAB + TAB + "Range" + TAB + + TAB + TAB + TAB + + "Frequency")); + for (int in = 0; in < ranges.length; in++) + { + Interval bin = ranges[in]; + IntervalClosure closure = bin.getIntervalClosure(); + String openParenthesis = + ((closure.equals(IntervalClosure.openClosed) || + closure.equals(IntervalClosure.openOpen))? "( ": "[ "); + String closeParenthesis = + ((closure.equals(IntervalClosure.openOpen) || + closure.equals(IntervalClosure.closedOpen))? " )": + " ]"); // bin Id + // range + //frequency + System.out.println(TAB + TAB + + getIndentation(indent, String.valueOf(in + + 1)) + + TAB + TAB + + getIndentation(indent, openParenthesis + + bin.getStartPoint() + + " - " + bin.getEndPoint() + + closeParenthesis) + TAB + + TAB + + getIndentation(indent, String.valueOf((int) frequencies[in]))); + } + } + } + else if (aType.equals(AttributeType.categorical)) + { + Object[] values = stats.getValues(); + if (values != null) + { + System.out.println(TAB + TAB + + getIndentation(indent, "Bin Id" + TAB + + "Category" + TAB + + "Frequency")); + for (int in = 0; in < values.length; in++) + { + // bin Id + //value + //frequency + System.out.println(TAB + TAB + + getIndentation(indent, String.valueOf(in + + 1)) + + TAB + TAB + values[in] + TAB + TAB + + getIndentation(indent, + String.valueOf((int) frequencies[in]))); + } + } + } + } + } + catch (Exception e) + { + System.out.println("Error printing statsitics for cluster: " + + cluster.getClusterId()); + } + } + + private static void clean() + { + //Drop the model + try + { + m_dmeConn.removeObject("kmModel_jdm", NamedObject.model); + } + catch (JDMException jdmExp) + { + } + } +} + diff --git a/dmkmdemo.sql b/dmkmdemo.sql new file mode 100644 index 0000000..02edcf6 --- /dev/null +++ b/dmkmdemo.sql @@ -0,0 +1,378 @@ +Rem +Rem $Header: dmkmdemo.sql 25-oct-2007.11:35:30 ramkrish Exp $ +Rem +Rem dmkmdemo.sql +Rem +Rem Copyright (c) 2003, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmkmdemo.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a clustering model +Rem using the K-Means algorithm +Rem and data in the SH (Sales History) schema in the RDBMS. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem jiawang 08/02/06 - ENABLE ADP +Rem ktaylor 07/11/05 - Minor edits to comments +Rem jcjeon 01/18/05 - add column format +Rem mmcampos 11/09/04 - edit comments +Rem ramkrish 10/04/04 - add data analysis and comments/cleanup +Rem jiawang 07/22/04 - Add order by to fix sorting dif +Rem pstengar 10/17/03 - added denormalization of model details +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET linesize 140 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Segment the demographic data into 10 clusters and study the individual +-- clusters. Rank the clusters on probability. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +-- The data for this sample is composed from base tables in SH Schema +-- (See Sample Schema Documentation) and presented through these views: +-- mining_data_build_v (build data) +-- mining_data_test_v (test data) +-- mining_data_apply_v (apply data) +-- (See dmsh.sql for view definitions). +-- + +----------- +-- ANALYSIS +----------- +-- For clustering using KM, perform the following on mining data. +-- +-- 1. Use Data Auto Preparation +-- + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old model with same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('KM_SH_Clus_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE km_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- K-Means is the default Clustering algorithm. For this sample, +-- we skip specification of any overrides to defaults +-- +-- Uncomment the appropriate sections of the code below for +-- changing settings values. +-- +set echo on +CREATE TABLE km_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); + +BEGIN + INSERT INTO km_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.kmns_distance,dbms_data_mining.kmns_euclidean); + + INSERT INTO km_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.prep_auto,dbms_data_mining.prep_auto_on); + -- Other examples of overrides are: + -- (dbms_data_mining.kmns_iterations,3); + -- (dbms_data_mining.kmns_block_growth,2); + -- (dbms_data_mining.kmns_conv_tolerance,0.01); + -- (dbms_data_mining.kmns_split_criterion,dbms_data_mining.kmns_variance); + -- (dbms_data_mining.kmns_min_pct_attr_support,0.1); + -- (dbms_data_mining.kmns_num_bins,10); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'KM_SH_Clus_sample', + mining_function => dbms_data_mining.clustering, + data_table_name => 'mining_data_build_v', + case_id_column_name => 'cust_id', + settings_table_name => 'km_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'KM_SH_CLUS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'KM_SH_CLUS_SAMPLE' +ORDER BY attribute_name; + +------------------------- +-- DISPLAY MODEL METADATA +-- +column mining_function format a20 +column algorithm format a20 +SELECT mining_function, algorithm, model_size + FROM user_mining_models + WHERE model_name = 'KM_SH_CLUS_SAMPLE'; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Cluster details are best seen in pieces - based on the kind of +-- associations and groupings that are needed to be observed. +-- +-- CLUSTERS +-- For each cluster_id, provides the number of records in the cluster, +-- the parent cluster id, the level in the hierarchy, and dispersion - +-- which is a measure of the quality of the cluster, and computationally, +-- the sum of square errors. +-- +SELECT T.id clu_id, + T.record_count rec_cnt, + T.parent parent, + T.tree_level tree_level, + T.dispersion dispersion + FROM (SELECT * + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_KM( + 'KM_SH_Clus_sample')) + ORDER BY id) T + WHERE ROWNUM < 11; + +-- TAXONOMY +-- +SELECT clu_id, child_id + FROM (SELECT T.id clu_id, C.id child_id + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_KM( + 'KM_SH_Clus_sample')) T, + TABLE(T.child) C + ORDER BY T.id,C.id) + WHERE ROWNUM < 11; + +-- CENTROIDS FOR LEAF CLUSTERS +-- For each cluster_id, this output lists all the attributes that +-- constitute the centroid, with the mean (for numericals) or +-- mode (for categoricals), along with the variance from mean +-- +column aname format a30 +column mode_val format a60 +WITH +centroid_tab AS ( +SELECT T.id clu_id, + C.attribute_name aname, + C.mean mean_val, + C.mode_value mode_val, + C.variance variance + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_KM('KM_SH_Clus_sample')) T, + TABLE(T.centroid) C +ORDER BY T.id, C.attribute_name +) +SELECT clu_id, aname, mean_val, mode_val, variance + FROM centroid_tab + WHERE clu_id > 17 AND ROWNUM < 11; + +-- HISTOGRAM FOR TWO LEAF CLUSTERS +-- +WITH +hist_tab AS ( +SELECT T.id clu_id, + H.attribute_name aname, + H.lower_bound lower_b, + H.upper_bound upper_b, + H.count rec_cnt + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_KM('KM_SH_Clus_sample')) T, + TABLE(T.histogram) H +ORDER BY T.id, H.attribute_name, H.label +) +SELECT clu_id, aname, lower_b, upper_b, rec_cnt + FROM hist_tab + WHERE clu_id > 17 AND ROWNUM < 11; + +-- RULES FOR LEAF CLUSTERS +-- A rule_id corresponds to the associated cluster_id. The support +-- indicates the number of records (say M) that satisfies this rule. +-- This is an upper bound on the number of records that fall within +-- the bounding box defined by the rule. Each predicate in the rule +-- antecedent defines a range for an attribute, and it can be +-- interpreted as the side of a bounding box which envelops most of +-- the data in the cluster. +-- Confidence = M/N, where N is the number of records in the cluster +-- and M is the rule support defined as above. +-- +SELECT T.id rule_id, + T.rule.rule_support support, + T.rule.rule_confidence confidence + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_KM('KM_SH_Clus_sample')) T +ORDER BY T.id; + +-- RULE DETAILS FOR LEAF CLUSTERS +-- Attribute level details of each rule/cluster id. +-- For an attribute, support (say M) indicates the number of records that +-- fall in the attribute range specified in the rule antecedent where the +-- given attribute is not null. Confidence is a number between 0 and 1 +-- that indicates how relevant this attribute is in distinguishing the +-- the records in the cluster from all the records in the whole data. The +-- larger the number, more relevant the attribute. +-- +-- The query shown below reverse-transforms the data to its original +-- values, since build data was normalized. +-- +column aname format a25 +column op format a3 +column val format a60 +column support format 9999 +column confidence format 9.9999 +WITH +rule_tab AS ( +SELECT T.id rule_id, + A.attribute_name aname, + A.conditional_operator op, + NVL(A.attribute_str_value, + ROUND(A.attribute_num_value,4)) val, + A.attribute_support support, + A.attribute_confidence confidence + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_KM('KM_SH_Clus_sample')) T, + TABLE(T.rule.antecedent) A +ORDER BY T.id, A.attribute_name, support, confidence desc, val +) +SELECT rule_id, aname, op, val, support, confidence + FROM rule_tab + WHERE rule_id < 3; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +-- There is no specific set of testing parameters for Clustering. +-- Examination and analysis of clusters is the main method to prove +-- the efficacy of a clustering model. +-- + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- +-- For a descriptive mining function like Clustering, "Scoring" involves +-- providing the probability values for each cluster. + +-- Cleanup scoring data preparation objects for repeat runs + +BEGIN EXECUTE IMMEDIATE 'DROP TYPE Cattrs'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TYPE Cattr'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------------------------------------- +-- SCORE NEW DATA USING SQL DATA MINING FUNCTIONS +-- +------------------ +-- BUSINESS CASE 1 +-- List the clusters into which the customers in this +-- given dataset have been grouped. +-- +SELECT CLUSTER_ID(km_sh_clus_sample USING *) AS clus, COUNT(*) AS cnt + FROM mining_data_apply_v +GROUP BY CLUSTER_ID(km_sh_clus_sample USING *) +ORDER BY cnt DESC; + +------------------ +-- BUSINESS CASE 2 +-- List ten most representative (based on likelihood) customers of cluster 2 +-- +SELECT * + FROM (SELECT cust_id, CLUSTER_PROBABILITY(km_sh_clus_sample, 2 USING *) prob + FROM mining_data_apply_v + ORDER BY prob DESC) + WHERE ROWNUM < 11; + +column prob format 9.9999 +column attr format a15 +column val format a15 +column conf format 9.9999 +------------------ +-- BUSINESS CASE 3 +-- List the most relevant attributes (with confidence > 55%) +-- of each cluster in which a given customer (id 101362) belongs +-- to with > 20% likelihood. +-- +set echo off +CREATE TYPE Cattr AS OBJECT ( + attr VARCHAR2(30), + op VARCHAR2(3), + val VARCHAR2(30), + supp NUMBER, + conf NUMBER) +/ +set echo on +CREATE TYPE Cattrs AS TABLE OF Cattr +/ + +column attr format a30 +column op format a2 +WITH +clus_tab AS ( +SELECT id, + A.attribute_name aname, + A.conditional_operator op, + NVL(A.attribute_str_value, + ROUND(A.attribute_num_value,4)) val, + A.attribute_support support, + A.attribute_confidence confidence + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_KM('km_sh_clus_sample')) T, + TABLE(T.rule.antecedent) A + WHERE A.attribute_confidence > 0.55 +), +clust AS ( +SELECT id, + CAST(COLLECT(Cattr(aname, op, TO_CHAR(val), support, confidence)) + AS Cattrs) cl_attrs + FROM clus_tab +GROUP BY id +), +custclus AS ( +SELECT T.cust_id, S.cluster_id, S.probability + FROM (SELECT cust_id, CLUSTER_SET(km_sh_clus_sample, NULL, 0.2 USING *) pset + FROM mining_data_apply_v + WHERE cust_id = 101362) T, + TABLE(T.pset) S +) +SELECT A.probability prob, A.cluster_id cl_id, + B.attr, B.op, B.val, B.supp, B.conf + FROM custclus A, + (SELECT T.id, C.* + FROM clust T, + TABLE(T.cl_attrs) C) B + WHERE A.cluster_id = B.id +ORDER BY prob DESC, cl_id ASC, conf DESC, attr ASC, val ASC; diff --git a/dmnbdemo.java b/dmnbdemo.java new file mode 100644 index 0000000..3b6bc56 --- /dev/null +++ b/dmnbdemo.java @@ -0,0 +1,1009 @@ +// Copyright (c) 2004, 2007, Oracle. All rights reserved. +// File: dmnbdemo.java + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using the Naive Bayes(NB) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* How to predict whether a customer responds or not to the new affinity card +* program using a classifier based on NB algorithm? +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing any data mining. Here in this demo, the following views are created +* in the user schema using CUSTOMERS, COUNTRIES and SUPPLIMENTARY_DEMOGRAPHICS +* tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics and purchasing +* details for predicting response to the new affinity card program. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* For NB, binning transformation is used to reduce the carinality of +* higher cardinality attributes. The prepareData() method in this demo program +* illustrates the preparation of the build, test, and apply data. +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification model using the NB algorithm. +* Test Model: +* Classification model performance can be evaluated by computing test +* metrics like accuracy, confusion matrix, lift, and ROC. The testModel() or +* computeTestMetrics() method illustrates how to perform the test operation to +* compute various metrics. +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification models. The applyModel() method illustrates how to +* predict the customer response for an affinity card program. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic api imports +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.Statement; + +import java.text.DecimalFormat; +import java.text.MessageFormat; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.algorithm.naivebayes.NaiveBayesSettings; +import javax.datamining.algorithm.naivebayes.NaiveBayesSettingsFactory; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.CategoryProperty; +import javax.datamining.data.CategorySet; +import javax.datamining.data.CategorySetFactory; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.modeldetail.naivebayes.NaiveBayesModelDetail; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.classification.ClassificationApplyContent; +import javax.datamining.supervised.classification.ClassificationApplySettings; +import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.supervised.classification.ClassificationTestMetrics; +import javax.datamining.supervised.classification.ClassificationTestMetricsTaskFactory; +import javax.datamining.supervised.classification.ClassificationTestTask; +import javax.datamining.supervised.classification.ClassificationTestTaskFactory; +import javax.datamining.supervised.classification.ConfusionMatrix; +import javax.datamining.supervised.classification.CostMatrix; +import javax.datamining.supervised.classification.CostMatrixFactory; +import javax.datamining.supervised.classification.Lift; +import javax.datamining.supervised.classification.ReceiverOperatingCharacterics; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; + +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraModel; +import oracle.dmt.jdm.modeldetail.naivebayes.OraNaiveBayesModelDetail; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.supervised.OraTestTask; +import oracle.dmt.jdm.supervised.classification.OraClassificationApplySettings; +import oracle.dmt.jdm.supervised.classification.OraClassificationModel; +import oracle.dmt.jdm.supervised.classification.OraLift; +import oracle.dmt.jdm.task.OraBuildTask; +import oracle.dmt.jdm.transform.OraExpressionTransform; +import oracle.dmt.jdm.transform.OraTransformationFactory; +import oracle.dmt.jdm.transform.OraTransformationSequence; + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using the Naive Bayes(NB) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* How to predict whether a customer responds or not to the new affinity card +* program using a classifier based on NB algorithm? +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing any data mining. Here in this demo, the following views are created +* in the user schema using CUSTOMERS, COUNTRIES and SUPPLIMENTARY_DEMOGRAPHICS +* tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics and purchasing +* details for predicting response to the new affinity card program. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* For NB, binning transformation is used to reduce the carinality of +* higher cardinality attributes. The prepareData() method in this demo program +* illustrates the preparation of the build, test, and apply data. +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification model using the NB algorithm. +* Test Model: +* Classification model performance can be evaluated by computing test +* metrics like accuracy, confusion matrix, lift, and ROC. The testModel() or +* computeTestMetrics() method illustrates how to perform the test operation to +* compute various metrics. +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification models. The applyModel() method illustrates how to +* predict the customer response for an affinity card program. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Java Data Mining (JDM) standard imports +// Oracle Java Data Mining (JDM) implemented api imports + +public class dmnbdemo extends Object { + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClassificationSettingsFactory m_clasFactory; + private static NaiveBayesSettingsFactory m_nbFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClassificationTestTaskFactory m_testFactory; + private static ClassificationApplySettingsFactory m_applySettingsFactory; + private static CostMatrixFactory m_costMatrixFactory; + private static CategorySetFactory m_catSetFactory; + private static ClassificationTestMetricsTaskFactory m_testMetricsTaskFactory; + private static OraTransformationFactory m_xformFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmnbdemo "); + System.out.println(" or: java dmnbdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build model with supplied prior probability + buildModel(); + // 5. Test model - To compute accuracy and confusion matrix, lift result + // and ROC for the model from a test input data. + String costMatrixName = createCostMatrix(); + //Add cost matrix to the model + OraClassificationModel.addCostMatrix(m_dmeConn, "nbModel_jdm", costMatrixName); + // Test the model with cost matrix + boolean useCostMatrix = true; + testModel("nbTestMetricsWithCost_jdm", useCostMatrix); + // Test the model without cost matrix + useCostMatrix = false; + testModel("nbTestMetrics_jdm", useCostMatrix); + //Remove cost matrix from the model after testing is done + OraClassificationModel.removeCostMatrix(m_dmeConn, "nbModel_jdm"); + // 6. Apply model + applyModel(); + // 7. Rank Apply model with cost matrix + rankApplyModel(costMatrixName); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { } // Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_clasFactory = (ClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationSettings"); + m_nbFactory = (NaiveBayesSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.algorithm.naivebayes.NaiveBayesSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_testFactory = (ClassificationTestTaskFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationTestTask"); + m_applySettingsFactory = (ClassificationApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationApplySettings"); + m_costMatrixFactory = (CostMatrixFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.CostMatrix"); + m_catSetFactory = (CategorySetFactory)m_dmeConn.getFactory( + "javax.datamining.data.CategorySet" ); + m_testMetricsTaskFactory = (ClassificationTestMetricsTaskFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationTestMetricsTask"); + m_xformFactory = (OraTransformationFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.OraTransformation" ); + } + + /** + * This method illustrates how to build a mining model using + * NB_BINNED_DATA_BUILD_JDM dataset and classification settings with + * the NB algorithm. + * + * By default, the NB algorithm uses 0.01 value for both singleton threshold + * and pairwise threshold settings. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model - using prior probabilities ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("nbBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // Create NB algorithm settings + NaiveBayesSettings nbAlgo = m_nbFactory.create(); + // + // Thresholding probabilities + // To increase the accuracy of its estimates, ODM can optionally eliminate + // probabilities whose estimates are based on relatively small amounts of + // data. + // + // The Singleton fraction refers to the fraction of training data in which + // a predictor, e.g., X, takes on a specific value, e.g., x1. + // + // Pairwise fraction refers to the fraction of training data in which a + // predictor, X, takes on a specific value, x1, **when** the target, T, + // takes on a specific value t1. + // + // If the singleton fraction associated with a predictor value or the + // pairwise fraction associated with a (predictor value, target value) + // pair are below certain respective thresholds, they are ignored + // in the probability calculations. + // + // Examples settings are: + // nbAlgo.setSingletonThreshold(0.01f); + // nbAlgo.setPairwiseThreshold(0.0001f); + // + // Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(nbAlgo); + buildSettings.setTargetAttributeName("AFFINITY_CARD"); + ((OraBuildSettings)buildSettings).useAutomatedDataPreparations(true);//NEW 11g capability of Automated Data Preparation + // + // Set target prior probabilities. + // + // The priors represent the overall + // distribution of the target in the population. By default, the priors + // are computed from the sample (in this case, the build data). If the + // sample is known to be a distortion of the population target + // distribution (because, say, stratified sampling has been employed, or + // due to some other reason), then the user can override the default by + // providing prior probabilities as a setting for model creation. + // See Oracle Data Mining Concepts Guide for more details. + Map priorMap = new HashMap(); + priorMap.put(new Double(0), new Double(0.65)); + priorMap.put(new Double(1), new Double(0.35)); + buildSettings.setPriorProbabilitiesMap("AFFINITY_CARD", priorMap); + m_dmeConn.saveObject("nbBuildSettings_jdm", buildSettings, true); + //Turn Off ADP for CUST_GENDER attribute + //Create TransformationSequence + OraExpressionTransform exprXform = m_xformFactory.createExpressionTransform(); + //When attribute specification is set to NOPREP, ADP is truned off for that attribute. + //Here we are specifying for CUST_GENDER attribute "NOPREP" to flag ADP to be truned off + exprXform.addAttributeExpression("CUST_GENDER", null, null, "NOPREP"); + //Output view can be specified a null in this case, because we are + //not intended to create a view but embed the expression transformations + //with the model + OraTransformationSequence xformSeq = m_xformFactory.createTransformationSequence( + "MINING_DATA_BUILD_V", exprXform, null ); + m_dmeConn.saveObject("nbTSADPoff_jdm", xformSeq, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "nbBuildData_jdm", //Build data specification + "nbBuildSettings_jdm", //Mining function settings name + "nbModel_jdm" //Mining model name + ); + //Specify expression transformations that are defined to specify ADP off attributes + //as an embedded transformation to the model build + ((OraBuildTask)buildTask).setTransformationSequenceName("nbTSADPoff_jdm"); + buildTask.setDescription("nbBuildTask_jdm"); + executeTask(buildTask, "nbBuildTask_jdm"); + // 4. Restore the model from the DME and explore the details of the model + ClassificationModel model = + (ClassificationModel)m_dmeConn.retrieveObject( + "nbModel_jdm", NamedObject.model); + + OraExpressionTransform autoDataPrepSQLExprs = ((OraModel)model).getModelTransformations(); + Map exprMap = autoDataPrepSQLExprs.getAttributeExpressionMap(); + + // Display model build settings + ClassificationSettings retrievedBuildSettings = + (ClassificationSettings)model.getBuildSettings(); + if(buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "nbBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + // Display model details + displayNBModelDetails(model); + } + + /** + * Create and save cost matrix. + * + * Consider an example where it costs $10 to mail a promotion to a + * prospective customer and if the prospect becomes a customer, the + * typical sale including the promotion, is worth $100. Then the cost + * of missing a customer (i.e. missing a $100 sale) is 10x that of + * incorrectly indicating that a person is a good prospect (spending + * $10 for the promo). In this case, all prediction errors made by + * the model are NOT equal. To act on what the model determines to + * be the most likely (probable) outcome may be a poor choice. + * + * Suppose that the probability of a BUY reponse is 10% for a given + * prospect. Then the expected revenue from the prospect is: + * .10 * $100 - .90 * $10 = $1. + * + * The optimal action, given the cost matrix, is to simply mail the + * promotion to the customer, because the action is profitable ($1). + * + * In contrast, without the cost matrix, all that can be said is + * that the most likely response is NO BUY, so don't send the + * promotion. This shows that cost matrices can be very important. + * + * The caveat in all this is that the model predicted probabilities + * may NOT be accurate. For binary targets, a systematic approach to + * this issue exists. It is ROC, illustrated below. + * + * With ROC computed on a test set, the user can see how various model + * predicted probability thresholds affect the action of mailing a promotion. + * Suppose I promote when the probability to BUY exceeds 5, 10, 15%, etc. + * what return can I expect? Note that the answer to this question does + * not rely on the predicted probabilities being accurate, only that + * they are in approximately the correct rank order. + * + * Assuming that the predicted probabilities are accurate, provide the + * cost matrix table name as input to the RANK_APPLY procedure to get + * appropriate costed scoring results to determine the most appropriate + * action. + * + * In this demo, we will create the following cost matrix + * + * ActualTarget PredictedTarget Cost + * ------------ --------------- ---- + * 0 0 0 + * 0 1 0.35 + * 1 0 0.65 + * 1 1 0 + */ + private static String createCostMatrix() throws JDMException + { + String costMatrixName = "nbCostMatrix"; + // Create categorySet + CategorySet catSet = m_catSetFactory.create(AttributeDataType.integerType); + // Add category values + catSet.addCategory(new Integer(0), CategoryProperty.valid); + catSet.addCategory(new Integer(1), CategoryProperty.valid); + // Create cost matrix + CostMatrix costMatrix = m_costMatrixFactory.create(catSet); + // ActualTarget PredictedTarget Cost + // ------------ --------------- ---- + costMatrix.setValue(new Integer(0), new Integer(0), 0); + costMatrix.setValue(new Integer(0), new Integer(1), 0.35f); + costMatrix.setValue(new Integer(1), new Integer(0), 0.65f); + costMatrix.setValue(new Integer(1), new Integer(1), 0); + //save cost matrix + m_dmeConn.saveObject(costMatrixName, costMatrix, true); + return costMatrixName; + } + + /** + * This method illustrates how to test the mining model with + * NB_BINNED_DATA_TEST_JDM dataset using classification test task. After + * completion of the task, a classification test metrics object is created + * in the DMS. The classification test metrics object encapsulates + * different metrics like accuracy, confusion matrix, lift, and ROC. + * + * @param testResultName test result name + * @param useCostMatrix flag to indicate the enabling/disabling cost matrix added to the model + * @exception JDMException if model test failed + */ + public static void testModel(String testResultName, boolean useCostMatrix) + throws JDMException + { + if (useCostMatrix) { + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using test input table ---"); + System.out.println("--- - using cost matrix table ---"); + System.out.println("---------------------------------------------------"); + } + else { + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using test input table ---"); + System.out.println("--- - using no cost matrix table ---"); + System.out.println("---------------------------------------------------"); + } + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet testData = m_pdsFactory.create( + "MINING_DATA_TEST_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + testData.addAttribute( pa ); + m_dmeConn.saveObject( "nbTestData_jdm", testData, true ); + // 2. Create, store & execute Test Task + ClassificationTestTask testTask = m_testFactory.create( + "nbTestData_jdm", "nbModel_jdm", testResultName ); + testTask.setPositiveTargetValue(new Integer(1)); + testTask.setNumberOfLiftQuantiles(10); + //Set useCost flag to indicate enabling/disabling of cost matrix in testing the model + ((OraTestTask)testTask).useCost(useCostMatrix); + // Store & execute the task + boolean isTaskSuccess = executeTask(testTask, "nbTestTask_jdm"); + if( isTaskSuccess ) { + // Restore & display test metrics + ClassificationTestMetrics testMetrics = + (ClassificationTestMetrics)m_dmeConn.retrieveObject( + testResultName, + NamedObject.testMetrics ); + displayTestMetricDetails(testMetrics); + } + } + + /** + * This method illustrates how to apply the mining model on + * NB_BINNED_DATA_APPLY_JDM dataset to predict customer + * response. After completion of the task, an apply output table with the + * predicted results is created at the user specified location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_APPLY_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "nbApplyData_jdm", applyData, true ); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + // Example: Add source attributes + // HashMap sourceAttrMap = new HashMap(); + // sourceAttrMap.put( "AGE", "AGE" ); + // sourceAttrMap.put( "OCCUPATION", "OCCUPATION" ); + // clasAS.setSourceDestinationMap( sourceAttrMap ); + m_dmeConn.saveObject( "nbApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "nbApplyData_jdm", "nbModel_jdm", + "nbApplySettings_jdm", "NB_APPLY_OUTPUT_JDM"); + executeTask(applyTask, "nbApplyTask_jdm"); + // 4. Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + displayTable("NB_APPLY_OUTPUT_JDM", + "where ROWNUM < 11", + "order by CUST_ID"); + } + + /** + * This method illustrates how to apply the mining model (mapped by rank) on + * NB_BINNED_DATA_APPLY_JDM dataset to predict customer + * response. After completion of the task, an apply output table with the + * predicted results is created at the user specified location. + * + * @param costMatrixName table name of the supplied cost matrix + * @exception JDMException if model apply failed + */ + public static void rankApplyModel(String costMatrixName) throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Rank Apply Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification -- We will use apply result + // table from applyModel() to perform rank apply here. + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_APPLY_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "nbRankApplyData_jdm", applyData, true ); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + if(costMatrixName != null ) { + OraClassificationModel.addCostMatrix(m_dmeConn, "nbModel_jdm", costMatrixName); + ((OraClassificationApplySettings)clasAS).useCostMatrixFromModel(true); + } + int topNRanks = 2; + String[] topNCategoryColNames = new String[topNRanks]; + String[] topNProbabilityColNames = new String[topNRanks]; + String[] topNCostColNames = new String[topNRanks]; + for(int i=0; i 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + }//Ignore + } + + private static void clean() + { + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + //Drop apply output table + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE NB_APPLY_OUTPUT_JDM"); + } catch(Exception anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop rank apply output table + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE NB_RANK_APPLY_OUTPUT_JDM"); + } catch(Exception anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop the model + try { + m_dmeConn.removeObject("nbModel_jdm", NamedObject.model); + } catch(Exception jdmExp) {} + //Drop the test metrics + try { + m_dmeConn.removeObject("nbTestMetricsWithCost_jdm", NamedObject.testMetrics); + } catch(JDMException jdmExp) {} + try { + m_dmeConn.removeObject("nbTestMetrics_jdm", NamedObject.testMetrics); + } catch(JDMException jdmExp) {} + } + +} diff --git a/dmnbdemo.sql b/dmnbdemo.sql new file mode 100644 index 0000000..e42e483 --- /dev/null +++ b/dmnbdemo.sql @@ -0,0 +1,887 @@ +Rem +Rem $Header: dmnbdemo.sql 25-oct-2007.11:36:01 ramkrish Exp $ +Rem +Rem dmnbdemo.sql +Rem +Rem Copyright (c) 2003, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmnbdemo.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a classification model +Rem using the Naive Bayes algorithm +Rem and data in the SH (Sales History) schema in the RDBMS. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem ktaylor 07/11/05 - Minor edits to comments +Rem ramkrish 01/28/05 - prediction column format fixes +Rem jcjeon 01/18/05 - add column format +Rem jyarmus 11/05/04 - review and update cost code +Rem ramkrish 09/21/04 - add data analysis and comments/cleanup +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic data about a set of customers, predict the +-- customer response to an affinity card program using a classifier +-- based on the NB algorithm. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +-- See the corresponding section in dmabdemo.sql - Classification +-- using ABN. The analysis and preparation steps are very similar. + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old build data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_num'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nb_sh_sample_build_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nb_sh_sample_build_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +-- Cleanup old model with the same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('NB_SH_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- +-- 1. Missing Value treatment for all Predictors +-- Skipped - see dmsvcdem.sql +-- +-- 2. Outlier Treatment +-- Skipped - due to choice of quantile binning +-- +-- 3. Binning +-- +BEGIN + -- Bin categorical attributes: OCCUPATION + DBMS_DATA_MINING_TRANSFORM.CREATE_BIN_CAT ( + bin_table_name => 'nb_sh_sample_cat'); + DBMS_DATA_MINING_TRANSFORM.INSERT_BIN_CAT_FREQ ( + bin_table_name => 'nb_sh_sample_cat', + data_table_name => 'mining_data_build_v', + bin_num => 7, + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'cust_gender', + 'cust_marital_status', + 'cust_income_level', + 'education', + 'household_size') + ); + + -- Bin numerical attributes: AGE + DBMS_DATA_MINING_TRANSFORM.CREATE_BIN_NUM ( + bin_table_name => 'nb_sh_sample_num'); + DBMS_DATA_MINING_TRANSFORM.INSERT_BIN_NUM_QTILE ( + bin_table_name => 'nb_sh_sample_num', + data_table_name => 'mining_data_build_v', + bin_num => 7, + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'affinity_card', + 'bookkeeping_application', + 'bulk_pack_diskettes', + 'cust_id', + 'flat_panel_monitor', + 'home_theater_package', + 'os_doc_set_kanji', + 'printer_supplies', + 'y_box_games') + ); + + -- Create the transformed view + -- Execute the first transformation (categorical binning) + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_CAT ( + bin_table_name => 'nb_sh_sample_cat', + data_table_name => 'mining_data_build_v', + xform_view_name => 'nb_sh_sample_build_cat'); + + -- Provide the result (nb_sh_sample_build_cat) + -- to the next transformation (numerical binning) + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM ( + bin_table_name => 'nb_sh_sample_num', + data_table_name => 'nb_sh_sample_build_cat', + xform_view_name => 'nb_sh_sample_build_prepared'); +END; +/ + +-- BUILD DATA PREPARATION OBJECTS: +-- ------------------------------ +-- 1. Categorical Bin Table: nb_sh_sample_cat +-- 2. Numerical Bin Table: nb_sh_sample_num +-- 3. Input (view) to CREATE_MODEL: nb_sh_sample_build_prepared + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_priors'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Algorithm setting: +-- NB is the default classifier, thus there is no need to specify +-- the algorithm in settings table when the mining_function parameter +-- of the CREATE_MODEL operation specifies classification. + +-- CREATE AND POPULATE A PRIORS TABLE +-- The priors represent the overall distribution of the target in +-- the population. By default, the priors are computed from the sample +-- (in this case, the build data). If the sample is known to be a +-- distortion of the population target distribution (because, say, +-- stratified sampling has been employed, or due to some other reason), +-- then the user can override the default by providing a priors table +-- as a setting for model creation. See Oracle Data Mining Concepts Guide +-- for more details. +-- +CREATE TABLE nb_sh_sample_priors ( + target_value NUMBER, + prior_probability NUMBER); +INSERT INTO nb_sh_sample_priors VALUES (0,0.65); +INSERT INTO nb_sh_sample_priors VALUES (1,0.35); + +-- CREATE AND POPULATE A SETTINGS TABLE +-- +-- Thresholding probabilities +-- To increase the accuracy of its estimates, ODM can optionally eliminate +-- probabilities whose estimates are based on relatively small amounts of data. +-- +-- The Singleton fraction refers to the fraction of training data in which a +-- predictor, e.g., X, takes on a specific value, e.g., x1. +-- +-- Pairwise fraction refers to the fraction of training data in which a +-- predictor, X, takes on a specific value, x1, **when** the target, T, +-- takes on a specific value t1. +-- +-- If the singleton fraction associated with a predictor value or the +-- pairwise fraction associated with a (predictor value, target value) +-- pair are below certain respective thresholds, they are ignored +-- in the probability calculations. +-- +-- Examples settings are: +--(dbms_data_mining.nabs_pairwise_threshold,'0.0001') +--(dbms_data_mining.nabs_singleton_threshold,'0.01') +-- +set echo off +CREATE TABLE nb_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on +BEGIN + INSERT INTO nb_sh_sample_settings VALUES + (dbms_data_mining.clas_priors_table_name, 'nb_sh_sample_priors'); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Build a new NB model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'NB_SH_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 'nb_sh_sample_build_prepared', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + settings_table_name => 'nb_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'NB_SH_CLAS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'NB_SH_CLAS_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Binned data for meaningful model statistics: +-- The number of distinct values for each predictor should be limited +-- so that the probabilities estimated by the model have sufficient support +-- (i.e. number of rows) to be statistically meaningful. If the original +-- data has predictors with large numbers of values, then the data should +-- be binned into groups. This can be done either by using third-party tools +-- or the DBMS_DATA_MINING_TRANSFORM package. +-- +-- If the build data is prepared (as in this example), then the training +-- data has been encoded. For numeric data, this means that ranges of +-- values have been grouped into bins and the original value encoded by +-- the bin number. For categorical data, the k most frequent values are +-- retained and the rest are grouped into an OTHER category. +-- +-- Thus to display the model statistics in a meaningful way to the user, +-- the data must be decoded. The model statistics consist of: +-- . (unconditional) distribution of the target - the overall proportion +-- of each target value in the population (termed the prior), and +-- . the conditional probabilities of the various predictor values given +-- each specific target value. +-- +-- Using the Bayes formula and the conditional independence assumptions +-- made by Naive Bayes, the probability of each target value can be +-- computed from the prior and conditional probabilities. +-- +-- +-- The SQL query presented below does the following. +-- 1. Use the bin boundary tables to create labels +-- 2. Replace attribute values with labels +-- 3. For numeric bins, the labels are "[/(lower_boundary,upper_boundary]/)" +-- 4. For categorical bins, label matches the value it represents +-- Note that this method of categorical label representation +-- will only work for cases where one value corresponds to one bin +-- Target was not binned, hence we don't unbin the target. +-- +-- You can replace the model name in the query with your own, +-- and also adapt the query to accomodate other transforms. +-- +-- +column tname format a14 +column tval format a4 +column pname format a20 +column pval format a13 +column priorp format 9.9999 +column condp format 9.9999 +WITH +bin_label_view AS ( +SELECT col, bin, (DECODE(bin,'1','[','(') || lv || ',' || val || ']') label + FROM (SELECT col, + bin, + LAST_VALUE(val) OVER ( + PARTITION BY col ORDER BY val + ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) lv, + val + FROM nb_sh_sample_num) +UNION ALL +SELECT col, bin, val label + FROM nb_sh_sample_cat +), +model_details AS ( +SELECT T.target_attribute_name tname, + TO_CHAR( + NVL(T.target_attribute_num_value,T.target_attribute_str_value)) tval, + C.attribute_name pname, + NVL(L.label, NVL(C.attribute_str_value, C.attribute_num_value)) pval, + T.prior_probability priorp, + C.conditional_probability condp + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_NB('NB_SH_Clas_sample')) T, + TABLE(T.conditionals) C, + bin_label_view L + WHERE C.attribute_name = L.col (+) AND + (NVL(C.attribute_str_value,C.attribute_num_value) = L.bin(+)) +ORDER BY 1,2,3,4,5,6 +) +SELECT tname, tval, pname, pval, priorp, condp + FROM model_details + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old test data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nb_sh_sample_test_targets'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nb_sh_sample_test_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nb_sh_sample_test_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------- +-- PREPARE TEST DATA +-- +-- If the data for model creation has been prepared, then the data used +-- for testing the model must be prepared in the same manner in order to +-- obtain meaningful results. +-- +-- 1. Missing value treatment - see dmsvcdem.sql for example on what +-- needs to be done with Test and Apply data input. +-- +-- 2. Outlier treatment and +-- 3. Binning -- Quantile binning handles both the outlier treatment and +-- binning in this case. +-- +-- Transform the test data mining_test_v, using the transformation tables +-- generated during the Build data preparation, to generate a view representing +-- prepared test data. +-- +-- If this model is tested in a different schema or instance, the +-- data preparation objects generated in the CREATE step must also +-- be made available in the target schema/instance. So you must export +-- those objects (i.e. the num and cat bin tables and views) along with +-- the model to the target user schema. +-- +BEGIN + -- Execute the first transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_CAT ( + bin_table_name => 'nb_sh_sample_cat', + data_table_name => 'mining_data_test_v', + xform_view_name => 'nb_sh_sample_test_cat'); + + -- Provide the result to the next transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM ( + bin_table_name => 'nb_sh_sample_num', + data_table_name => 'nb_sh_sample_test_cat', + xform_view_name => 'nb_sh_sample_test_prepared'); +END; +/ + +-- Cleanup old test result objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_test_apply'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_confusion_matrix'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_cm_no_cost'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_lift'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_roc'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_alter_cost'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_alter_confusion_matrix'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- +-- The COMPUTE interfaces that provide the test results require two +-- data inputs: +-- 1. A table or view of targets - i.e. one that provides only the +-- case identifier and target columns of your test data. +-- 2. The table with the results of an APPLY operation on test data. +-- + +-- CREATE TEST TARGETS VIEW +-- +CREATE VIEW nb_sh_sample_test_targets AS +SELECT cust_id, affinity_card + FROM nb_sh_sample_test_prepared; + +-- APPLY MODEL ON TEST DATA +-- +BEGIN + DBMS_DATA_MINING.APPLY( + model_name => 'NB_SH_Clas_sample', + data_table_name => 'nb_sh_sample_test_prepared', + case_id_column_name => 'cust_id', + result_table_name => 'nb_sh_sample_test_apply'); +END; +/ + +---------------------------------- +-- COMPUTE TEST METRICS, WITH COST +-- +---------------------- +-- Specify cost matrix +-- +-- Consider an example where it costs $10 to mail a promotion to a +-- prospective customer and if the prospect becomes a customer, the +-- typical sale including the promotion, is worth $100. Then the cost +-- of missing a customer (i.e. missing a $100 sale) is 10x that of +-- incorrectly indicating that a person is good prospect (spending +-- $10 for the promo). In this case, all prediction errors made by +-- the model are NOT equal. To act on what the model determines to +-- be the most likely (probable) outcome may be a poor choice. +-- +-- Suppose that the probability of a BUY reponse is 10% for a given +-- prospect. Then the expected revenue from the prospect is: +-- .10 * $100 - .90 * $10 = $1. +-- The optimal action, given the cost matrix, is to simply mail the +-- promotion to the customer, because the action is profitable ($1). +-- +-- In contrast, without the cost matrix, all that can be said is +-- that the most likely response is NO BUY, so don't send the +-- promotion. +-- +-- This shows that cost matrices can be very important. +-- +-- The caveat in all this is that the model predicted probabilities +-- may NOT be accurate. For binary targets, a systematic approach to +-- this issue exists. It is ROC, illustrated below. +-- +-- With ROC computed on a test set, the user can see how various model +-- predicted probability thresholds affect the action of mailing a promotion. +-- Suppose I promote when the probability to BUY exceeds 5, 10, 15%, etc. +-- What return can I expect? Note that the answer to this question does +-- not rely on the predicted probabilities being accurate, only that +-- they are in approximately the correct rank order. +-- +-- Assuming that the predicted probabilities are accurate, provide the +-- cost matrix table name as input to the RANK_APPLY procedure to get +-- appropriate costed scoring results to determine the most appropriate +-- action. + +-- Cleanup old cost matrix table for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_cost'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- CREATE A COST MATRIX TABLE +-- +CREATE TABLE nb_sh_cost ( + actual_target_value NUMBER, + predicted_target_value NUMBER, + cost NUMBER); + +-- POPULATE THE COST MATRIX +-- +INSERT INTO nb_sh_cost VALUES (0,0,0); +INSERT INTO nb_sh_cost VALUES (0,1,.35); +INSERT INTO nb_sh_cost VALUES (1,0,.65); +INSERT INTO nb_sh_cost VALUES (1,1,0); + +-- Compute Test Metrics +DECLARE + v_accuracy NUMBER; + v_area_under_curve NUMBER; +BEGIN + DBMS_DATA_MINING.COMPUTE_CONFUSION_MATRIX ( + accuracy => v_accuracy, + apply_result_table_name => 'nb_sh_sample_test_apply', + target_table_name => 'nb_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + confusion_matrix_table_name => 'nb_sh_sample_confusion_matrix', + score_column_name => 'PREDICTION', -- default + score_criterion_column_name => 'PROBABILITY', -- default + cost_matrix_table_name => 'nb_sh_cost'); + DBMS_OUTPUT.PUT_LINE('**** MODEL ACCURACY ****: ' || ROUND(v_accuracy,4)); + + DBMS_DATA_MINING.COMPUTE_LIFT ( + apply_result_table_name => 'nb_sh_sample_test_apply', + target_table_name => 'nb_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + lift_table_name => 'nb_sh_sample_lift', + positive_target_value => '1', + num_quantiles => '10', + cost_matrix_table_name => 'nb_sh_cost'); + + DBMS_DATA_MINING.COMPUTE_ROC ( + roc_area_under_curve => v_area_under_curve, + apply_result_table_name => 'nb_sh_sample_test_apply', + target_table_name => 'nb_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + roc_table_name => 'nb_sh_sample_roc', + positive_target_value => '1', + score_column_name => 'PREDICTION', + score_criterion_column_name => 'PROBABILITY'); + DBMS_OUTPUT.PUT_LINE('**** AREA UNDER ROC CURVE ****: ' || + ROUND(v_area_under_curve,4)); +END; +/ + +-- TEST RESULT OBJECTS: +-- ------------------- +-- 1. Confusion matrix Table: nb_sh_sample_confusion_matrix +-- 2. Lift Table: nb_sh_sample_lift +-- 3. ROC Table: nb_sh_sample_roc +-- + +-- DISPLAY CONFUSION MATRIX +-- +-- NOTES ON COST (contd): +-- This section illustrates the effect of the cost matrix on the per-class +-- errors in the confusion matrix. First, compute the Confusion Matrix with +-- costs. Our cost matrix assumes that ratio of the cost of an error in +-- class 1 to class 0 is 65:35 (say, where 1 => BUY and 0 => NO BUY). + +column predicted format 9; +SELECT actual_target_value as actual, + predicted_target_value as predicted, + value as count + FROM nb_sh_sample_confusion_matrix +ORDER BY actual_target_value, predicted_target_value; + +-- Compute the confusion matrix without costs for later analysis +DECLARE + v_accuracy NUMBER; + v_area_under_curve NUMBER; +BEGIN + DBMS_DATA_MINING.COMPUTE_CONFUSION_MATRIX ( + accuracy => v_accuracy, + apply_result_table_name => 'nb_sh_sample_test_apply', + target_table_name => 'nb_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + confusion_matrix_table_name => 'nb_sh_sample_cm_no_cost', + score_column_name => 'PREDICTION', + score_criterion_column_name => 'PROBABILITY'); + DBMS_OUTPUT.PUT_LINE('** ACCURACY W/ NO COST **: ' || ROUND(v_accuracy,4)); +END; +/ + +-- The Cost matrix is: +-- 0 0.35 +-- 0.65 0 +-- +-- Confusion matrix with Cost: +-- 868 286 +-- 56 290 +-- 868 correct predictions, and 290 misclassifications +-- Overall Cost (286 x 0.35 + 56 x 0.65 = 136.5) +-- Per class accuracy 0: 0.752166378 +-- 1: 0.838150289 +-- Accuracy: 0.772 +-- Overall Cost can be computed using this query: +-- +SELECT (SELECT (C.cost * M.value) + FROM nb_sh_sample_confusion_matrix M, + nb_sh_cost C + WHERE C.actual_target_value = '0' AND C.predicted_target_value = '1' + AND M.actual_target_value = '0' AND M.predicted_target_value = '1') + + + (SELECT (C.cost * M.value) c2 + FROM nb_sh_sample_confusion_matrix M, + nb_sh_cost C + WHERE C.actual_target_value = '1' AND C.predicted_target_value = '0' + AND M.actual_target_value = '1' AND M.predicted_target_value = '0') + cost +FROM DUAL; + +-- Confusion matrix without Cost: +-- +column predicted format 9; +SELECT actual_target_value as actual, + predicted_target_value as predicted, + value as count + FROM nb_sh_sample_cm_no_cost +ORDER BY actual_target_value, predicted_target_value; + +-- Confusion matrix with Cost: +-- 901 253 +-- 65 281 +-- 901 correct predictions, and 281 misclassifications +-- Overall Cost (253 x 0.35 + 65 x 0.65) = 130.8 +-- Per class accuracy 0: 0.780762565 +-- 1: 0.812138728 +-- Accuracy: 0.78 +-- +-- Several points are illustrated here: +-- 1. The cost matrix causes an increase in the class 1 accuracy +-- (0.83 vs 0.81) at the expense of the class 0 accuracy (0.75 vs 0.78). +-- 2. The overall accuracy is down (0.772 vs 0.78) +-- 3. The predicted probabilities are NOT accurate enough to minimize cost. +-- Note that the cost is lower for no cost matrix model (136.5 vs 130)! +-- +-- Hence, the decision model is likely to benefit from an ROC analysis. + +-- DISPLAY ROC - TOP 10 PROBABILITIES +-- +column prob format .9999 +column tp format 9999 +column fn format 9999 +column fp format 9999 +column tn format 9999 +column tpf format 9.9999 +column fpf format 9.9999 +column nb_cost format 9999.99 +SELECT * + FROM (SELECT * + FROM (SELECT ROUND(probability,4) prob, + true_positives tp, + false_negatives fn, + false_positives fp, + true_negatives tn, + ROUND(true_positive_fraction,4) tpf, + ROUND(false_positive_fraction,4) fpf, + .35 * false_positives + .65 * false_negatives nb_cost + FROM nb_sh_sample_roc) + ORDER BY nb_cost) + WHERE ROWNUM < 11; + +-- Here we see 10 different probability thresholds resulting in +-- confusion matrices with a lower overall cost (< 130) than a +-- straight-forward apply with or without a cost matrix. +-- +-- Now, let us create a cost matrix from the optimal threshold, i.e., +-- one whose action is to most closely mimic the user cost matrix. +-- Let Poptimal = Probability corresponding to the minimum cost +-- computed from the ROC table above +-- +-- Find the ratio of costs that causes breakeven expected cost at +-- at the optimal probability threshold: +-- +-- Cost(misclassify 1) = (1 - Poptimal)/Poptimal +-- Cost(misclassify 0) = 1.0 +-- +-- The following query constructs the alternative cost matrix +-- based on the above rationale. +-- +CREATE TABLE nb_alter_cost AS +WITH +cost_q AS ( +SELECT probability, + (.35 * false_positives + .65 * false_negatives) nb_cost + FROM nb_sh_sample_roc +), +min_cost AS ( +SELECT MIN(nb_cost) mincost + FROM cost_q +), +prob_q AS ( +SELECT min(probability) prob + FROM cost_q, min_cost + WHERE nb_cost = mincost +) +SELECT 1 actual_target_value, + 0 predicted_target_value, + (1.0 - prob)/prob cost + FROM prob_q +UNION ALL +SELECT 0 actual_target_value, + 1 predicted_target_value, + 1 cost + FROM dual +UNION ALL +SELECT 0 actual_target_value, + 0 predicted_target_value, + 0 cost + FROM dual +UNION ALL +SELECT 1 actual_target_value, + 1 predicted_target_value, + 0 cost + FROM dual; + +SELECT * + FROM nb_alter_cost; + +-- Now, use this new cost matrix to compute the confusion matrix +-- +DECLARE + v_accuracy NUMBER; + v_area_under_curve NUMBER; +BEGIN + DBMS_DATA_MINING.COMPUTE_CONFUSION_MATRIX ( + accuracy => v_accuracy, + apply_result_table_name => 'nb_sh_sample_test_apply', + target_table_name => 'nb_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + confusion_matrix_table_name => 'nb_sh_alter_confusion_matrix', + score_column_name => 'PREDICTION', -- default + score_criterion_column_name => 'PROBABILITY', -- default + cost_matrix_table_name => 'nb_alter_cost'); + DBMS_OUTPUT.PUT_LINE('**** MODEL ACCURACY ****: ' || ROUND(v_accuracy,4)); +END; +/ + +SELECT actual_target_value as actual, + predicted_target_value as predicted, + value as count + FROM nb_sh_alter_confusion_matrix + ORDER BY actual_target_value, predicted_target_value; + +-- DISPLAY LIFT RESULTS +-- +-- See dmabdemo.sql for example on generating a .CSV file +-- for charting using Excel +-- +SELECT quantile_number qtl, + lift_cumulative lcume, + percentage_records_cumulative prcume, + targets_cumulative tcume, + target_density_cumulative tdcume +-- Other info in Lift results +-- quantile_total_count, +-- non_targets_cumulative, +-- lift_quantile, +-- target_density + FROM nb_sh_sample_lift +ORDER BY quantile_number; + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old scoring data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nb_sh_sample_apply_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nb_sh_sample_apply_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +----------------------- +-- PREPARE SCORING DATA +-- +-- If the data for model creation has been prepared, then the data +-- to be scored using the model must be prepared to the same scale +-- in order to obtain meaningful results. +-- +-- 1. Missing value treatment - see dmsvcdem.sql for example of what +-- needs to be done with Test and Apply data input. +-- 2. Outlier treatment and +-- 3. Binning +-- Quantile binning handles both the outlier treatment and binning in +-- this case. Transform the test data mining_test_v, using the transformation +-- tables generated during the Build data preparation, to generate a view +-- representing prepared test data. +-- +-- If this model is applied in a different schema or instance, the +-- data preparation objects generated in the CREATE step must also +-- be made available in the target schema/instance. So you must export +-- those objects (i.e. the num and cat bin tables and views) along with +-- the model to the target user schema. +-- +BEGIN + -- Execute the first transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_CAT ( + bin_table_name => 'nb_sh_sample_cat', + data_table_name => 'mining_data_apply_v', + xform_view_name => 'nb_sh_sample_apply_cat'); + + -- Provide the result to the next transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM ( + bin_table_name => 'nb_sh_sample_num', + data_table_name => 'nb_sh_sample_apply_cat', + xform_view_name => 'nb_sh_sample_apply_prepared'); +END; +/ + +-- Cleanup old scoring result objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_apply_result'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_apply_ranked'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------ +-- APPLY THE MODEL +-- +BEGIN + DBMS_DATA_MINING.APPLY( + model_name => 'NB_SH_Clas_sample', + data_table_name => 'nb_sh_sample_apply_prepared', + case_id_column_name => 'cust_id', + result_table_name => 'nb_sh_sample_apply_result'); +END; +/ + +-- APPLY RESULT OBJECTS: nb_sh_sample_apply_result + +------------------------ +-- DISPLAY APPLY RESULTS +-- +-- 1. The results table contains a prediction set - i.e. ALL the predictions +-- for a given case id, with their corresponding probability values. +-- 2. In this example, note that APPLY results do not need to be reverse +-- transformed, as done in the case of model details. This is because +-- class values of a classification target were not (required to be) +-- binned or normalized. +-- 3. Only the first 10 rows of the table are displayed here. +-- +column probability format 9.99999 +column prediction format 9 +SELECT cust_id, prediction, probability + FROM (SELECT cust_id, prediction, ROUND(probability,4) probability + FROM nb_sh_sample_apply_result + ORDER BY cust_id, prediction, probability) + WHERE ROWNUM < 11 +ORDER BY cust_id; + +----------------------------------------------------------- +-- GENERATE RANKED APPLY RESULTS (OPTIONALLY BASED ON COST) +-- +-- ALTER APPLY RESULTS TABLE (just for demo purposes) +-- +-- The RANK_APPLY and COMPUTE() procedures do not necessarily have +-- to work on the result table generated from DBMS_DATA_MINING.APPLY +-- alone. They can work on any table with similar schema and content +-- that matches the APPLY result table. An example will be a table +-- generated from some other tool, scoring engine or a generated result. +-- +-- To demonstrate this, we will make a simply change the column names in +-- the APPLY results schema table, and supply the new table as input to +-- RANK_APPLY. The only requirement is that the new column names have to be +-- reflected in the RANK_APPLY procedure. The table containing the ranked +-- results will reflect these new column names. +-- +ALTER TABLE nb_sh_sample_apply_result RENAME COLUMN cust_id TO customer_id; +ALTER TABLE nb_sh_sample_apply_result RENAME COLUMN prediction TO score; +ALTER TABLE nb_sh_sample_apply_result RENAME COLUMN probability TO chance; + +-- RANK APPLY RESULTS (WITH COST MATRIX INPUT) +-- +BEGIN + DBMS_DATA_MINING.RANK_APPLY ( + apply_result_table_name => 'nb_sh_sample_apply_result', + case_id_column_name => 'customer_id', + score_column_name => 'score', + score_criterion_column_name => 'chance', + ranked_apply_table_name => 'nb_sh_sample_apply_ranked', + top_n => 2, + cost_matrix_table_name => 'nb_alter_cost'); +END; +/ + +-- RANK_APPLY RESULT OBJECTS: smvc_sh_sample_apply_ranked + +------------------------------- +-- DISPLAY RANKED APPLY RESULTS +-- using altered cost matrix +column chance format 9.99 +column cost format 9.99 +SELECT customer_id, score, chance, cost, rank + FROM (SELECT customer_id, score, ROUND(chance,4) chance, + ROUND(cost,4) cost, rank + FROM nb_sh_sample_apply_ranked + ORDER BY customer_id, rank) + WHERE ROWNUM < 11 +ORDER BY customer_id; diff --git a/dmnmdemo.java b/dmnmdemo.java new file mode 100644 index 0000000..71f5fd0 --- /dev/null +++ b/dmnmdemo.java @@ -0,0 +1,618 @@ +// Copyright (c) 2001, 2006, Oracle. All rights reserved. +// File: dmnmdemo.java + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to build and apply a feature extraction model using the Non-negative Matrix +* Factorization (NMF) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Given demographic data about a set of customers, extract features +* from the given dataset. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created +* in the user schema using CUSTOMERS, COUNTRIES and SUPPLIMENTARY_DEMOGRAPHICS +* tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics and purchasing +* details for scoring against the clustering model. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a feature extraction model using the NMF algorithm. +* Apply Model: +* For a descriptive mining function like feature extraction, "Scoring" +* involves providing the probability values for each feature. +* During model apply, an NMF model maps the original data into the +* new set of attributes (features) discovered by the model. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic api imports +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.DecimalFormat; +import java.text.MessageFormat; +import java.util.Collection; +import java.util.Iterator; +// Java Data Mining (JDM) standard imports +import java.util.Map; +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.resource.Connection; +import javax.datamining.resource.ConnectionFactory; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.algorithm.nmf.OraNMFAlgorithmSettingsFactory; +import oracle.dmt.jdm.algorithm.nmf.OraNMFAlgorithmSettings; +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.featureextraction.OraFeature; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionApplySettings; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionApplySettingsFactory; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionModel; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionSettings; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionSettingsFactory; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformImpl; + +public class dmnmdemo extends Object{ + //Connection related data members + private static Connection m_dmeConn; + private static ConnectionFactory m_dmeConnFactory; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static OraFeatureExtractionSettingsFactory m_feSettingFactory; + private static OraNMFAlgorithmSettingsFactory m_feAlgFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static OraFeatureExtractionApplySettingsFactory m_applySettingsFactory; + // Global constants used for formatting output + private static String UNDERLINE = "*************************************"; + private static String TAB = " "; + private static char SPACE = ' '; + private static int SECOND_COLUMN = 40; + private static int THIRD_COLUMN = 70; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmnmdemo "); + System.out.println(" or: java dmnmdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + //1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build a model + buildModel(); + // 5. Apply the model + applyModel(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 7. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { }//Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_feSettingFactory = (OraFeatureExtractionSettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.featureextraction.OraFeatureExtractionSettings"); + m_feAlgFactory = (OraNMFAlgorithmSettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.algorithm.nmf.OraNMFAlgorithmSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = (OraFeatureExtractionApplySettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.featureextraction.OraFeatureExtractionApplySettings"); + } + + /** + * This method illustrates how to build a mining model using the + * "MINING_DATA_BUILD_V" dataset with the nmf algorithm. + * + * After completing the build task, a model named "nmModel_jdm" will + * be created. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("nmfBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // Create NMF algorithm settings + OraNMFAlgorithmSettings nmfAlgo = (OraNMFAlgorithmSettings)m_feAlgFactory.create(); + // Examples settings are: + // nmfAlgo.setMaxNumberOfIterations(10); + // nmfAlgo.setMinConvergenceTolerance(0.05); + // nmfAlgo.setSeedValue(-1); + // Create OraFeatureExtractionSettings + OraFeatureExtractionSettings buildSettings = m_feSettingFactory.create(); + buildSettings.setAlgorithmSettings(nmfAlgo); + //Set auto data preparation on + buildSettings.useAutomatedDataPreparations(true); + + m_dmeConn.saveObject("nmfBuildSettings_jdm", buildSettings, true); + //3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "nmfBuildData_jdm", //Build data specification + "nmfBuildSettings_jdm", //Mining function settings name + "nmfModel_jdm" //Mining model name + ); + buildTask.setDescription("nmfBuildTask_jdm"); + executeTask(buildTask, "nmfBuildTask_jdm"); + //4. Restore the model from the DME and explore the details of the model + OraFeatureExtractionModel model = (OraFeatureExtractionModel) + m_dmeConn.retrieveObject("nmfModel_jdm", NamedObject.model); + // Display model build settings + OraFeatureExtractionSettings retrievedBuildSettings = + (OraFeatureExtractionSettings)model.getBuildSettings(); + if(buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "nmfBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + // Display model details + displayFEModelDetails(model); + } + + /** + * Apply operation is performed by a task that requires the location of + * the dataset, the model name, the output specification, and the location + * of the output. + * + * The output table "nmf_apply_output_jdm" is specified by a MiningApplyOutput + * object to contain the feature identifier and the match quality for feature + * extraction models. + * + * In this example, the NMF model is applied with the + * "NMF_LIN_NORM_DATA_APPLY_JDM" prepared dataset to obtain the feature + * identifier and the match quality. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_APPLY_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "nmfNMFData_jdm", applyData, true ); + // 2. Create & save FeatureExtractionApplySettings + OraFeatureExtractionApplySettings feAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "nmfApplySettings_jdm", feAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "nmfNMFData_jdm", "nmfModel_jdm", "nmfApplySettings_jdm", + "NMF_APPLY_OUTPUT_JDM"); + executeTask(applyTask, "nmfApplyTask_jdm"); + // 4. Display apply result -- the first 10 rows + displayTable("NMF_APPLY_OUTPUT_JDM", + "where ROWNUM < 11", + "order by CUST_ID"); + } + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints the error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static boolean executeTask(Task taskObj, String taskName) throws JDMException + { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful."); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() ); + } + return isTaskSuccess; + } + + private static void displayBuildSettings( + OraFeatureExtractionSettings featureSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " model build settings object:"); + String objName = featureSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = featureSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = featureSettings.getCreationDate(); + String creator = featureSettings.getCreatorInfo(); + AlgorithmSettings algoSettings = featureSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: featureSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = featureSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: featureSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + // List of NMF algorithm settings + long intValue = ((OraNMFAlgorithmSettings)algoSettings).getMaxNumberOfIterations(); + System.out.println("Max Number Of Iterations: " + intValue); + double doubleValue = ((OraNMFAlgorithmSettings)algoSettings).getMinConvergenceTolerance(); + System.out.println("Min Convergence Tolerance: " + m_df.format(doubleValue)); + intValue = ((OraNMFAlgorithmSettings)algoSettings).getSeedValue(); + System.out.println("Seed Value: " + intValue); + intValue = featureSettings.getNumberOfFeatures(); + System.out.println("Number Of Features: " + intValue); + } + + /** + * This method displayes the NMF model signature. + * + * @param model model object + * @exception JDMException + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + // Display the first 10 rows only + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while(rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + /** + * Each feature is a linear combination of the original attribute set; + * the coefficients of these linear combinations are non-negative. + * The model details return for each feature the coefficients + * associated with each one of the original attributes. Categorical + * attributes are described by (attribute_name, attribute_value) pairs. + * That is, for a given feature, each distinct value of a categorical + * attribute has its own coefficient. + * + * @param model model to be presented + * @exception JDMException if failed to retrieve model details + */ + public static void displayFEModelDetails(OraFeatureExtractionModel model) + throws JDMException + { + System.out.println(UNDERLINE+"\n"+"NMF model details"+"\n"+UNDERLINE+"\n"); + System.out.println("\n"+TAB+"Listing all features:\n"+UNDERLINE); + Collection features = model.getFeatures(); + if ( features == null ){ + System.out.println(TAB+TAB+"Error printing features."); + return; + } + + OraFeature sampleFeature = null; + Iterator it = features.iterator(); + while ( it.hasNext() ){ + OraFeature feature = (OraFeature)it.next(); + printFeature(feature); + if ( sampleFeature == null ) + sampleFeature = feature; + } + + System.out.println("\n"+TAB+"Listing Top 3 features:\n"+UNDERLINE); + Collection topNfeatures = model.getFeatures(3); + if ( topNfeatures == null ){ + System.out.println(TAB+TAB+"Error printing Top N features."); + return; + } + + Iterator itTopN = topNfeatures.iterator(); + while ( itTopN.hasNext() ){ + OraFeature feature = (OraFeature)itTopN.next(); + printFeature(feature); + } + + if ( sampleFeature != null ){ + System.out.println(TAB+"Listing all attribute names for the feature:" + sampleFeature.getFeatureIdentifier()); + System.out.println(TAB+"____________________________________________"); + String[] attrNames = sampleFeature.getAttributeNames(); + for ( int ni = 0 ; ni < attrNames.length ; ni++ ) { + Map attrValCoefficientMap = sampleFeature.getAttributeCoefficients(attrNames[ni]); + System.out.println("\n"+TAB+TAB+"Attribute Name:" + attrNames[ni] ); + printCoefficients(attrNames[ni], attrValCoefficientMap, false); + } + } + } + + /** + * Display a single feature + * + * @param feature specific feature to be displayed + * @exception JDMException if failed to retrieve the feature details + */ + public static void printFeature(OraFeature feature) throws JDMException + { + if ( feature == null ){ + System.out.println("Error: feature is null"); + return; + } + + System.out.println("\n" + TAB+TAB+"Feature : " + feature.getFeatureIdentifier() ); + String[] featureAttrNames = feature.getAttributeNames(); + //Print attributes coefficient details for each attribute + if(featureAttrNames != null) { + for(int iAttr=0; iAttr < featureAttrNames.length; iAttr++) + { + Map attrValCoefficientMap = feature.getAttributeCoefficients(featureAttrNames[iAttr]); + printCoefficients(featureAttrNames[iAttr], attrValCoefficientMap, true); + } + } + + } + + private static void printCoefficients (String attrName, Map attrValCoefficientMap, boolean printAttrName) + throws JDMException + { + if ( attrValCoefficientMap == null ){ + System.out.println("Error printing coefficients for this feature."); + return; + } + + if ( printAttrName == true ) + print3Columns(new String[]{"Attribute","Value","Coefficient"} ); + else + print3Columns(new String[]{"","Value","Coefficient"} ); + + System.out.println(TAB+TAB+TAB +"____________________________________________________________________________" ); + Object[] attrVals = attrValCoefficientMap.keySet().toArray(); + if(attrVals != null) { + for(int iAttr=0; iAttr < attrVals.length; iAttr++) + { + print3Columns ( new String[]{ + ( printAttrName == true ? attrName : "" ) , + (( attrVals[iAttr] == null ? "" : attrVals[iAttr] )).toString(), + String.valueOf(m_df.format((Number)attrValCoefficientMap.get(attrVals[iAttr]))) + } + ); + } + } + + } + + + private static void print3Columns(String[] names){ + if ( names == null || names.length != 3 ) + return; + + StringBuffer sbOut = new StringBuffer(TAB+TAB+TAB); + sbOut.append(names[0]); + + int padLength = Math.max ( SECOND_COLUMN - sbOut.length(), 0 ); + for ( int ni = 0 ; ni < padLength; ni++) + sbOut.append(SPACE); + + sbOut.append(names[1]); + padLength = Math.max ( THIRD_COLUMN - sbOut.length(), 0 ); + for ( int ni = 0 ; ni < padLength; ni++) + sbOut.append(SPACE); + + sbOut.append(names[2]); + System.out.println(sbOut.toString()); + } + + private static void clean() + { + try { + m_dmeConn.removeObject("nmfModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + //Drop apply output table + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW NMF_LIN_NORM_DATA_BUILD_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW NMF_LIN_NORM_DATA_APPLY_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE NMF_APPLY_OUTPUT_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + } +} \ No newline at end of file diff --git a/dmnmdemo.sql b/dmnmdemo.sql new file mode 100644 index 0000000..f26b511 --- /dev/null +++ b/dmnmdemo.sql @@ -0,0 +1,329 @@ +Rem +Rem $Header: dmnmdemo.sql 17-jan-2008.13:35:55 jiawang Exp $ +Rem +Rem dmnmdemo.sql +Rem +Rem Copyright (c) 2003, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmnmdemo.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a feature extraction model +Rem using the NMF algorithm +Rem and data in the SH (Sales History) schema in the RDBMS. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem jiawang 01/17/08 - Correct comments +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem jiawang 03/06/07 - Add order by to fix bug5381396 +Rem xbarr 02/22/07 - add force drop for type objects +Rem amozes 05/09/06 - repeatable ordering +Rem ktaylor 07/11/05 - Minor edits to comments +Rem ramkrish 02/01/05 - remove rownum clause in model signature +Rem jcjeon 01/18/05 - add column format +Rem ramkrish 10/27/04 - add data analysis and comments/cleanup +Rem jiawang 07/22/04 - Add order by to fix sorting dif +Rem xbarr 06/25/04 - xbarr_dm_rdbms_migration +Rem ramkrish 10/20/03 - ramkrish_txn109085 +Rem pstengar 10/17/03 - added denormalization of model details +Rem cbhagwat 10/17/03 - feature_extraction +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET linesize 100 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic data about a set of customers, extract features +-- from the given dataset. +-- + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +-- See the corresponding section in dmsvcdem.sql +-- + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old build data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nmf_sh_sample_norm'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nmf_sh_sample_build_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +-- Cleanup old model with same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('NMF_SH_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- +-- This step is required only if the data is not prepared/transformed +-- to enable creation of an efficient model using the NMF algorithm. +-- In this case, the data for attribute 'age' requires preparation. +-- +BEGIN + -- Normalize numerical attributes: age + DBMS_DATA_MINING_TRANSFORM.CREATE_NORM_LIN( + norm_table_name => 'nmf_sh_sample_norm'); + + DBMS_DATA_MINING_TRANSFORM.INSERT_NORM_LIN_MINMAX ( + norm_table_name => 'nmf_sh_sample_norm', + data_table_name => 'mining_data_build_v', + exclude_list => dbms_data_mining_transform.column_list ( + 'yrs_residence', + 'affinity_card', + 'bulk_pack_diskettes', + 'flat_panel_monitor', + 'home_theater_package', + 'bookkeeping_application', + 'printer_supplies', + 'y_box_games', + 'os_doc_set_kanji', + 'cust_id') + ); + + -- Create the transformed view + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 'nmf_sh_sample_norm', + data_table_name => 'mining_data_build_v', + xform_view_name => 'nmf_sh_sample_build_prepared'); +END; +/ + +-- BUILD DATA PREPARATION OBJECTS: +-- ------------------------------ +-- 1. Missing Value Treatment for all predictors +-- skipped. See dmsvcdem.sql for an example. +-- 2. Normalization Table: nmf_sh_sample_norm +-- 3. Input (view) to CREATE_MODEL: nmf_sh_sample_build_prepared + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nmf_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- CREATE A SETTINGS TABLE +-- +-- NMF is the default Feature Extraction algorithm. For this sample, +-- we skip specification of any overrides to defaults +-- +-- Uncomment the appropriate sections of the code below if you +-- want to override any defaults. +-- +set echo off +-- CREATE TABLE nmf_sh_sample_settings ( +-- setting_name VARCHAR2(30), +-- setting_value VARCHAR2(30)); +set echo on + +-- BEGIN + -- Populate settings table + -- INSERT INTO nmf_sh_sample_settings (setting_name, setting_value) VALUES + -- Examples of possible overrides are: + -- (dbms_data_mining.feat_num_features, 10); + -- (dbms_data_mining.nmfs_conv_tolerance,0.05); + -- (dbms_data_mining.nmfs_num_iterations,50); + -- (dbms_data_mining.nmfs_random_seed,-1); +-- END; +-- / + +--------------------- +-- CREATE A NEW MODEL +-- +-- Build NMF model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'NMF_SH_sample', + mining_function => dbms_data_mining.feature_extraction, + data_table_name => 'nmf_sh_sample_build_prepared', + case_id_column_name => 'cust_id'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'NMF_SH_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'NMF_SH_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Each feature is a linear combination of the original attribute set; +-- the coefficients of these linear combinations are non-negative. +-- The model details return for each feature the coefficients +-- associated with each one of the original attributes. Categorical +-- attributes are described by (attribute_name, attribute_value) pairs. +-- That is, for a given feature, each distinct value of a categorical +-- attribute has its own coefficient. +-- +column attribute_name format a40; +column attribute_value format a20; +SELECT * FROM ( +SELECT F.feature_id, + A.attribute_name, + A.attribute_value, + A.coefficient + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_NMF('NMF_SH_Sample')) F, + TABLE(F.attribute_set) A +ORDER BY feature_id,attribute_name,attribute_value +) WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- +-- There is no specific set of testing parameters for feature extraction. +-- Examination and analysis of features is the main method to prove +-- the efficacy of an NMF model. +-- + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- +-- +-- For a descriptive mining function like feature extraction, "Scoring" +-- involves providing the probability values for each feature. +-- During model apply, an NMF model maps the original data into the +-- new set of attributes (features) discovered by the model. +-- +-- Cleanup scoring data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nmf_sh_sample_apply_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TYPE Featattrs FORCE'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TYPE Featattr FORCE'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +----------------------- +-- PREPARE SCORING DATA +-- +-- 1. Missing Value Treatment for all predictors +-- skipped. See dmsvcdem.sql for an example. +-- +-- 2. Outlier Treatment +-- Skipped. See dmsvcdem.sql for an example. +-- +-- 3. Normalization +-- +BEGIN + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 'nmf_sh_sample_norm', + data_table_name => 'mining_data_apply_v', + xform_view_name => 'nmf_sh_sample_apply_prepared'); +END; +/ + +------------------------------------------------- +-- SCORE NEW DATA USING SQL DATA MINING FUNCTIONS +-- +------------------ +-- BUSINESS CASE 1 +-- List the features that correspond to customers in this dataset. +-- +SELECT FEATURE_ID(nmf_sh_sample USING *) AS feat, COUNT(*) AS cnt + FROM nmf_sh_sample_apply_prepared +GROUP BY FEATURE_ID(nmf_sh_sample USING *) +ORDER BY cnt DESC,FEAT DESC; + +------------------ +-- BUSINESS CASE 2 +-- List customers that correspond to feature 3 ordered by match quality +-- +SELECT * + FROM (SELECT cust_id, FEATURE_VALUE(nmf_sh_sample, 3 USING *) match_quality + FROM nmf_sh_sample_apply_prepared + ORDER BY match_quality DESC) + WHERE ROWNUM < 11; + +column value format 99.9999 +column fid format 999 +column attr format a25 +column val format a20 +column coeff format 9.9999 + +------------------ +-- BUSINESS CASE 3 +-- List top 10 features corresponding to a given customer +-- record (based on match_quality), and find out the top +-- attributes for each feature (based on coefficient > 0.25) +-- +set echo off +CREATE TYPE Featattr AS OBJECT ( + attr VARCHAR2(30), + val VARCHAR2(30), + coeff NUMBER) +/ +set echo on +CREATE TYPE Featattrs AS TABLE OF Featattr +/ + +column val format a50 +WITH +feat_tab AS ( +SELECT F.feature_id fid, + A.attribute_name attr, + TO_CHAR(A.attribute_value) val, + A.coefficient coeff + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_NMF('nmf_sh_sample')) F, + TABLE(F.attribute_set) A + WHERE A.coefficient > 0.25 +), +feat AS ( +SELECT fid, + CAST(COLLECT(Featattr(attr, val, coeff)) + AS Featattrs) f_attrs + FROM feat_tab +GROUP BY fid +), +cust_10_features AS ( +SELECT T.cust_id, S.feature_id, S.value + FROM (SELECT cust_id, FEATURE_SET(nmf_sh_sample, 10 USING *) pset + FROM nmf_sh_sample_apply_prepared + WHERE cust_id = 100002) T, + TABLE(T.pset) S +) +SELECT A.value, A.feature_id fid, + B.attr, B.val, B.coeff + FROM cust_10_features A, + (SELECT T.fid, F.* + FROM feat T, + TABLE(T.f_attrs) F) B + WHERE A.feature_id = B.fid +ORDER BY A.value DESC, A.feature_id ASC, coeff DESC, attr ASC, val ASC; diff --git a/dmocdemo.java b/dmocdemo.java new file mode 100644 index 0000000..aac40ca --- /dev/null +++ b/dmocdemo.java @@ -0,0 +1,899 @@ +// Copyright (c) 2001, 2006, Oracle. All rights reserved. +// File: dmocdemo.java + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to cluster data records based on Orthogonal Clustering. +* The o-Cluster (OC) clustering model provides the user with insight about the +* discovered groups. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Segment the demographic data into 10 clusters and study the individual +* clusters. Apply clustering model to new data and rank the clusters on probability. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created +* in the user schema using CUSTOMERS, COUNTRIES and SUPPLIMENTARY_DEMOGRAPHICS +* tables. +* +* MINING_DATA_BUILD_STR_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_APPLY_STR_V: +* This view collects the prospective customers' demographics and purchasing +* details for scoring against the clustering model. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* OC is not a distance based algorithm like K-Means, and instead works on +* histograms. Therefore binning is the preferred transformation for high +* cardinality data. OC uses a special binning procedure that automatically +* determines the number of bins based on data statistics. The +* prepareData() method illustrates the binning of the build and apply +* data. +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a clustering model using the OC algorithm. +* Apply Model: +* The results of an APPLY operation will contain a list of the cluster +* identifiers for each case, and the associated probabilities. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic api imports +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Set; +import java.util.TreeMap; +import java.util.Hashtable; +// Java Data Mining (JDM) standard imports +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.NamedObject; +import javax.datamining.base.Task; +import javax.datamining.clustering.Cluster; +import javax.datamining.clustering.ClusteringApplySettings; +import javax.datamining.clustering.ClusteringApplySettingsFactory; +import javax.datamining.clustering.ClusteringModel; +import javax.datamining.clustering.ClusteringSettings; +import javax.datamining.clustering.ClusteringSettingsFactory; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.AttributeType; +import javax.datamining.data.Interval; +import javax.datamining.data.IntervalClosure; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.rule.CompoundPredicate; +import javax.datamining.rule.Predicate; +import javax.datamining.rule.Rule; +import javax.datamining.rule.SimplePredicate; +import javax.datamining.statistics.AttributeStatisticsSet; +import javax.datamining.statistics.UnivariateStatistics; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.OraPLSQLMappings; +import oracle.dmt.jdm.algorithm.ocluster.OraOClusterSettings; +import oracle.dmt.jdm.algorithm.ocluster.OraOClusterSettingsFactory; +import oracle.dmt.jdm.clustering.OraCluster; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.rule.OraSimplePredicate; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.binning.OraBinningTransformFactory; +import oracle.dmt.jdm.transform.binning.OraBinningTransformImpl; +import oracle.dmt.jdm.transform.binning.OraCategoricalBinningType; +import oracle.dmt.jdm.transform.binning.OraNumericalBinningType; + +public class dmocdemo extends Object{ + //Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClusteringSettingsFactory m_clusFactory; + private static OraOClusterSettingsFactory m_oclusterFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClusteringApplySettingsFactory m_applySettingsFactory; + private static OraBinningTransformFactory m_binningXformFactory; + private static OraTransformationTaskFactory m_xformTaskFactory; + // Global constants used for formatting output + private static String TAB = " "; + private static String CR = "\n"; + private static String CR_TAB = "\n "; + private static String HORZ_LINE = "----"; + private static String UNDERLINE = "*************************************"; + private static String LEAF_CLUSTERS_HEADER = "* Leaf clusters *"; + private static String RULES_CLUSTERS_HEADER = "* Rules *"; + private static String RULES_CLUSTERS_HIERARCHY_HEADER = "* Printing clusters hierarchy *"; + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmocdemo "); + System.out.println(" or: java dmocdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + //1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Prepare data + prepareData(); + // 5. Build a model + buildModel(); + // 6. Apply the model + applyModel(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 7. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { }//Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_clusFactory = (ClusteringSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.clustering.ClusteringSettings"); + m_oclusterFactory = (OraOClusterSettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.algorithm.ocluster.OraOClusterSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = (ClusteringApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.clustering.ClusteringApplySettings"); + m_binningXformFactory = (OraBinningTransformFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.binning.OraBinningTransform"); + m_xformTaskFactory = (OraTransformationTaskFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.task.OraTransformationTask"); + } + + /** + * This method illustrates preparation of the data for build and apply + * operations by using binning transformation. + * + * Here all numerical attributes except CUST_ID are prepared using + * auto equal width binning. Categorical attributes are not binned. + * For more details about the binning please refer to + * Oracle Data Mining Concepts Guide. + * + * The case id and any attribute with <= 2 distinct values should be excluded + * from the binning process. + * + * The following table illustrates customer attributes available for building + * the mining model and data characteristics and type of binning used + * for each attribute and number of bins used. + * + * COLUMN_NAME DATA_TYPE DISTINCT EXCLUDED BIN TYPE BIN # + * ------------------ --------- -------- -------- ----------- ----- + * CUST_ID NUMBER 1500 YES + * AGE NUMBER 66 NO AUTOEQWIDTH 10 + * YRS_RESIDENCE NUMBER 15 NO AUTOEQWIDTH 10 + * + * Build data binnning transformation produces numerical and categorical + * bin boundary tables. These tables must be specified for apply data + * to bin the data consistent with the build data. + * Following binned tables are created after the execution of this method. + * + * Unprepared Data ---> Prepared(Binned) Data + * --------------------- --------------------------- + * MINING_DATA_BUILD_STR_V OC_BINNED_DATA_BUILD_JDM + * MINING_DATA_APPLY_STR_V OC_BINNED_DATA_APPLY_JDM + */ + public static void prepareData() throws JDMException + { + boolean isOutputAsView = false; + String inputDataURI = null; + String outputDataURI = null; + String categoricalBinTable = null; + String numericalBinTable = null; + OraTransformationTask xformTask = null; + + // Prepare build data + isOutputAsView = true; + inputDataURI = "MINING_DATA_BUILD_STR_V"; + outputDataURI = "OC_BINNED_DATA_BUILD_JDM"; + // Create boundaries for all numeric attributes + OraBinningTransformImpl buildDataXform = + (OraBinningTransformImpl)m_binningXformFactory.create( + inputDataURI, outputDataURI, isOutputAsView ); + buildDataXform.setLiteralFlag(true); + String[] excludeColumnList = {"CUST_ID"}; + buildDataXform.setExcludeColumnList(excludeColumnList); + buildDataXform.setNumberOfBinsForNumerical(10); + buildDataXform.setNumericalBinningType(OraNumericalBinningType.auto_equi_width); + buildDataXform.setCategoricalBinningType(OraCategoricalBinningType.systemDefault); + xformTask = m_xformTaskFactory.create(buildDataXform); + executeTask(xformTask, "ocPrepareBuildTask_jdm"); + + // Prepare apply data + isOutputAsView = true; + inputDataURI = "MINING_DATA_APPLY_STR_V"; + outputDataURI = "OC_BINNED_DATA_APPLY_JDM"; + categoricalBinTable = buildDataXform.getCategoricalBinTable(); + numericalBinTable = buildDataXform.getNumericalBinTable(); + OraBinningTransformImpl applyDataXform = + (OraBinningTransformImpl)m_binningXformFactory.create( + inputDataURI, outputDataURI, isOutputAsView, + categoricalBinTable, numericalBinTable); + applyDataXform.setLiteralFlag(true); + xformTask = m_xformTaskFactory.create(applyDataXform); + executeTask(xformTask, "ocPrepareApplyTask_jdm"); + } + + /** + * This method illustrates how to build a mining model using the + * "OC_BINNED_DATA_BUILD_JDM" dataset with the OC algorithm. + * + * After completing the build task, the model named "ocModel_jdm" will + * be created. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = m_pdsFactory.create("OC_BINNED_DATA_BUILD_JDM", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("ocBuildData_jdm", buildData, true); + //2. Create & save Mining Function Settings + //Create oClusetr algorithm settings + OraOClusterSettings ocAlgo = (OraOClusterSettings)m_oclusterFactory.create(); + ocAlgo.setBufferSize(30000); + //ocAlgo.setSensitivity(0.5); + + //Create ClusteringSettings + ClusteringSettings buildSettings = m_clusFactory.create(); + buildSettings.setAlgorithmSettings(ocAlgo); + buildSettings.setMaxNumberOfClusters(10); + m_dmeConn.saveObject("ocBuildSettings_jdm", buildSettings, true); + //3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "ocBuildData_jdm", //Build data specification + "ocBuildSettings_jdm", //Mining function settings name + "ocModel_jdm" //Mining model name + ); + buildTask.setDescription("ocBuildTask_jdm"); + executeTask(buildTask, "ocBuildTask_jdm"); + //4. Restore the model from the DME and explore the details of the model + ClusteringModel model = (ClusteringModel) + m_dmeConn.retrieveObject("ocModel_jdm", NamedObject.model); + displayOCModelDetails(model); + } + + /** + * For a descriptive mining function like Clustering, "Scoring" involves + * assigning the probability with which a given case belongs to a given + * cluster. + * + * After completing the apply task, an apply output table + * "oc_apply_output_jdm" will be created at the user specfied location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "OC_BINNED_DATA_APPLY_JDM", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "ocApplyData_jdm", applyData, true ); + //2. Create & save ClassificationApplySettings + ClusteringApplySettings clusAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "ocApplySettings_jdm", clusAS, true); + + //3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "ocApplyData_jdm", + "ocModel_jdm", + "ocApplySettings_jdm", "oc_apply_output_jdm"); + executeTask(applyTask, "ocApplyTask_jdm"); + //4. Display results + displayScoringResults(); + } + + /** + * Shows scoring results. Lists the clusters into which the customers in this + * dataset have been grouped. + */ + public static void displayScoringResults() + { + String sqlResults = + "SELECT clus, COUNT(*) AS CNT FROM " + + " (SELECT cluster_id CLUS, " + + " ROW_NUMBER() OVER " + + " (PARTITION BY CUST_ID ORDER BY PROBABILITY DESC) CLUS_RNK " + + " FROM oc_apply_output_jdm) " + + "WHERE CLUS_RNK = 1 " + + "GROUP BY CLUS ORDER BY CNT DESC"; + + + Statement stmt = null; + ResultSet rs = null; + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + try { + stmt = dbConn.createStatement(); + rs = stmt.executeQuery(sqlResults); + System.out.println("Cluster ID Count"); + System.out.println("----------------------------"); + while ( rs.next() ) { + int clus = rs.getInt(1); + int cnt = rs.getInt(2); + System.out.println(TAB + clus + TAB + TAB + cnt); + } + } catch(SQLException anySqlExp) { + System.out.println(anySqlExp); + } + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + } + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful."); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() ); + } + return isTaskSuccess; + } + + private static void clean() + { + //Drop prepared views + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + //Drop the model + try { + m_dmeConn.removeObject("ocModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW OC_BINNED_DATA_BUILD_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW OC_BINNED_DATA_APPLY_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop apply output table + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE OC_APPLY_OUTPUT"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + } + + /** + * This method displayes OC model details. + * + * @param model to be presented + * + * @exception JDMException if failed to retrieve model details + */ + public static void displayOCModelDetails(ClusteringModel model) throws JDMException{ + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + System.out.println("Clustering model details:"); + System.out.println(TAB+"Number of clusters: "+ model.getNumberOfClusters()); + System.out.println(TAB+"Number of tree levels: "+ model.getNumberOfLevels()); + Collection clusters = model.getClusters(); + if ( clusters == null || clusters.isEmpty() == true ){ + System.out.println("Unable to retrieve clusters."); + return; + } + + // Display root cluster(s) + Collection vRootClusters = model.getRootClusters(); + Cluster[] rootCluster = null; + if ( vRootClusters != null && vRootClusters.isEmpty() == false ){ + rootCluster =(Cluster[])vRootClusters.toArray(new Cluster[vRootClusters.size()]); + if ( rootCluster != null ){ + System.out.println(TAB+"Root Cluster Id: " + rootCluster[0].getClusterId()); + } + } + + // Display leaf clusters + Collection vLeafClusters = model.getLeafClusters(); + if ( vLeafClusters != null && vLeafClusters.isEmpty() == false ){ + Cluster[] leafClusters =(Cluster[])vLeafClusters.toArray(new Cluster[vLeafClusters.size()]); + System.out.println(UNDERLINE); + System.out.println(LEAF_CLUSTERS_HEADER); + System.out.println(UNDERLINE); + for ( int ni = 0; ni < leafClusters.length ; ni++ ) { + printSingleClusterDetails(leafClusters[ni]); + if ( ni == 0 ){ + // display first leaf cluster statistics + printClusterStatistics(model, leafClusters[ni], 1); + } + } + } + + // Display all model rules + Collection vRules = model.getRules(); + if ( vRules != null && vRules.isEmpty() == false ){ + Rule[] rules =(Rule[])vRules.toArray(new Rule[vRules.size()]); + System.out.println(CR+CR+UNDERLINE); + System.out.println(RULES_CLUSTERS_HEADER); + System.out.println(UNDERLINE); + for ( int rl = 0; rl < rules.length ; rl++ ) { + printRuleNoDetails(rules[rl], 0); + } + } + + if ( rootCluster != null ){ + // print hierarchy + System.out.println(CR+CR+UNDERLINE); + System.out.println(RULES_CLUSTERS_HIERARCHY_HEADER); + System.out.println(UNDERLINE); + // 1.print root + printRootClusterDetails(rootCluster[0]); + // 1.print children + Cluster[] children = rootCluster[0].getChildren(); + int indent = 0; + if ( children != null ){ + for (int k=0 ; kSimplePredicate information. + * + * @param predicate SimplePredicate being presented + * + * @exception JDMException if failed to retrieve SimplePredicate details + */ + public static StringBuffer printSimplePredicate(SimplePredicate predicate) throws JDMException{ + StringBuffer sb = new StringBuffer(); + if(predicate == null){ + sb.append(" "); + return sb; + } + if ( predicate.isNumericalValue() ){ + sb.append( + predicate.getAttributeName() + " " + + //((OraSimplePredicate)predicate).getComparisonOperatorValue() + " " + + OraPLSQLMappings.getComparisonOperatorValue_tree(((OraSimplePredicate)predicate).getComparisonOperator()) + " " + + predicate.getNumericalValue() + ); + } + else{ + sb = new StringBuffer( + predicate.getAttributeName() + " " + + //((OraSimplePredicate)predicate).getComparisonOperatorValue() + " " + OraPLSQLMappings.getComparisonOperatorValue_tree(((OraSimplePredicate)predicate).getComparisonOperator()) + " " + ); + Object[] inValues = predicate.getCategoryValues(); + if ( inValues != null ){ + for (int i=0 ; i < inValues.length; i++ ) { + sb.append(inValues[i] ); + if ( i != inValues.length - 1) + sb.append(","); + } + } + } + return sb; + } + + /** + * This method shows details of the root cluster. + * + * @param cluster root cluster + * + * @exception JDMException if failed to retrieve root cluster details + */ + public static void printRootClusterDetails(Cluster cluster) throws JDMException{ + CompoundPredicate cp = (CompoundPredicate)cluster.getSplitPredicate(); + Predicate[] predicates = cp.getPredicates(); + for ( int ni = 0; ni < predicates.length; ni++) { + StringBuffer sb = printSimplePredicate((SimplePredicate)predicates[ni]); + System.out.println(CR+"Root Cluster Id: " + cluster.getClusterId() + + CR_TAB + "Case Count: " + cluster.getCaseCount() + + CR_TAB + "Tree Level: " + cluster.getLevel() + + CR_TAB + "Dispersion: " + ((OraCluster)cluster).getDispersion() + + CR_TAB + "Split predicate: " + sb.toString() + + CR_TAB + "Children:" + ); + } + } + + /** + * This method shows details of any cluster. + * + * @param cluster cluster being presented + * + * @exception JDMException if failed to retrieve this cluster details + */ + public static void printSingleClusterDetails(Cluster cluster) throws JDMException{ + System.out.println(CR+"Cluster Id: " + cluster.getClusterId() + + CR_TAB+"Case Count: " + cluster.getCaseCount() + + CR_TAB+"Tree Level: " + cluster.getLevel() + + CR_TAB+"Dispersion: " + ((OraCluster)cluster).getDispersion() + + CR_TAB+"Parent's id: " + ( cluster.getParent() != null ? + String.valueOf(cluster.getParent().getClusterId()) : "") + + CR_TAB + "Is root Cluster: " + cluster.isRoot() + + CR_TAB + "Is leaf Cluster: " + cluster.isLeaf() + ); + + Cluster[] ancestors = cluster.getAncestors(); + StringBuffer sbTab = new StringBuffer(TAB+"Anchestors "); + if ( ancestors != null ){ + for (int j=0 ; j 'oc_sh_sample_num'); + + DBMS_DATA_MINING_TRANSFORM.INSERT_AUTOBIN_NUM_EQWIDTH( + bin_table_name => 'oc_sh_sample_num', + data_table_name => 'mining_data_build_str_v', + -- categoricals are automatically excluded by this procedure + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'cust_id'), + sample_size => 30000 -- same as OCLT_MAX_BUFFER setting below + ); + + -- Create the transformed view + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM( + bin_table_name => 'oc_sh_sample_num', + data_table_name => 'mining_data_build_str_v', + xform_view_name => 'oc_sh_sample_build_prepared', + -- see dbmsdmxf.sql for explanation of literal flag + literal_flag => TRUE); +END; +/ + +-- DATA PREPARATION OBJECTS: +-- ------------------------ +-- 1. Bin boundary Table: oc_sh_sample_num +-- 2. Input (view) to CREATE_MODEL: oc_sh_sample_build_prepared + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE oc_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- K-Means is the default clustering algorithm. Override the +-- default to set the algorithm to O-Cluster using a settings table. +-- +-- CREATE AND POPULATE A SETTINGS TABLE +-- +set echo off +CREATE TABLE oc_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on +BEGIN + INSERT INTO oc_sh_sample_settings VALUES + (dbms_data_mining.algo_name, dbms_data_mining.algo_ocluster); + INSERT INTO oc_sh_sample_settings VALUES + (dbms_data_mining.clus_num_clusters, 10); + INSERT INTO oc_sh_sample_settings VALUES + (dbms_data_mining.oclt_max_buffer, 30000); + + -- Other possible settings are: + -- (dbms_data_mining.oclt_sensitivity, 0.5); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Build a new OC model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'OC_SH_Clus_sample', + mining_function => dbms_data_mining.clustering, + data_table_name => 'oc_sh_sample_build_prepared', + case_id_column_name => 'cust_id', + settings_table_name => 'oc_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'OC_SH_CLUS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'OC_SH_CLUS_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Cluster details are best seen in pieces - based on the kind of +-- associations and groupings that are needed to be observed. +-- + +-- CLUSTERS +-- For each cluster_id, provides the number of records in the cluster, +-- the parent cluster id, and the level in the hierarchy. +-- NOTE: Unlike K-means, O-Cluster does not return a value for the +-- dispersion associated with a cluster. +-- +SELECT T.id clu_id, + T.record_count rec_cnt, + T.parent parent, + T.tree_level tree_level + FROM (SELECT * + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_OC( + 'OC_SH_Clus_sample')) + ORDER BY id) T + WHERE ROWNUM < 11; + +-- TAXONOMY +-- +SELECT clu_id, child_id + FROM (SELECT T.id clu_id, C.id child_id + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_OC( + 'OC_SH_Clus_sample')) T, + TABLE(T.child) C + ORDER BY T.id,C.id) + WHERE ROWNUM < 11; + +-- SPLIT PREDICATES +-- For each cluster, the split predicate indicates the attribute +-- and the condition used to assign records to the cluster's children +-- during model build. It provides an important piece of information +-- on how the population within a cluster can be divided up into +-- two smaller clusters. +-- +column attribute_name format a20 +column op format a2 +column s_value format a50 +SELECT clu_id, attribute_name, op, s_value + FROM (SELECT a.id clu_id, sp.attribute_name, sp.conditional_operator op, + sp.attribute_str_value s_value + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_OC( + 'OC_SH_Clus_sample')) a, + TABLE(a.split_predicate) sp + ORDER BY a.id, op, s_value) + WHERE ROWNUM < 11; + +-- CENTROIDS FOR LEAF CLUSTERS +-- For each cluster_id, this output lists all the attributes that +-- constitute the centroid, with the mean (for numericals) or +-- mode (for categoricals). Unlike K-Means, O-Cluster does not return +-- the variance for numeric attributes. +-- +column mode_val format a60 +SELECT clu_id, attribute_name, mean, mode_val + FROM (SELECT a.id clu_id, c.attribute_name, c.mean, c.mode_value mode_val + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_OC( + 'OC_SH_Clus_sample')) a, + TABLE(a.centroid) c + ORDER BY a.id, c.attribute_name) + WHERE ROWNUM < 11; + +-- HISTOGRAM FOR LEAF CLUSTERS +-- Histogram count is represented in frequency, rather than actual count. +column count format 9999.99 +column bin_id format 9999999 +column clu_id format 99999999 +column label format a15; +SELECT clu_id, bin_id, attribute_name, label, cnt + FROM (SELECT a.id clu_id, h.bin_id, h.attribute_name, h.label, h.count cnt + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_OC( + 'OC_SH_Clus_sample')) a, + TABLE(a.histogram) h + ORDER BY a.id, h.attribute_name, h.bin_id) + WHERE ROWNUM < 11; + +-- RULES FOR LEAF CLUSTERS +-- See dmkmdemo.sql for explanation on output columns. +column confidence format 999999.99 +SELECT * + FROM (SELECT T.id rule_id, + T.rule.rule_support support, + T.rule.rule_confidence confidence + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_OC( + 'OC_SH_Clus_sample')) T + ORDER BY confidence DESC, support DESC) + WHERE confidence > 0.5; + +-- RULE DETAILS FOR LEAF CLUSTERS +-- +-- The build data is prepared in this example, so reverse transform +-- the model contents to corresponding bin boundary labels. Translation +-- back to the exact value is not possible. +-- +-- See dmkmdemo.sql for explanation on output columns. +column val format a60; +WITH +mod_dtls AS ( +SELECT * + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_OC('OC_SH_Clus_sample')) +), +bin_labels AS ( +SELECT col, bin, (DECODE(bin,'1','[','(') || lv || ',' || val || ']') label + FROM (SELECT col, + bin, + LAST_VALUE(val) OVER ( + PARTITION BY col ORDER BY val + ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) lv, + val + FROM oc_sh_sample_num) +) +SELECT R.id rule_id, + A.attribute_name attribute_name, + A.conditional_operator op, + NVL(L.label, NVL(A.attribute_str_value,A.attribute_num_value)) val, + A.attribute_support support, + A.attribute_confidence confidence + FROM mod_dtls R, + TABLE(R.rule.antecedent) A, + bin_labels L + WHERE A.attribute_name = L.col (+) AND + (NVL(A.attribute_str_value,A.attribute_num_value) = L.bin(+)) AND + A.attribute_confidence > 0.5 +ORDER BY confidence DESC, support DESC, rule_id, attribute_name, val; + +-- 0.5 is used as the threshold just to show some numerical attributes +-- that have been decoded back to their original ranges. +-- The ORDER BYs are there just to enable repeatable output; they are +-- not a mandatory part of the query. + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +-- There is no specific set of testing parameters for Clustering. +-- Examination and analysis of clusters is the main method to prove +-- the efficacy of a clustering model. +-- + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- +-- For a descriptive mining function like Clustering, "Scoring" involves +-- assigning the probability with which a given case belongs to a given +-- cluster. + +-- Cleanup scoring data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP VIEW oc_sh_sample_apply_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +----------------------- +-- PREPARE SCORING DATA +-- +-- 1. Outlier Treatment +-- Skipped. See dmsvcdem.sql for an example. +-- +-- 2. Binning +-- Use the Bin Boundary Table obtained earlier to bin the apply data. +-- +BEGIN + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM( + bin_table_name => 'oc_sh_sample_num', + data_table_name => 'mining_data_apply_str_v', + xform_view_name => 'oc_sh_sample_apply_prepared', + literal_flag => TRUE); +END; +/ + +-- Cleanup scoring result objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE oc_sh_sample_apply_result'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE oc_sh_sample_apply_ranked'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------------------------------------- +-- SCORE NEW DATA USING SQL DATA MINING FUNCTIONS +-- +------------------ +-- BUSINESS CASE 1 +-- List the clusters into which the customers in this +-- given dataset have been grouped. +-- +SELECT CLUSTER_ID(oc_sh_clus_sample USING *) AS clus, COUNT(*) AS cnt + FROM oc_sh_sample_apply_prepared +GROUP BY CLUSTER_ID(oc_sh_clus_sample USING *) +ORDER BY cnt DESC; + +-- See dmkmdemo.sql for more examples diff --git a/dmpademo.java b/dmpademo.java new file mode 100644 index 0000000..bc53b61 --- /dev/null +++ b/dmpademo.java @@ -0,0 +1,235 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmpademo.java +// Generic api imports +import java.sql.Statement; +// Java Data Mining (JDM) standard imports +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.NamedObject; +import javax.datamining.base.Task; +import javax.datamining.resource.Connection; +import javax.datamining.resource.ConnectionFactory; +import javax.datamining.resource.ConnectionSpec; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.task.OraExplainTask; +import oracle.dmt.jdm.task.OraExplainTaskFactory; +import oracle.dmt.jdm.task.OraPredictTask; +import oracle.dmt.jdm.task.OraPredictTaskFactory; +import oracle.dmt.jdm.task.OraPredictiveAnalyticsTaskFactory; +import oracle.dmt.jdm.task.OraProfileTask; + +/** +* Predictive Analytics Demo. This demo runs the predict, explain and profile +* tasks. +* +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +public class + +dmpademo + extends Object +{ + + //Connection related data members + private static Connection m_dmeConn = null; + private static ConnectionFactory m_dmeConnFactory = null; + //Object factories used in this demo program + private static OraPredictiveAnalyticsTaskFactory m_paFactory = null; + + public static void main(String[] args) + { + try + { + if (args.length != 3) + { + System.out.println("Usage: java dmpademo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Initialize factories for mining objects + initFactories(); + // 3. Predict + predict(); + // 4. Explain + explain(); + // 5. Profile + profile(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + // 6. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + } //Ignore + } + } + + public static void initFactories() + throws JDMException + { + m_paFactory = + (OraPredictiveAnalyticsTaskFactory) m_dmeConn.getFactory("oracle.dmt.jdm.task.OraPredictiveAnalyticsTask"); + } + + /** + * This method builds a mining model. The build operation requires the training + * dataset location details and the mining function settings. + * In this example, we will use the original unprepared dataset + * "MINING_DATA_BUILD_V" as an input. The predictTask will automatically + * prepare the dataset and create a new prepared dataset called + * "JDM_PRED_MINING_DATA_BUILD". Then, we will build a classification model + * using the prepared build dataset in the user schema, with the NaiveBayes + * algorithm. This model can be used to predict which customer would respond + * to a promotion campaign. + */ + public static void predict() + throws JDMException + { + //1. Create, save & execute predict Task + OraPredictTask predictTask = + m_paFactory.createPredictTask("MINING_DATA_BUILD_V", "cust_id", + "affinity_card", + "JDM_PRED_MINING_DATA_BUILD"); + predictTask.setDescription("PredictTask_jdm"); + ((OraTask)predictTask).overwriteOutput(true); + executeTask(predictTask, "PredictTask_jdm"); + //Retrieve task & see the details of the task (Note:Remove this from demo program) + try + { + predictTask = + (OraPredictTask) m_dmeConn.retrieveObject("PredictTask_jdm", + NamedObject.task); + predictTask.getInputData(); + predictTask.getOutputData(); + predictTask.getTargetAttributeName(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(); + } + } + + public static void explain() + throws JDMException + { + //1. Create, save & execute predict Task + OraExplainTask explainTask = + m_paFactory.createExplainTask("MINING_DATA_BUILD_V", "affinity_card", + "JDM_EXPL_MINING_DATA_BUILD"); + explainTask.setDescription("ExplainTask_jdm"); + ((OraTask)explainTask).overwriteOutput(true); + executeTask(explainTask, "ExplainTask_jdm"); + try + { + explainTask = + (OraExplainTask) m_dmeConn.retrieveObject("ExplainTask_jdm", + NamedObject.task); + explainTask.getInputData(); + explainTask.getOutputData(); + explainTask.getExplainAttributeName(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(); + } + } + + /** + * This method builds a mining model. The build operation requires the training + * dataset location details and the mining function settings. + * In this example, we will use the original unprepared dataset + * "MINING_DATA_BUILD_V" as an input. The predictTask will automatically + * prepare the dataset and create a new prepared dataset called + * "JDM_PRED_MINING_DATA_BUILD". Then, we will build a classification model + * using the prepared build dataset in the user schema, with the NaiveBayes + * algorithm. This model can be used to predict which customer would respond + * to a promotion campaign. + */ + public static void profile() + throws JDMException + { + //1. Create, save & execute predict Task + OraProfileTask profileTask = + m_paFactory.createProfileTask("MINING_DATA_BUILD_V", "affinity_card", + "JDM_PROFILE_RESULTS"); + profileTask.setDescription("ProfileTask_jdm"); + ((OraTask)profileTask).overwriteOutput(true); + executeTask(profileTask, "ProfileTask_jdm"); + //Retrieve task & see the details of the task (Note:Remove this from demo program) + try + { + profileTask = + (OraProfileTask) m_dmeConn.retrieveObject("ProfileTask_jdm", + NamedObject.task); + profileTask.getInputData(); + profileTask.getTargetAttributeName(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(); + } + } + + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints the error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException + { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = + execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if (isTaskSuccess) + { + //Task completed successfully + System.out.println(taskName + " is successful."); + } + else + { //Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription()); + } + return isTaskSuccess; + } +} diff --git a/dmsh.sql b/dmsh.sql new file mode 100644 index 0000000..5678615 --- /dev/null +++ b/dmsh.sql @@ -0,0 +1,593 @@ +-------------------------------------------------------------------------------- +-- +-- $Header: dmsh.sql 11-jul-2005.15:09:03 ktaylor Exp $ +-- +-- dmsh.sql +-- +-- Copyright (c) 2001, 2005, Oracle. All rights reserved. +-- +-- NAME +-- dmsh.sql +-- +-- DESCRIPTION +-- This script creates views and tables using SH data +-- in the schema of the data mining user. These tables/views +-- are the datasets used by the Oracle Data Mining demo programs. +-- This script also creates an index and index preference for +-- text mining. +-- NOTES +-- The script assumes that the full SH schema is already created and the +-- necessary SELECTs have been granted (See dmshgrants.sql). This script runs in +-- the schema of the data mining user. +-- mining_data_*_str_v views : Used for OC +-- mining_data_*_v views : Used for mining (no text) +-- market_basket_v view : Used for association rules +-- mining_*_text tables: Used for Text mining in ODM Java API +-- mining_*_nested_text tables: Used for Text mining in DBMS_DATA_MINING API +-- +-- MODIFIED (MM/DD/YY) +-- ktaylor 07/11/05 - minor edits to comments +-- xbarr 03/14/05 - add purge for object drop +-- cbhagwat 11/09/04 - Using collect +-- bmilenov 10/20/04 - Add one-class demo view +-- cbhagwat 09/17/04 - Bug 3881118 +-- xbarr 08/17/04 - create view for OC +-- xbarr 06/25/04 - xbarr_dm_rdbms_migration +-- cbhagwat 11/11/03 - Text NMF_CLUSTERING => SVM_CLASSIFIER +-- cbhagwat 10/10/03 - Remove DROPs +-- cbhagwat 10/10/03 - Remove Sh grants +-- cbhagwat 10/09/03 - Add nested table creatin using Text tf +-- cbhagwat 10/08/03 - cbhagwat_txn109150 +-- cbhagwat 10/08/03 - creation +-- +-------------------------------------------------------------------------------- +-- +-- Creates data mining views on SH data +-- +-- Build, apply views for OC +CREATE VIEW mining_data_apply_str_v( +CUST_ID, +CUST_GENDER, +AGE, +CUST_MARITAL_STATUS, +COUNTRY_NAME, +CUST_INCOME_LEVEL, +EDUCATION, +OCCUPATION, +HOUSEHOLD_SIZE, +YRS_RESIDENCE, +AFFINITY_CARD, +BULK_PACK_DISKETTES, +FLAT_PANEL_MONITOR, +HOME_THEATER_PACKAGE, +BOOKKEEPING_APPLICATION, +PRINTER_SUPPLIES, +Y_BOX_GAMES, +OS_DOC_SET_KANJI) +AS SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + SUBSTR(TO_CHAR(b.AFFINITY_CARD),1,1), + SUBSTR(TO_CHAR(b.BULK_PACK_DISKETTES),1,1), + SUBSTR(TO_CHAR(b.FLAT_PANEL_MONITOR),1,1), + SUBSTR(TO_CHAR(b.HOME_THEATER_PACKAGE),1,1), + SUBSTR(TO_CHAR(b.BOOKKEEPING_APPLICATION),1,1), + SUBSTR(TO_CHAR(b.PRINTER_SUPPLIES),1,1), + SUBSTR(TO_CHAR(b.Y_BOX_GAMES),1,1), + SUBSTR(TO_CHAR(b.OS_DOC_SET_KANJI),1,1) +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 100001 and 101500; + +CREATE VIEW mining_data_build_str_v( +CUST_ID, +CUST_GENDER, +AGE, +CUST_MARITAL_STATUS, +COUNTRY_NAME, +CUST_INCOME_LEVEL, +EDUCATION, +OCCUPATION, +HOUSEHOLD_SIZE, +YRS_RESIDENCE, +AFFINITY_CARD, +BULK_PACK_DISKETTES, +FLAT_PANEL_MONITOR, +HOME_THEATER_PACKAGE, +BOOKKEEPING_APPLICATION, +PRINTER_SUPPLIES, +Y_BOX_GAMES, +OS_DOC_SET_KANJI) +AS SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + SUBSTR(TO_CHAR(b.AFFINITY_CARD),1,1), + SUBSTR(TO_CHAR(b.BULK_PACK_DISKETTES),1,1), + SUBSTR(TO_CHAR(b.FLAT_PANEL_MONITOR),1,1), + SUBSTR(TO_CHAR(b.HOME_THEATER_PACKAGE),1,1), + SUBSTR(TO_CHAR(b.BOOKKEEPING_APPLICATION),1,1), + SUBSTR(TO_CHAR(b.PRINTER_SUPPLIES),1,1), + SUBSTR(TO_CHAR(b.Y_BOX_GAMES),1,1), + SUBSTR(TO_CHAR(b.OS_DOC_SET_KANJI),1,1) +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 101501 and 103000; + +-- Build , test and apply views, no text +CREATE VIEW mining_data_apply_v AS +SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + b.AFFINITY_CARD, + b.BULK_PACK_DISKETTES, + b.FLAT_PANEL_MONITOR, + b.HOME_THEATER_PACKAGE, + b.BOOKKEEPING_APPLICATION, + b.PRINTER_SUPPLIES, + b.Y_BOX_GAMES, + b.OS_DOC_SET_KANJI +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 100001 and 101500; + +CREATE VIEW mining_data_build_v AS +SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + b.AFFINITY_CARD, + b.BULK_PACK_DISKETTES, + b.FLAT_PANEL_MONITOR, + b.HOME_THEATER_PACKAGE, + b.BOOKKEEPING_APPLICATION, + b.PRINTER_SUPPLIES, + b.Y_BOX_GAMES, + b.OS_DOC_SET_KANJI +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 101501 and 103000; + +CREATE VIEW mining_data_test_v AS +SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + b.AFFINITY_CARD, + b.BULK_PACK_DISKETTES, + b.FLAT_PANEL_MONITOR, + b.HOME_THEATER_PACKAGE, + b.BOOKKEEPING_APPLICATION, + b.PRINTER_SUPPLIES, + b.Y_BOX_GAMES, + b.OS_DOC_SET_KANJI +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 103001 and 104500; + +CREATE VIEW market_basket_v AS +SELECT a.cust_id, + MAX((CASE WHEN b.PROD_NAME = + 'Extension Cable' THEN a.QUANTITY_SOLD else null end)) EXTENSION_CABLE, + MAX((CASE WHEN b.PROD_NAME = + '18" Flat Panel Graphics Monitor' THEN a.QUANTITY_SOLD else NULL END)) + FLAT_PANEL_MONITOR , + MAX((CASE WHEN b.PROD_NAME = + 'CD-RW, High Speed Pack of 5' THEN a.QUANTITY_SOLD else NULL END)) + CD_RW_HIGH_SPEED_5_PACK, + MAX((CASE WHEN b.PROD_NAME = + 'Envoy 256MB - 40GB' THEN a.QUANTITY_SOLD else NULL END)) + ENVOY_256MB_40GB, + MAX((CASE WHEN b.PROD_NAME = + 'Envoy Ambassador' THEN a.QUANTITY_SOLD else NULL END)) + ENVOY_AMBASSADOR, + MAX((CASE WHEN b.PROD_NAME = + 'External 8X CD-ROM' THEN a.QUANTITY_SOLD else NULL END)) + EXTERNAL_8X_CD_ROM, + MAX((CASE WHEN b.PROD_NAME = + 'Keyboard Wrist Rest' THEN a.QUANTITY_SOLD else NULL END)) + KEYBOARD_WRIST_REST, + MAX((CASE WHEN b.PROD_NAME = + 'Model SM26273 Black Ink Cartridge' THEN a.QUANTITY_SOLD else NULL END)) + SM26273_BLACK_INK_CARTRIDGE, + MAX((CASE WHEN b.PROD_NAME = + 'Mouse Pad' THEN a.QUANTITY_SOLD else NULL END)) + MOUSE_PAD, + MAX((CASE WHEN b.PROD_NAME = + 'Multimedia speakers- 3" cones' THEN a.QUANTITY_SOLD else NULL END)) + MULTIMEDIA_SPEAKERS_3INCH, + MAX((CASE WHEN b.PROD_NAME = + 'O/S Documentation Set - English' THEN a.QUANTITY_SOLD else NULL END)) + OS_DOC_SET_ENGLISH, + MAX((CASE WHEN b.PROD_NAME = + 'SIMM- 16MB PCMCIAII card' THEN a.QUANTITY_SOLD else NULL END)) + SIMM_16MB_PCMCIAII_CARD, + MAX((CASE WHEN b.PROD_NAME = + 'Standard Mouse' THEN a.QUANTITY_SOLD else NULL END)) + STANDARD_MOUSE +FROM sh.sales a, + sh.products b + where a.prod_id = b.prod_id + AND a.cust_id BETWEEN 100001 AND 104500 + group by cust_id; + +-- Build, test and apply views with Text + +CREATE TABLE mining_apply_text AS +SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + b.AFFINITY_CARD, + b.BULK_PACK_DISKETTES, + b.FLAT_PANEL_MONITOR, + b.HOME_THEATER_PACKAGE, + b.BOOKKEEPING_APPLICATION, + b.PRINTER_SUPPLIES, + b.Y_BOX_GAMES, + b.os_doc_set_kanji, + b.comments +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 100001 and 101500; + +-- CREATE TEXT INDEX +CREATE INDEX apply_text_idx ON mining_apply_text(comments) + INDEXTYPE IS ctxsys.context PARAMETERS('nopopulate') +/ + +CREATE TABLE mining_build_text AS +SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + b.AFFINITY_CARD, + b.BULK_PACK_DISKETTES, + b.FLAT_PANEL_MONITOR, + b.HOME_THEATER_PACKAGE, + b.BOOKKEEPING_APPLICATION, + b.PRINTER_SUPPLIES, + b.Y_BOX_GAMES, + b.os_doc_set_kanji, + b.comments +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 101501 and 103000; + +-- CREATE TEXT INDEX +CREATE INDEX build_text_idx ON mining_build_text(comments) + INDEXTYPE IS ctxsys.context PARAMETERS('nopopulate') +/ + +CREATE TABLE mining_test_text AS +SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + b.AFFINITY_CARD, + b.BULK_PACK_DISKETTES, + b.FLAT_PANEL_MONITOR, + b.HOME_THEATER_PACKAGE, + b.BOOKKEEPING_APPLICATION, + b.PRINTER_SUPPLIES, + b.Y_BOX_GAMES, + b.os_doc_set_kanji, + b.comments +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 103001 and 104500; + +-- CREATE TEXT INDEX +CREATE INDEX test_text_idx ON mining_test_text(comments) + INDEXTYPE IS ctxsys.context PARAMETERS('nopopulate') +/ + +-- +-- Use the text table functions to create nested data +-- Using dm$ to avoid conflicts with user tables +EXECUTE ctx_ddl.create_preference('dm$temp_text_pref','SVM_CLASSIFIER'); + +-- SVM_CLASSIFIER needs a table +CREATE TABLE + dm$temp_text_pref_cat ( + id NUMBER, + cat NUMBER) +/ + +-- Extract features from the build table +CREATE TABLE dm$build_tf_out AS +SELECT * + FROM + TABLE(ctxsys.drvodm.feature_prep + ('BUILD_TEXT_IDX', -- Text index name + 'CUST_ID', -- case-id + 'dm$temp_text_pref_cat', + 'id', + 'cat', + 'dm$build_prep_features', -- Features table + 'dm$temp_text_pref')) -- Text preference name +/ +CREATE TABLE dm$build_explain_out AS +SELECT a.sequence_id, + b.text, + a.value + FROM dm$build_tf_out a, + TABLE(ctxsys.drvodm.feature_explain('dm$build_prep_features')) b + WHERE a.attribute_id = b.id +/ +CREATE TABLE mining_build_nested_text + NESTED TABLE comments store AS build_comments + AS +SELECT non_text.cust_id, + non_text.cust_gender, + non_text.age, + non_text.cust_marital_status, + non_text.country_name, + non_text.cust_income_level, + non_text.education, + non_text.occupation, + non_text.household_size, + non_text.yrs_residence, + non_text.affinity_card, + non_text.bulk_pack_diskettes, + non_text.flat_panel_monitor, + non_text.home_theater_package, + non_text.bookkeeping_application, + non_text.printer_supplies, + non_text.y_box_games, + non_text.os_doc_set_kanji, + txt.comments + FROM + mining_build_text non_text, + ( SELECT features.sequence_id, + cast(COLLECT(dm_nested_numerical(features.text,features.value)) + as dm_nested_numericals) comments + FROM dm$build_explain_out features + group by features.sequence_id) txt + WHERE non_text.cust_id = txt.sequence_id(+) +/ + +DROP TABLE dm$build_tf_out purge; +DROP TABLE dm$build_explain_out purge; + +-- +-- Extract features, Cast into dm_nested_numericals +-- Make a TEST view with non-text and text data +-- Use featres table from build data +CREATE TABLE dm$test_tf_out AS +SELECT * + FROM + TABLE(ctxsys.drvodm.feature_prep + ('TEST_TEXT_IDX', -- Text index name + 'CUST_ID', -- case-id + 'dm$build_prep_features')) -- restab +/ +CREATE TABLE dm$test_explain_out AS +SELECT a.sequence_id, + b.text, + a.value + FROM dm$test_tf_out a, + TABLE(ctxsys.drvodm.feature_explain('dm$build_prep_features')) b + WHERE a.attribute_id = b.id +/ +CREATE TABLE mining_test_nested_text + NESTED TABLE comments store AS test_comments AS +SELECT non_text.cust_id, + non_text.cust_gender, + non_text.age, + non_text.cust_marital_status, + non_text.country_name, + non_text.cust_income_level, + non_text.education, + non_text.occupation, + non_text.household_size, + non_text.yrs_residence, + non_text.affinity_card, + non_text.bulk_pack_diskettes, + non_text.flat_panel_monitor, + non_text.home_theater_package, + non_text.bookkeeping_application, + non_text.printer_supplies, + non_text.y_box_games, + non_text.os_doc_set_kanji, + txt.comments + FROM + mining_test_text non_text, + ( SELECT features.sequence_id, + cast(COLLECT(dm_nested_numerical(features.text,features.value)) + as dm_nested_numericals) comments + FROM dm$test_explain_out features + group by features.sequence_id) txt + WHERE non_text.cust_id = txt.sequence_id(+) +/ + +DROP TABLE dm$test_tf_out purge; +DROP TABLE dm$test_explain_out purge; + + +-- Extract features from the build table +-- Use features from build data +CREATE TABLE dm$apply_tf_out AS +SELECT * + FROM + TABLE(ctxsys.drvodm.feature_prep + ('APPLY_TEXT_IDX', -- Text index name + 'CUST_ID', -- case-id + 'dm$build_prep_features')) -- restab +/ +CREATE TABLE dm$apply_explain_out AS +SELECT a.sequence_id, + b.text, + a.value + FROM dm$apply_tf_out a, + TABLE(ctxsys.drvodm.feature_explain('dm$build_prep_features')) b + WHERE a.attribute_id = b.id +/ + +CREATE TABLE mining_apply_nested_text + NESTED TABLE comments store AS apply_comments AS +SELECT non_text.cust_id, + non_text.cust_gender, + non_text.age, + non_text.cust_marital_status, + non_text.country_name, + non_text.cust_income_level, + non_text.education, + non_text.occupation, + non_text.household_size, + non_text.yrs_residence, + non_text.affinity_card, + non_text.bulk_pack_diskettes, + non_text.flat_panel_monitor, + non_text.home_theater_package, + non_text.bookkeeping_application, + non_text.printer_supplies, + non_text.y_box_games, + non_text.os_doc_set_kanji, + txt.comments + FROM + mining_apply_text non_text, + ( SELECT features.sequence_id, + cast(COLLECT(dm_nested_numerical(features.text,features.value)) + as dm_nested_numericals) comments + FROM dm$apply_explain_out features + group by features.sequence_id) txt + WHERE non_text.cust_id = txt.sequence_id(+) +/ + +CREATE VIEW mining_data_one_class_v AS +SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 101501 and 103000 + AND affinity_card=1; + +DROP TABLE dm$build_prep_features purge; +DROP TABLE dm$apply_tf_out purge; +DROP TABLE dm$apply_explain_out purge; +-- Clean up the temp preference +EXECUTE ctx_ddl.drop_preference('dm$temp_text_pref'); +-- Clean up temp cat table created +DROP TABLE dm$temp_text_pref_cat purge; + + + + + + + + + diff --git a/dmshgrants.sql b/dmshgrants.sql new file mode 100644 index 0000000..c9cdcbf --- /dev/null +++ b/dmshgrants.sql @@ -0,0 +1,61 @@ +-------------------------------------------------------------------------------- +-- +-- $Header: dmshgrants.sql 28-aug-2007.07:35:51 xbarr Exp $ +-- +-- dmshgrants.sql +-- +-- Copyright (c) 2001, 2005, Oracle. All rights reserved. +-- +-- NAME +-- dmshgrants.sql +-- +-- DESCRIPTION +-- This script grants SELECT on SH tables and SYS privileges +-- required to run the Oracle Data Mining demo programs +-- +-- The script is to be run in SYS account +-- +-- NOTES +-- &&1 Name of the DM user +-- +-- MODIFIED (MM/DD/YY) +-- xbarr 08/28/07 - fix security bug 6367775 +-- pstengar 07/05/06 - add create mining model privilege +-- ktaylor 07/11/05 - Minor edits to comments +-- xbarr 12/20/04 - add privileges required by DM demo +-- cbhagwat 10/10/03 - creation +-- +-------------------------------------------------------------------------------- +DEFINE DMUSER = &&1 + +GRANT create procedure to &DMUSER +/ +grant create session to &DMUSER +/ +grant create table to &DMUSER +/ +grant create sequence to &DMUSER +/ +grant create view to &DMUSER +/ +grant create job to &DMUSER +/ +grant create type to &DMUSER +/ +grant create synonym to &DMUSER +/ +grant create mining model to &DMUSER +/ +grant execute on ctxsys.ctx_ddl to &DMUSER +/ + +GRANT SELECT ON sh.customers TO &DMUSER +/ +GRANT SELECT ON sh.sales TO &DMUSER +/ +GRANT SELECT ON sh.products TO &DMUSER +/ +GRANT SELECT ON sh.supplementary_demographics TO &DMUSER +/ +GRANT SELECT ON sh.countries TO &DMUSER +/ diff --git a/dmsvcdem.sql b/dmsvcdem.sql new file mode 100644 index 0000000..d64e207 --- /dev/null +++ b/dmsvcdem.sql @@ -0,0 +1,746 @@ +Rem +Rem $Header: dmsvcdem.sql 24-mar-2008.12:41:40 ramkrish Exp $ +Rem +Rem dmsvcdem.sql +Rem +Rem Copyright (c) 2003, 2008, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmsvcdem.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a classification model +Rem using the SVM algorithm +Rem and data in the SH (Sales History) schema in the RDBMS. +Rem +Rem NOTES +Rem This script demonstrates the use of the new Oracle10gR2 +Rem SQL functions for scoring models against new data, and +Rem the computation of various test metrics based on these +Rem new SQL functions. +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 03/06/08 - bug 6820838 - clas_weights instead of priors +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem jyarmus 10/18/06 - reduce precision of accuracy and AUC +Rem ktaylor 07/11/05 - minor edits to comments +Rem jcjeon 01/18/05 - add column format +Rem dmukhin 01/12/05 - bug 4053211: missing value treatment +Rem dmukhin 12/07/04 - 4053822 - lift and roc computation +Rem bmilenov 11/04/04 - Edit comments, add priors, remove costs +Rem ramkrish 09/27/04 - add data analysis and comments/cleanup +Rem bmilenov 05/18/04 - Change zscore to minmax normalization +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic and purchase data about a set of customers, predict +-- customer's response to an affinity card program using an SVM classifier. +-- + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +------- +-- DATA +------- +-- The data for this sample is composed from base tables in SH Schema +-- (See Sample Schema Documentation) and presented through these views: +-- mining_data_build_v (build data) +-- mining_data_test_v (test data) +-- mining_data_apply_v (apply data) +-- (See dmsh.sql for view definitions). +-- + +----------- +-- ANALYSIS +----------- + +-- For classification using SVM, perform the following on mining data. +-- +-- 1. Missing Value treatment for Predictors in Build, Test and Apply data +-- +-- "Missing Value" here implies "Missing at Random" values, that is, +-- there is no pattern to the missing data, a NULL value does not have a +-- special meaning, and there is no correlation either direct or indirect +-- with the target or other predictor values. +-- +-- Missing value imputation is recommended when the fraction of missing +-- at random values is high compared to the overall attribute value set. +-- +-- Contrast this with a "sparse" dataset - where a NULL value for +-- an attribute encodes a zero/non-present. Typical examples of domains +-- with sparse data are market basket and text mining. Missing value +-- imputation should not be used on sparse data. By default, SVM +-- interprets all NULL values for a given attribute as "sparse". +-- +-- Based on the business problem, one should designate the NULL value +-- for a given attribute to be "missing at random" or "sparse". For +-- example, a NULL value for AGE in demographic data can be missing +-- at random if omitting this information is a random occurrence. +-- In contrast, a shopping cart record with NULL values for certain +-- items is usually considered sparse - because a customer cannot +-- buy the entire inventory of items in a store. +-- +-- +-- +-- Here we are showing a simple approach to missing value treatment: +-- +-- 1.1. Compute the mean for numerical attributes, and mode for +-- categoricals. Store them away in a table for use with +-- Test and Apply data. +-- +-- 1.2. Replace the NULLs in the build, test, and apply data +-- with the computed mean (for numerical), mode (for categorical). +-- +-- +-- 2. Outlier Treatment for Predictors for Build data +-- +-- For SVM, we recommended that the data be normalized (individual +-- attributes need to be on a similar scale) to achieve faster +-- convergence of model builds and more accurate models. Large outliers +-- in individual attributes can result in sub-optimal normalization +-- output and sub-optimal models. Note that outlier treatment would be also +-- beneficial for algorithms that use equi-width-binning (e.g., O-Cluster) +-- since outliers in the data would produce sub-optimal bin boundaries. +-- +-- Here we winsorize the tail (see documentation on DBMS_DATA_MINING_TRANSFORM +-- for details) elements of the data as a preparatory step to normalization. +-- We recommend the use of winsorizing to reduce the influence of outliers on +-- the normalization computation. The normalization parameters are computed +-- on the winsorized data. Once the normalization parameters are computed, +-- they can be used directly on the original data. Winsorizing is not needed +-- at test and apply time - it only affects the specification of the +-- normalization parameters. +-- +-- 3. Normalize Predictors in Build, Test, and Apply data +-- +-- NOTE: that unlike Regression using SVM, the target attribute is +-- NOT normalized. + + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old build data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE svmc_sh_sample_miss_num'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE svmc_sh_sample_miss_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE svmc_sh_sample_clip'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE svmc_sh_sample_norm'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_build_miss'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_build'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW svmc_sh_sample_winsor'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW svmc_sh_sample_build_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +-- Cleanup old model with the same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('SVMC_SH_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- + +-- 1. Missing Value treatment for all Predictors and +-- 2. Outlier Treatment and +-- 3. Normalization are performed below. +-- NOTE: that unlike SVM regression, the classification target is NOT +-- normalized here. +-- NOTE: AGE is the only predictor with continuous values in this dataset. +-- +BEGIN + -- Perform missing value treatment for all predictors + -- create miss tables + DBMS_DATA_MINING_TRANSFORM.CREATE_MISS_NUM ( + miss_table_name => 'svmc_sh_sample_miss_num'); + DBMS_DATA_MINING_TRANSFORM.CREATE_MISS_CAT ( + miss_table_name => 'svmc_sh_sample_miss_cat'); + + -- populate miss tables + DBMS_DATA_MINING_TRANSFORM.INSERT_MISS_NUM_MEAN ( + miss_table_name => 'svmc_sh_sample_miss_num', + data_table_name => 'mining_data_build_v', + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'affinity_card', + 'cust_id')); + DBMS_DATA_MINING_TRANSFORM.INSERT_MISS_CAT_MODE ( + miss_table_name => 'svmc_sh_sample_miss_cat', + data_table_name => 'mining_data_build_v', + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'affinity_card', + 'cust_id')); + + -- xform input data to replace missing values + DBMS_DATA_MINING_TRANSFORM.XFORM_MISS_NUM( + miss_table_name => 'svmc_sh_sample_miss_num', + data_table_name => 'mining_data_build_v', + xform_view_name => 'mining_data_build_miss'); + DBMS_DATA_MINING_TRANSFORM.XFORM_MISS_CAT( + miss_table_name => 'svmc_sh_sample_miss_cat', + data_table_name => 'mining_data_build_miss', + xform_view_name => 'mining_data_build'); + + -- Perform outlier treatment for: AGE + -- create clip table + DBMS_DATA_MINING_TRANSFORM.CREATE_CLIP ( + clip_table_name => 'svmc_sh_sample_clip'); + + -- populate clip table + DBMS_DATA_MINING_TRANSFORM.INSERT_CLIP_WINSOR_TAIL ( + clip_table_name => 'svmc_sh_sample_clip', + data_table_name => 'mining_data_build', + tail_frac => 0.025, + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'affinity_card', + 'bookkeeping_application', + 'bulk_pack_diskettes', + 'cust_id', + 'flat_panel_monitor', + 'home_theater_package', + 'os_doc_set_kanji', + 'printer_supplies', + 'y_box_games')); + + -- xform input data to winsorized data + DBMS_DATA_MINING_TRANSFORM.XFORM_CLIP( + clip_table_name => 'svmc_sh_sample_clip', + data_table_name => 'mining_data_build', + xform_view_name => 'svmc_sh_sample_winsor'); + + -- normalize numerical attributes: AGE + -- create normalization table + DBMS_DATA_MINING_TRANSFORM.CREATE_NORM_LIN ( + norm_table_name => 'svmc_sh_sample_norm'); + + -- populate normalization table based on winsorized data + DBMS_DATA_MINING_TRANSFORM.INSERT_NORM_LIN_MINMAX ( + norm_table_name => 'svmc_sh_sample_norm', + data_table_name => 'svmc_sh_sample_winsor', + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'affinity_card', + 'bookkeeping_application', + 'bulk_pack_diskettes', + 'cust_id', + 'flat_panel_monitor', + 'home_theater_package', + 'os_doc_set_kanji', + 'printer_supplies', + 'y_box_games')); + + -- normalize the original data + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 'svmc_sh_sample_norm', + data_table_name => 'mining_data_build', + xform_view_name => 'svmc_sh_sample_build_prepared'); +END; +/ + +-- BUILD DATA PREPARATION OBJECTS: +-- ------------------------------ +-- 1. Numerical Missing Value Table: svmc_sh_sample_miss_num +-- 2. Categorical Missing Value Table: svmc_sh_sample_miss_cat +-- 3. Winsorize Clip Table: svmc_sh_sample_clip +-- 4. MinMax Normalization Table: svmc_sh_sample_norm +-- 5. Input (view) to CREATE_MODEL: svmc_sh_sample_build_prepared + +------------------ +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE svmc_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE svmc_sh_sample_class_wt'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- CREATE AND POPULATE A CLASS WEIGHTS TABLE +-- +-- A class weights table is used to influence the weighting of target classes +-- during model creation. For example, weights of (0.9, 0.1) for a binary +-- problem specify that an error in the first class has significantly +-- higher penalty that an error in the second class. Weights of (0.5, 0.5) +-- do not introduce a differential weight and would produce the same +-- model as when no weights are provided. +-- +CREATE TABLE svmc_sh_sample_class_wt ( + target_value NUMBER, + class_weight NUMBER); +INSERT INTO svmc_sh_sample_class_wt VALUES (0,0.35); +INSERT INTO svmc_sh_sample_class_wt VALUES (1,0.65); +COMMIT; + +-- CREATE AND POPULATE A SETTINGS TABLE +-- +set echo off +CREATE TABLE svmc_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on + +-- The default classification algorithm is Naive Bayes. So override +-- this choice to SVM using a settings table. +-- SVM chooses a kernel type automatically. This choice can be overriden +-- by the user. Linear kernel is preferred high dimensional data, and +-- Gaussian kernel for low dimensional data. Here we use linear kernel +-- to demonstrate the get_model_details_svm() API, which applies only for +-- models. +-- +BEGIN +-- Populate settings table + INSERT INTO svmc_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.algo_name, dbms_data_mining.algo_support_vector_machines); + INSERT INTO svmc_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.svms_kernel_function, dbms_data_mining.svms_linear); + INSERT INTO svmc_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.clas_weights_table_name, 'svmc_sh_sample_class_wt'); + -- Examples of other possible overrides are: + --(dbms_data_mining.svms_kernel_function, dbms_data_mining.svms_gaussian); + --(dbms_data_mining.svms_kernel_function, dbms_data_mining.svms_complexity_factor); + --(dbms_data_mining.svms_kernel_cache_size,100000000); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Build a new SVM Model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'SVMC_SH_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 'svmc_sh_sample_build_prepared', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + settings_table_name => 'svmc_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'SVMC_SH_CLAS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'SVMC_SH_CLAS_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- The coefficient indicates the relative influence of a given +-- (attribute, value) pair on the target value. A negative +-- coefficient value indicates a negative influence. +-- +-- NOTE: The FIRST row in the SVM model details output shows the +-- value for SVM bias under the COEFFICIENT column. +-- +SET line 120 +column class format a10 +column aname format a25 +column aval format a25 +column coeff format 9.99 + +WITH +mod_dtls AS ( +SELECT * + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_SVM('SVMC_SH_Clas_sample')) +), +model_details AS ( +SELECT D.class, A.attribute_name, A.attribute_value, A.coefficient + FROM mod_dtls D, + TABLE(D.attribute_set) A +ORDER BY D.class, ABS(A.coefficient) DESC +) +SELECT class, attribute_name aname, attribute_value aval, coefficient coeff + FROM model_details + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_test_miss'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_test'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW svmc_sh_sample_test_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------- +-- PREPARE TEST DATA +-- +-- If the data for model creation has been prepared, then the data used +-- for testing the model must be prepared in the same manner in order to +-- obtain meaningful results. +-- +-- 1. Missing Value treatment for all Predictors and +-- 2. Normalization +-- No outlier treatment will be performed during test and apply. The +-- normalization step is sufficient, since the normalization parameters +-- already capture the effects of outlier treatment done with build data. +-- +BEGIN + -- Xform Test data to replace missing values + DBMS_DATA_MINING_TRANSFORM.XFORM_MISS_NUM( + miss_table_name => 'svmc_sh_sample_miss_num', + data_table_name => 'mining_data_test_v', + xform_view_name => 'mining_data_test_miss'); + DBMS_DATA_MINING_TRANSFORM.XFORM_MISS_CAT( + miss_table_name => 'svmc_sh_sample_miss_cat', + data_table_name => 'mining_data_test_miss', + xform_view_name => 'mining_data_test'); + + -- Normalize Test data + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 'svmc_sh_sample_norm', + data_table_name => 'mining_data_test', + xform_view_name => 'svmc_sh_sample_test_prepared'); +END; +/ + +-- Cost matrix - not used here +-- It is possible to use a cost matrix on the apply results (see Naive +-- Bayes demo). However, for SVM we recommend that any known costs +-- be provided to the algorithm during build via the prior mechanism. +-- See discussion above on class weights table usage with SVM. +-- + +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- +-- The queries shown below demonstrate the use of new SQL data mining functions +-- along with analytic functions to compute various test metrics. In these +-- queries: +-- +-- Modelname: svmc_sh_clas_sample +-- # of Lift Quantiles: 10 +-- Target attribute: affinity_card +-- Positive target value: 1 +-- (Change these as appropriate for a different example) + +-- Compute CONFUSION MATRIX +-- +-- This query demonstates how to generate a confusion matrix using the new +-- SQL prediction functions for scoring. The returned columns match the +-- schema of the table generated by COMPUTE_CONFUSION_MATRIX procedure. +-- +SELECT affinity_card AS actual_target_value, + PREDICTION(svmc_sh_clas_sample USING *) AS predicted_target_value, + COUNT(*) AS value + FROM svmc_sh_sample_test_prepared + GROUP BY affinity_card, PREDICTION(svmc_sh_clas_sample USING *) + ORDER BY 1, 2; + +-- Compute ACCURACY +-- +column accuracy format 9.99 + +SELECT SUM(correct)/COUNT(*) AS accuracy + FROM (SELECT DECODE(affinity_card, + PREDICTION(svmc_sh_clas_sample USING *), 1, 0) AS correct + FROM svmc_sh_sample_test_prepared); + +-- Compute CUMULATIVE LIFT, GAIN Charts. +-- +-- The cumulative gain chart is a popular version of the lift chart, and +-- it maps cumulative gain (Y axis) against the cumulative records (X axis). +-- +-- The cumulative lift chart is another popular representation of lift, and +-- it maps cumulative lift (Y axis) against the cumulative records (X axis). +-- +-- The query also returns the probability associated with each quantile, so +-- that when the cut-off point for Lift is selected, you can correlate it +-- with a probability value (say P_cutoff). You can then use this value of +-- P_cutoff in a prediction query as follows: +-- +-- SELECT * +-- FROM records_to_be_scored +-- WHERE PREDICTION_PROBABILITY(svmc_sh_clas_sample, 1 USING *) > P_cutoff; +-- +-- In the query below +-- +-- q_num - Quantile Number +-- pos_cnt - # of records that predict the positive target +-- pos_prob - the probability associated with predicting a positive target +-- value for a given new record +-- cume_recs - % Cumulative Records upto quantile +-- cume_gain - % Cumulative Gain +-- cume_lift - Cumulative Lift +-- +WITH +pos_prob_and_counts AS ( +SELECT PREDICTION_PROBABILITY(svmc_sh_clas_sample, 1 USING *) pos_prob, + -- hit count for positive target value + DECODE(affinity_card, 1, 1, 0) pos_cnt + FROM svmc_sh_sample_test_prepared +), +qtile_and_smear AS ( +SELECT NTILE(10) OVER (ORDER BY pos_prob DESC) q_num, + pos_prob, + -- smear the counts across records with the same probability to + -- eliminate potential biased distribution across qtl boundaries + AVG(pos_cnt) OVER (PARTITION BY pos_prob) pos_cnt + FROM pos_prob_and_counts +), +cume_and_total_counts AS ( +SELECT q_num, + -- inner sum for counts within q_num groups, + -- outer sum for cume counts + MIN(pos_prob) pos_prob, + SUM(COUNT(*)) OVER (ORDER BY q_num) cume_recs, + SUM(SUM(pos_cnt)) OVER (ORDER BY q_num) cume_pos_cnt, + SUM(COUNT(*)) OVER () total_recs, + SUM(SUM(pos_cnt)) OVER () total_pos_cnt + FROM qtile_and_smear + GROUP BY q_num +) +SELECT pos_prob, + 100*(cume_recs/total_recs) cume_recs, + 100*(cume_pos_cnt/total_pos_cnt) cume_gain, + (cume_pos_cnt/total_pos_cnt)/(cume_recs/total_recs) cume_lift + FROM cume_and_total_counts + ORDER BY pos_prob DESC; + +-- Compute ROC CURVE +-- +-- This can be used to find the operating point for classification. +-- +-- The ROC curve plots true positive fraction - TPF (Y axis) against +-- false positive fraction - FPF (X axis). Note that the query picks +-- only the corner points (top tpf switch points for a given fpf) and +-- the last point. It should be noted that the query does not generate +-- the first point, i.e (tpf, fpf) = (0, 0). All of the remaining points +-- are computed, but are then filtered based on the criterion above. For +-- example, the query picks points a,b,c,d and not points o,e,f,g,h,i,j. +-- +-- The Area Under the Curve (next query) is computed using the trapezoid +-- rule applied to all tpf change points (i.e. summing up the areas of +-- the trapezoids formed by the points for each segment along the X axis; +-- (recall that trapezoid Area = 0.5h (A+B); h=> hieght, A, B are sides). +-- In the example, this means the curve covering the area would trace +-- points o,e,a,g,b,c,d. +-- +-- | +-- | .c .j .d +-- | .b .h .i +-- | .g +-- .a .f +-- .e +-- .__.__.__.__.__.__ +-- o +-- +column prob format 9.9999 +column fpf format 9.9999 +column tpf format 9.9999 + +WITH +pos_prob_and_counts AS ( +SELECT PREDICTION_PROBABILITY(svmc_sh_clas_sample, 1 USING *) pos_prob, + -- hit count for positive target value + DECODE(affinity_card, 1, 1, 0) pos_cnt + FROM svmc_sh_sample_test_prepared +), +cume_and_total_counts AS ( +SELECT pos_prob, + pos_cnt, + SUM(pos_cnt) OVER (ORDER BY pos_prob DESC) cume_pos_cnt, + SUM(pos_cnt) OVER () tot_pos_cnt, + SUM(1 - pos_cnt) OVER (ORDER BY pos_prob DESC) cume_neg_cnt, + SUM(1 - pos_cnt) OVER () tot_neg_cnt + FROM pos_prob_and_counts +), +roc_corners AS ( +SELECT MIN(pos_prob) pos_prob, + MAX(cume_pos_cnt) cume_pos_cnt, cume_neg_cnt, + MAX(tot_pos_cnt) tot_pos_cnt, MAX(tot_neg_cnt) tot_neg_cnt + FROM cume_and_total_counts + WHERE pos_cnt = 1 -- tpf switch points + OR (cume_pos_cnt = tot_pos_cnt AND -- top-right point + cume_neg_cnt = tot_neg_cnt) + GROUP BY cume_neg_cnt +) +SELECT pos_prob prob, + cume_pos_cnt/tot_pos_cnt tpf, + cume_neg_cnt/tot_neg_cnt fpf, + cume_pos_cnt tp, + tot_pos_cnt - cume_pos_cnt fn, + cume_neg_cnt fp, + tot_neg_cnt - cume_neg_cnt tn + FROM roc_corners + ORDER BY fpf; + +-- Compute AUC (Area Under the roc Curve) +-- +-- See notes on ROC Curve and AUC computation above +-- +column auc format 9.99 + +WITH +pos_prob_and_counts AS ( +SELECT PREDICTION_PROBABILITY(svmc_sh_clas_sample, 1 USING *) pos_prob, + DECODE(affinity_card, 1, 1, 0) pos_cnt + FROM svmc_sh_sample_test_prepared +), +tpf_fpf AS ( +SELECT pos_cnt, + SUM(pos_cnt) OVER (ORDER BY pos_prob DESC) / + SUM(pos_cnt) OVER () tpf, + SUM(1 - pos_cnt) OVER (ORDER BY pos_prob DESC) / + SUM(1 - pos_cnt) OVER () fpf + FROM pos_prob_and_counts +), +trapezoid_areas AS ( +SELECT 0.5 * (fpf - LAG(fpf, 1, 0) OVER (ORDER BY fpf, tpf)) * + (tpf + LAG(tpf, 1, 0) OVER (ORDER BY fpf, tpf)) area + FROM tpf_fpf + WHERE pos_cnt = 1 + OR (tpf = 1 AND fpf = 1) +) +SELECT SUM(area) auc + FROM trapezoid_areas; + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old scoring data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_apply_miss'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_apply'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW svmc_sh_sample_apply_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +----------------------- +-- PREPARE SCORING DATA +-- +-- If the data for model creation has been prepared, then the data +-- to be scored using the model must be prepared in the same manner +-- in order to obtain meaningful results. +-- +-- 1. Missing Value treatment for all Predictors and +-- 2. Normalization +-- No outlier treatment will be performed during test and apply. The +-- normalization step is sufficient, since the normalization parameters +-- already capture the effects of outlier treatment done with build data. +-- +BEGIN + -- Xform Test data to replace missing values + DBMS_DATA_MINING_TRANSFORM.XFORM_MISS_NUM( + miss_table_name => 'svmc_sh_sample_miss_num', + data_table_name => 'mining_data_apply_v', + xform_view_name => 'mining_data_apply_miss'); + DBMS_DATA_MINING_TRANSFORM.XFORM_MISS_CAT( + miss_table_name => 'svmc_sh_sample_miss_cat', + data_table_name => 'mining_data_apply_miss', + xform_view_name => 'mining_data_apply'); + + -- Normalize the data to be scored + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 'svmc_sh_sample_norm', + data_table_name => 'mining_data_apply', + xform_view_name => 'svmc_sh_sample_apply_prepared'); +END; +/ + +------------------------------------------------- +-- SCORE NEW DATA USING SQL DATA MINING FUNCTIONS +-- +-- Note that APPLY results do not need to be reverse transformed, as done +-- in the case of model details. This is because class values of a +-- classification target were not (required to be) binned or normalized. +-- +------------------ +-- BUSINESS CASE 1 +-- Find the 10 customers who live in Italy that are most likely +-- to use an affinity card. +-- +SELECT cust_id + FROM (SELECT cust_id + FROM svmc_sh_sample_apply_prepared + WHERE country_name = 'Italy' + ORDER BY PREDICTION_PROBABILITY(svmc_sh_clas_sample, 1 USING *) DESC, 1) +WHERE ROWNUM < 11; + +------------------ +-- BUSINESS CASE 2 +-- Find the average age of customers who are likely to use an +-- affinity card. Break out the results by gender. +-- +SELECT cust_gender, + COUNT(*) AS cnt, + ROUND(AVG(age)) AS avg_age + FROM svmc_sh_sample_apply_prepared + WHERE PREDICTION(svmc_sh_clas_sample USING *) = 1 +GROUP BY cust_gender +ORDER BY cust_gender; + +------------------ +-- BUSINESS CASE 3 +-- List ten customers (ordered by their id) along with their likelihood to +-- use or reject the affinity card (Note: while this example has a +-- binary target, such a query is useful in multi-class classification - +-- Low, Med, High for example). +-- +SELECT T.cust_id, S.prediction, S.probability + FROM (SELECT cust_id, + PREDICTION_SET(svmc_sh_clas_sample USING *) pset + FROM svmc_sh_sample_apply_prepared + WHERE cust_id < 100011) T, + TABLE(T.pset) S +ORDER BY cust_id, S.prediction; + +------------------ +-- BUSINESS CASE 4 +-- Find customers whose profession is Tech Support +-- with > 75% likelihood of using the affinity card +-- +SELECT cust_id + FROM svmc_sh_sample_apply_prepared + WHERE PREDICTION_PROBABILITY(svmc_sh_clas_sample, 1 USING *) > 0.75 + AND occupation = 'TechSup' +ORDER BY cust_id; + diff --git a/dmsvcdemo.java b/dmsvcdemo.java new file mode 100644 index 0000000..4ec2c4c --- /dev/null +++ b/dmsvcdemo.java @@ -0,0 +1,770 @@ +// Copyright (c) 2004, 2008, Oracle. All rights reserved. +// File: dmsvcdemo.java +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.Statement; + +import java.text.DecimalFormat; +import java.text.MessageFormat; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.algorithm.svm.KernelFunction; +import javax.datamining.algorithm.svm.classification.SVMClassificationSettings; +import javax.datamining.algorithm.svm.classification.SVMClassificationSettingsFactory; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.CategorySet; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.modeldetail.svm.SVMClassificationModelDetail; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.classification.ClassificationApplySettings; +import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.supervised.classification.ClassificationTestMetrics; +import javax.datamining.supervised.classification.ClassificationTestTask; +import javax.datamining.supervised.classification.ClassificationTestTaskFactory; +import javax.datamining.supervised.classification.ConfusionMatrix; +import javax.datamining.supervised.classification.Lift; +import javax.datamining.supervised.classification.ReceiverOperatingCharacterics; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; + +import oracle.dmt.jdm.algorithm.svm.classification.OraSVMClassificationSettings; +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.modeldetail.svm.OraSVMClassificationModelDetail; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.supervised.classification.OraClassificationModel; +import oracle.dmt.jdm.supervised.classification.OraLift; + +/** + * This demo program describes how to use the Oracle Data Mining (ODM) Java API + * to solve a classification problem using Support Vector Machines (SVM) + * algorithm. + * ------------------------------------------------------------------------------ + * PROBLEM DEFINITION + * ------------------------------------------------------------------------------ + * How to predict whether a customer responds or not to the new affinity card + * program using a classifier based on SVM algorithm? + * ------------------------------------------------------------------------------ + * DATA DESCRIPTION + * ------------------------------------------------------------------------------ + * Data for this demo is composed from base tables in the Sales History (SH) + * Schema. The SH schema is an Oracle Database Sample Schema that has the customer + * demographics, purchasing, and response details for the previous affinity card + * programs. Data exploration and preparing the data is a common step before + * doing data mining. Here in this demo, the following views are created in the user + * schema using CUSTOMERS, COUNTRIES, and SUPPLIMENTARY_DEMOGRAPHICS tables. + * + * MINING_DATA_BUILD_V: + * This view collects the previous customers' demographics, purchasing, and affinity + * card response details for building the model. + * + * MINING_DATA_TEST_V: + * This view collects the previous customers' demographics, purchasing, and affinity + * card response details for testing the model. + * + * MINING_DATA_APPLY_V: + * This view collects the prospective customers' demographics and purchasing + * details for predicting response for the new affinity card program. + * + * ------------------------------------------------------------------------------ + * DATA MINING PROCESS + * ------------------------------------------------------------------------------ + * Build Model: + * Mining Model is the prime object in data mining. The buildModel() method + * illustrates how to build a classification model using SVM algorithm. + * + * Test Model: + * Classification models' performance can be evaluated by computing test + * metrics like accuracy, confusion matrix, lift and ROC. The testModel() or + * computeTestMetrics() method illustrates how to perform a test operation to + * compute various metrics. + * + * Apply Model: + * Predicting the target attribute values is the prime function of + * classification models. The applyModel() method illustrates how to + * predict the customer response for an affinity card program. + * ------------------------------------------------------------------------------ + * EXECUTING DEMO PROGRAM + * ------------------------------------------------------------------------------ + * Refer to Oracle Data Mining Administrator's Guide + * for guidelines for executing this demo program. + */ + +public class dmsvcdemo extends Object { + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClassificationSettingsFactory m_clasFactory; + private static SVMClassificationSettingsFactory m_svmcFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClassificationTestTaskFactory m_testFactory; + private static ClassificationApplySettingsFactory m_applySettingsFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + private static boolean displayModelDeatils = false;//By default it is set to false. To view the details of the model this flag can be enabled + + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmsvcdemo "); + System.out.println(" or: java dmsvcdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build a model with supplied prior probability + buildModel(); + // 5. Test model - To compute accuracy and confusion matrix, lift result + // and ROC for the model. + testModel(); + // 6. Apply the model + applyModel(); + // 7. Start execution of the first task in the sequnece + m_dmeConn.execute("svmcBuildTask_jdm"); + // 8. Monitor and display results (if any) + monitorTaskExecutionProcess(); + + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { } // Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_clasFactory = (ClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationSettings"); + m_svmcFactory = (SVMClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.algorithm.svm.classification.SVMClassificationSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_testFactory = (ClassificationTestTaskFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationTestTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = (ClassificationApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationApplySettings"); + } + + /** + * This method illustrates how to build mining model using + * MINING_DATA_BUILD_V dataset and classification settings with + * SVM algorithm. + * + * By default SVM algorithm chooses an kernel type automatically. This + * choice can be overriden by the user. Linear kernel is preferred high + * dimensional data, and Gaussian kernel for low dimensional data. Here we use + * linear kernel to demonstrate the getModelDetail() API, which applies only + * for models. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("svmcBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // Create SVMC algorithm settings + SVMClassificationSettings svmcAlgo = m_svmcFactory.create(); + svmcAlgo.setKernelFunction(KernelFunction.kLinear); + // Examples settings are: + // svmcAlgo.setKernelFunction(KernelFunction.kGaussian); + // svmcAlgo.setComplexityFactor(0.01f); + // svmcAlgo.setTolerance(0.01f); + // + //Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(svmcAlgo); + buildSettings.setTargetAttributeName("AFFINITY_CARD"); + // + // Set target prior probabilities. + // + // A priors table is used to influence the weighting of target classes + // during model creation. SVM's usage of priors is different from the + // priors interpretation in probabilistic models. In probabilistic models, + // priors can be used to correct for biased sampling procedures. Instead, + // in SVM priors act as a weight vector that biases optimization and favors + // one class over the other. For example, priors of (0.9, 0.1) for a binary + // problem specify that an error in the first class has significantly + // higher penalty that an error in the second class. Priors of (0.5, 0.5) + // do not introduce a differential weight and would produce the same + // model as when no priors are provided. + Map priorMap = new HashMap(); + priorMap.put(new Double(0), new Double(0.35)); + priorMap.put(new Double(1), new Double(0.65)); + buildSettings.setPriorProbabilitiesMap("AFFINITY_CARD", priorMap); + //Set auto data preparation on + ((OraBuildSettings)buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject("svmcBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "svmcBuildData_jdm", //Build data specification + "svmcBuildSettings_jdm", //Mining function settings name + "svmcModel_jdm" //Mining model name + ); + buildTask.setDescription("svmcBuildTask_jdm"); + saveTask(buildTask, "svmcBuildTask_jdm", null); + } + + + /** + * This method illustrates how to compute test metrics using + * MINING_DATA_TEST_V dataset and ClassificationTestTask. + * @exception JDMException if model test failed + */ + public static void testModel() throws JDMException + { + // 1. Do the apply on test data to create an apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_TEST_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "svmcTestData_jdm", applyData, true ); + + // 5. Create a ClassificationTestTask + ClassificationTestTask testTask = m_testFactory.create( + "svmcTestData_jdm", "svmcModel_jdm", "svcTestMetrics_jdm" ); + testTask.setPositiveTargetValue(new Integer(1)); + testTask.setNumberOfLiftQuantiles(10); + // 6. Store & execute the task + saveTask(testTask, "svmcTestTask_jdm", "svmcBuildTask_jdm"); + } + + /** + * This method illustrates how to apply the mining model on the + * MINING_DATA_APPLY_V dataset to predict customer + * response. After completion of the task, the apply output table with the + * predicted results is created at the user specified location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_APPLY_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "svmcApplyData_jdm", applyData, true ); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "svmcApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "svmcApplyData_jdm", "svmcModel_jdm", + "svmcApplySettings_jdm", "SVMC_APPLY_OUTPUT_JDM"); + saveTask(applyTask, "svmcApplyTask_jdm", "svmcBuildTask_jdm" ); + } + + /** + * This method saves the given task with the specified task name and task + * dependency (parent task) in the DME. + * + * @param taskObj task object + * @param taskName name of the task + * @param parentTaskName name of the parent task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static void saveTask(Task taskObj, String taskName, + String parentTaskName) + throws JDMException + { + if (parentTaskName != null) + ((OraTask) taskObj).addDependency(parentTaskName); //Since OJDM 11.1 + ((OraTask) taskObj).overwriteOutput(true); //Since OJDM 11.1 + m_dmeConn.saveObject(taskName, taskObj, true); + } + + /** + * This method monitor task execution initiated by the first task + * in the sequence of dependent tasks. In addition, this method displays + * task output results (if any). + * @throws JDMException + */ + public static void monitorTaskExecutionProcess() + throws JDMException + { + //BuildTask + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of svmcBuildTask_jdm. "); + ExecutionStatus buildTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("svmcBuildTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(buildTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + // 3. Restore the model from the data mining server + ClassificationModel model = + (ClassificationModel) m_dmeConn.retrieveObject("svmcModel_jdm", + NamedObject.model); + // 4. Explore the details of the restored model + // Display model build settings + ClassificationSettings retrievedBuildSettings = + (ClassificationSettings) model.getBuildSettings(); + if (retrievedBuildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, + "svmcBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + if(displayModelDeatils) + displaySVMCModelDetails((Model)model); + + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model ---"); + System.out.println("---------------------------------------------------"); + + //If model build is successful, then do testData ApplyTask + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of svmcTestTask_jdm. "); + ExecutionStatus testTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("svmcTestTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(testTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + // Restore & display test metrics + ClassificationTestMetrics testMetrics = + (ClassificationTestMetrics) m_dmeConn.retrieveObject("svcTestMetrics_jdm", + NamedObject.testMetrics); + // Display classification test metrics + displayTestMetricDetails(testMetrics); + } + else + { + System.out.println("It is at state:" + + testTaskCompletionStatus.getState().name() + + ((testTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + testTaskCompletionStatus.getDescription())); + } + //ApplyTask(s) + //Waiting for apply task to complete + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + + ExecutionStatus applyTaskStatus = + m_dmeConn.getLastExecutionHandle("svmcApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + if (ExecutionState.success.equals(applyTaskStatus.getState())) + { + // Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + displayTable("SVMC_APPLY_OUTPUT_JDM", "where ROWNUM < 11", + "order by CUST_ID"); + } + else + { + System.out.println("svmcApplyTask_jdm is at state:" + + applyTaskStatus.getState().name() + + ((applyTaskStatus.getDescription() == null)? + "": + "State Description:" + applyTaskStatus.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + buildTaskCompletionStatus.getState().name() + + ((buildTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + buildTaskCompletionStatus.getDescription())); + } + + } + + private static void displayBuildSettings( + ClassificationSettings clasSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " model build settings object:"); + String objName = clasSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = clasSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = clasSettings.getCreationDate(); + String creator = clasSettings.getCreatorInfo(); + String targetAttrName = clasSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = clasSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: clasSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = clasSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: clasSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + try { + Map map = clasSettings.getPriorProbabilitiesMap(targetAttrName); + if(map != null) System.out.println("Priors Map: " + map.toString()); + } catch(Exception jdmExp) + { + System.out.println("Failure: clasSettings.getPriorProbabilitiesMap(targetAttrName)throws exception"); + jdmExp.printStackTrace(); + } + // List of SVM algorithm settings availabe in linear kernel + KernelFunction kernelFunction = ((OraSVMClassificationSettings)algoSettings).getKernelFunction(); + System.out.println("Kernel Function: " + kernelFunction.name()); + double doubleValue = ((OraSVMClassificationSettings)algoSettings).getComplexityFactor(); + System.out.println("Complexity Factor: " + m_df.format(doubleValue)); + doubleValue = ((OraSVMClassificationSettings)algoSettings).getTolerance(); + System.out.println("Tolerance: " + m_df.format(doubleValue)); + boolean enable = ((OraSVMClassificationSettings)algoSettings).getActiveLearning(); + System.out.println("Is Active Learning enabled? " + enable); + } + + /** + * This method displayes SVMC model signature. + * + * @param model model object + * @exception JDMException if failed to retrieve model signature + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + /** + * This method displayes SVMC model details. The coefficient indicates the + * relative influence of a given (attribute, value) pair on the target value. + * A negative coefficient value indicates a negative influence. + * + * @param svmcModelDetails svm classification model details object + * @exception JDMException if failed to retrieve model details + */ + public static void displaySVMCModelDetails( + Model model) throws JDMException + { + // Obtains model details + SVMClassificationModelDetail svmcModelDetails = + (SVMClassificationModelDetail)model.getModelDetail(); + // Is linear model? + System.out.println("Is linear model? " + svmcModelDetails.isLinearSVMModel() ); + // Available targets + CategorySet targetSet = ((OraClassificationModel)model).getTargetCategorySet(); + Object[] targets = targetSet.getValues(); + // Attribute coefficient value will be available if it is a linear model + if (svmcModelDetails.isLinearSVMModel()) + { + System.out.println("Model Deatils: ( Target Value, Attribute Name, Attribute Value, Coefficient)"); + MessageFormat mfDetails = new MessageFormat(" ( {0}, {1}, {2}, {3} )"); + String[] vals = new String[4]; + for (int row =0; row < targets.length; row++) + { + // Print bias of the current target value by invoking getBias method. + vals[0] =(String) targets[row].toString(); + vals[1] = ""; + vals[2] = ""; + vals[3] = m_df.format(svmcModelDetails.getBias(targets[row])) + " (Bias)"; + System.out.println( mfDetails.format(vals) ); + //Get the signature attributes + ModelSignature modelSignature = model.getSignature(); + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + // Print all attribute coefficients -- The FIRST row in the SVM model + // details output shows the value for SVM bias under the COEFFICIENT + // column. + Map attrCoefficientMap = ((OraSVMClassificationModelDetail)svmcModelDetails).getCoefficients(targets[row],attr.getName()); + Object[] attrVals = attrCoefficientMap.keySet().toArray(); + if(attrVals != null) { + for(int iAttr=0; iAttr < attrVals.length; iAttr++) + { + vals[1] = attr.getName(); + vals[2] = ""; + if(attrVals[iAttr] != null) + vals[2] = attrVals[iAttr].toString(); + vals[3] = ""; + Number coefficient = (Number)attrCoefficientMap.get(attrVals[iAttr]); + if(coefficient != null) + vals[3] = m_df.format(coefficient); + System.out.println( mfDetails.format(vals) ); + } + } + } + } + } + } + + /** + * Display classification test metrics object + * + * @param testMetrics classification test metrics object + * @exception JDMException if failed to retrieve test metric details + */ + public static void displayTestMetricDetails( + ClassificationTestMetrics testMetrics) throws JDMException + { + // Retrieve Oracle SVMC model test metrics deatils extensions + // Test Metrics Name + System.out.println("Test Metrics Name = " + testMetrics.getName()); + // Model Name + System.out.println("Model Name = " + testMetrics.getModelName()); + // Test Data Name + System.out.println("Test Data Name = " + testMetrics.getTestDataName()); + // Accuracy + System.out.println("Accuracy = " + m_df.format(testMetrics.getAccuracy().doubleValue())); + // Confusion Matrix + ConfusionMatrix confusionMatrix = testMetrics.getConfusionMatrix(); + Collection categories = confusionMatrix.getCategories(); + Iterator xIterator = categories.iterator(); + System.out.println("Confusion Matrix: Accuracy = " + m_df.format(confusionMatrix.getAccuracy())); + System.out.println("Confusion Matrix: Error = " + m_df.format(confusionMatrix.getError())); + System.out.println("Confusion Matrix:( Actual, Prection, Value )"); + MessageFormat mf = new MessageFormat(" ( {0}, {1}, {2} )"); + String[] vals = new String[3]; + while(xIterator.hasNext()) + { + Object actual = xIterator.next(); + vals[0] = actual.toString(); + Iterator yIterator = categories.iterator(); + while(yIterator.hasNext()) + { + Object predicted = yIterator.next(); + vals[1] = predicted.toString(); + long number = confusionMatrix.getNumberOfPredictions(actual, predicted); + vals[2] = Long.toString(number); + System.out.println(mf.format(vals)); + } + } + // Lift + Lift lift = testMetrics.getLift(); + System.out.println("Lift Details:"); + System.out.println("Lift: Target Attribute Name = " + lift.getTargetAttributeName()); + System.out.println("Lift: Positive Target Value = " + lift.getPositiveTargetValue()); + System.out.println("Lift: Total Cases = " + lift.getTotalCases()); + System.out.println("Lift: Total Positive Cases = " + lift.getTotalPositiveCases()); + int numberOfQuantiles = lift.getNumberOfQuantiles(); + System.out.println("Lift: Number Of Quantiles = " + numberOfQuantiles); + System.out.println("Lift: ( QUANTILE_NUMBER, TOTAL_CASES, QUANTILE_PERCENT_SIZE, POSITIVE_CASES, NEGATIVE_CASES, PROBABILITY_THRESHOLD, LIFT, CUMULATIVE_LIFT, GAIN, CUMULATIVE_GAIN, TARGET_DENSITY, CUMULATIVE_TARGET_DENSITY)"); + MessageFormat mfLift = + new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10} )"); + double[] totalCasesPerQuantile = ((OraLift)lift).getCases();//Total cases per quantile + double[] quantilePercentageSize = ((OraLift)lift).getPercentageSize();//Quantile pecentage size + double[] positiveCasesPerQuantile = ((OraLift)lift).getNumberOfPositiveCases();//Positive target cases per quantile + double[] negativeCasesPerQuantile = ((OraLift)lift).getNumberOfNegativeCases();//Negative target cases per quantile + double[] probabilityOrCostThresholdPerQuantile = ((OraLift)lift).getProbabilityOrCostThreshold();//Probability or cost threshold per quantile + double[] liftPerQuantile = ((OraLift)lift).getLift();//Lift values for all quantiles + double[] targetDensityPerQuantile = ((OraLift)lift).getTargetDensity();//Target densities per quantile + + double[] cumulativeLift = ((OraLift)lift).getCumulativeLift(); + double[] cumulativeGain = ((OraLift)lift).getCumulativeGain(); + double[] cumulativeTargetDensity = ((OraLift)lift).getCumulativeTargetDensity(); + + + + String[] messageParams = new String[11]; + + for (int iQuantile = 0; iQuantile < numberOfQuantiles; iQuantile++) + { + //Assign message parameters + messageParams[0] = Integer.toString(iQuantile+1); //QUANTILE_NUMBER + messageParams[1] = m_df.format(totalCasesPerQuantile[iQuantile]); //TOTAL_CASES + messageParams[2] = m_df.format(quantilePercentageSize[iQuantile]);//QUANTILE_PERCENT_SIZE + messageParams[3] = m_df.format(positiveCasesPerQuantile[iQuantile]); //POSITIVE_CASES + messageParams[4] = m_df.format(negativeCasesPerQuantile[iQuantile]); //NEGATIVE_CASES + messageParams[5] = m_df.format(probabilityOrCostThresholdPerQuantile[iQuantile]); //PROBABILITY_THRESHOLD + messageParams[6] = m_df.format(liftPerQuantile[iQuantile]); //LIFT + messageParams[7] = m_df.format(cumulativeLift[iQuantile]); //CUMULATIVE_LIFT + messageParams[8] = m_df.format(cumulativeGain[iQuantile]); //CUMULATIVE_GAIN + messageParams[9] = m_df.format(targetDensityPerQuantile[iQuantile]); //TARGET_DENSITY + messageParams[10] = m_df.format(cumulativeTargetDensity[iQuantile]); //CUMULATIVE_TARGET_DENSITY + System.out.println(mfLift.format(messageParams)); + } + // ROC + ReceiverOperatingCharacterics roc = testMetrics.getROC(); + System.out.println("ROC Details:"); + System.out.println("ROC: Area Under Curve = " + m_df.format(roc.getAreaUnderCurve())); + int nROCThresh = roc.getNumberOfThresholdCandidates(); + System.out.println("ROC: Number Of Threshold Candidates = " + nROCThresh); + System.out.println("ROC: ( INDEX, PROBABILITY, TRUE_POSITIVES, FALSE_NEGATIVES, FALSE_POSITIVES, TRUE_NEGATIVES, TRUE_POSITIVE_FRACTION, FALSE_POSITIVE_FRACTION )"); + MessageFormat mfROC = new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7} )"); + String[] rocVals = new String[8]; + for(int iROC=1; iROC <= nROCThresh; iROC++) + { + rocVals[0] = Integer.toString(iROC); //INDEX + rocVals[1] = m_df.format(roc.getProbabilityThreshold(iROC));//PROBABILITY + rocVals[2] = Long.toString(roc.getPositives(iROC, true));//TRUE_POSITIVES + rocVals[3] = Long.toString(roc.getNegatives(iROC, false));//FALSE_NEGATIVES + rocVals[4] = Long.toString(roc.getPositives(iROC, false));//FALSE_POSITIVES + rocVals[5] = Long.toString(roc.getNegatives(iROC, true));//TRUE_NEGATIVES + rocVals[6] = m_df.format(roc.getHitRate(iROC));//TRUE_POSITIVE_FRACTION + rocVals[7] = m_df.format(roc.getFalseAlarmRate(iROC));//FALSE_POSITIVE_FRACTION + System.out.println(mfROC.format(rocVals)); + } + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while(rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + private static void clean() + { + //Drop the model + try { + m_dmeConn.removeObject("svmcModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + + } +} + diff --git a/dmsvodem.sql b/dmsvodem.sql new file mode 100644 index 0000000..3c16d2e --- /dev/null +++ b/dmsvodem.sql @@ -0,0 +1,264 @@ +Rem +Rem $Header: dmsvodem.sql 25-oct-2007.11:34:45 ramkrish Exp $ +Rem +Rem dmsvodem.sql +Rem +Rem Copyright (c) 2004, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmsvodem.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates an anomaly detection model +Rem for data analysis and outlier identification using the +Rem one-class SVM algorithm +Rem and data in the SH (Sales History)schema in the RDBMS. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem ktaylor 07/11/05 - minor edits to comments +Rem jcjeon 01/18/05 - add column format +Rem bmilenov 10/28/04 - bmilenov_oneclass_demo +Rem bmilenov 10/25/04 - Remove dbms_output statements +Rem bmilenov 10/22/04 - Comment revision +Rem bmilenov 10/20/04 - Created +Rem + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographics about a set of customers that are known to have +-- an affinity card, 1) find the most atypical members of this group +-- (outlier identification), 2) discover the common demographic +-- characteristics of the most typical customers with affinity card, +-- and 3) compute how typical a given new/hypothetical customer is. +-- +------- +-- DATA +------- +-- The data for this sample is composed from base tables in the SH schema +-- (See Sample Schema Documentation) and presented through a view: +-- mining_data_one_class_v +-- (See dmsh.sql for view definition). +-- +-- + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old build data preparation objects, if any +BEGIN + EXECUTE IMMEDIATE 'DROP TABLE svmo_sh_sample_norm'; + EXECUTE IMMEDIATE 'DROP VIEW svmo_sh_sample_prepared'; +EXCEPTION WHEN OTHERS THEN + NULL; +END; +/ +-- Cleanup old model with the same name (if any) +BEGIN DBMS_DATA_MINING.DROP_MODEL('SVMO_SH_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE DATA +-- + +-- 1. Missing Value treatment for all Predictors +-- This is an optional step. Missing value imputation is recommended +-- when the fraction of missing at random values is high. Sparse data +-- representation where missing values encode 0 (non-present) should +-- be left as it is. +-- For numerical attributes, if z-score normalization is applied, the +-- missing value treatment step can be skipped. +-- For missing value treatment sample code see dmsvcdem.sql. +-- +-- 2. Outlier Treatment +-- This is an optional step. Large outlier values in individual attributes +-- can result in sub-optimal normalization ouput and sub-optimal models. +-- For outlier treatment sample code see dmsvcdem.sql. +-- +-- 3. Normalization +-- Normalization brings all numeric attributes on a similar scale. Unless +-- there are reasons for weighting individual attributes differently, +-- this step is strongly recommended. In the presence of numeric only +-- attributes either min_max or z-score normalization can be used. If the +-- dataset has both numeric and categorical attributes, min_max +-- normalization is preferred. +-- +BEGIN + -- Normalize numerical attributes: AGE, YRS_RESIDENCE + -- CUST_ID is the record unique identifier and therefore excluded + -- from normalization + -- Create normalization specification + DBMS_DATA_MINING_TRANSFORM.CREATE_NORM_LIN ( + norm_table_name => 'svmo_sh_sample_norm'); + + DBMS_DATA_MINING_TRANSFORM.INSERT_NORM_LIN_MINMAX ( + norm_table_name => 'svmo_sh_sample_norm', + data_table_name => 'mining_data_one_class_v', + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'cust_id')); + + -- Create the transformed view + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 'svmo_sh_sample_norm', + data_table_name => 'mining_data_one_class_v', + xform_view_name => 'svmo_sh_sample_prepared'); + +END; +/ + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table (if any) +BEGIN + EXECUTE IMMEDIATE 'DROP TABLE svmo_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN + NULL; +END; +/ + +-- CREATE AND POPULATE A SETTINGS TABLE +-- +set echo off +CREATE TABLE svmo_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on + +BEGIN + -- Populate settings table + -- SVM needs to be selected explicitly (default classifier: Naive Bayes) + + -- Examples of other possible overrides are: + -- select a different rate of outliers in the data (default 0.1) + -- (dbms_data_mining.svms_outlier_rate, ,0.05); + -- select a kernel type (default kernel: selected by the algorithm) + -- (dbms_data_mining.svms_kernel_function, dbms_data_mining.svms_linear); + -- (dbms_data_mining.svms_kernel_function, dbms_data_mining.svms_gaussian); + -- turn off active learning (enabled by default) + -- (dbms_data_mining.svms_active_learning, dbms_data_mining.svms_al_disable); + + INSERT INTO svmo_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.algo_name, dbms_data_mining.algo_support_vector_machines); +END; +/ + +--------------------- +-- CREATE A MODEL +-- +-- Build a new one-class SVM Model +-- Note the NULL sprecification for target column name +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'SVMO_SH_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 'svmo_sh_sample_prepared', + case_id_column_name => 'cust_id', + target_column_name => NULL, + settings_table_name => 'svmo_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'SVMO_SH_CLAS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +-- For sample code displaying SVM signature see dmsvcdem.sql. + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Model details are available only for SVM models with linear kernel. +-- For SVM model details sample code see dmsvcdem.sql. +-- + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- + +-- Depending on the business case, the model can be scored against the +-- build data (e.g, business cases 1 and 2) or against new, previously +-- unseen data (e.g., business case 3). New apply data needs to undergo +-- the same transformations as the build data (see business case 3). + +------------------ +-- BUSINESS CASE 1 +-- Find the top 10 outliers - customers that differ the most from +-- the rest of the population. Depending on the application, such +-- atypical customers can be removed from the data (data cleansing). +-- + +SELECT cust_id FROM ( + SELECT cust_id + FROM svmo_sh_sample_prepared + ORDER BY prediction_probability(SVMO_SH_Clas_sample, 0 using *) DESC, 1) +WHERE rownum < 11; + + +------------------ +-- BUSINESS CASE 2 +-- Find demographic characteristics of the typical affinity card members. +-- These statistics will not be influenced by outliers and are likely to +-- to provide a more truthful picture of the population of interest than +-- statistics computed on the entire group of affinity members. +-- Statistics are computed on the original (non-transformed) data. +column cust_gender format a12 +SELECT a.cust_gender, round(avg(a.age)) age, + round(avg(a.yrs_residence)) yrs_residence, + count(*) cnt +FROM mining_data_one_class_v a, + svmo_sh_sample_prepared b +WHERE prediction(SVMO_SH_Clas_sample using b.*) = 1 +AND a.cust_id=b.cust_id +GROUP BY a.cust_gender +ORDER BY a.cust_gender; + + +------------------ +-- BUSINESS CASE 3 +-- +-- Compute probability of a new/hypothetical customer being a typical +-- affinity card holder. +-- Normalization of the numerical attributes is performed on-the-fly. +-- +column prob_typical format 9.99 + +WITH age_norm AS ( +SELECT shift, scale FROM svmo_sh_sample_norm WHERE col = 'AGE'), +yrs_residence_norm AS ( +SELECT shift, scale FROM svmo_sh_sample_norm WHERE col = 'YRS_RESIDENCE') +SELECT prediction_probability(SVMO_SH_Clas_sample, 1 using + (44 - a.shift)/a.scale AS age, + (6 - b.shift)/b.scale AS yrs_residence, + 'Bach.' AS education, + 'Married' AS cust_marital_status, + 'Exec.' AS occupation, + 'United States of America' AS country_name, + 'M' AS cust_gender, + 'L: 300,000 and above' AS cust_income_level, + '3' AS houshold_size + ) prob_typical +FROM age_norm a, yrs_residence_norm b; + diff --git a/dmsvodemo.java b/dmsvodemo.java new file mode 100644 index 0000000..20d549a --- /dev/null +++ b/dmsvodemo.java @@ -0,0 +1,581 @@ +// Copyright (c) 2004, 2005, Oracle. All rights reserved. +// File: dmsvodemo.java + import java.math.BigDecimal; + + import java.sql.PreparedStatement; + import java.sql.ResultSet; + import java.sql.ResultSetMetaData; + import java.sql.SQLException; + import java.sql.Statement; + + import java.text.DecimalFormat; + import java.text.MessageFormat; + + import java.util.Collection; + import java.util.Iterator; + + import java.util.Map; + import javax.datamining.ExecutionHandle; + import javax.datamining.ExecutionState; + import javax.datamining.ExecutionStatus; + import javax.datamining.JDMException; + import javax.datamining.MiningAlgorithm; + import javax.datamining.MiningFunction; + import javax.datamining.NamedObject; + import javax.datamining.algorithm.svm.KernelFunction; + import javax.datamining.algorithm.svm.classification.SVMClassificationSettings; + import javax.datamining.algorithm.svm.classification.SVMClassificationSettingsFactory; + import javax.datamining.base.AlgorithmSettings; + import javax.datamining.base.Model; + import javax.datamining.base.Task; + import javax.datamining.data.AttributeDataType; + import javax.datamining.data.CategorySet; + import javax.datamining.data.ModelSignature; + import javax.datamining.data.PhysicalAttribute; + import javax.datamining.data.PhysicalAttributeFactory; + import javax.datamining.data.PhysicalAttributeRole; + import javax.datamining.data.PhysicalDataSet; + import javax.datamining.data.PhysicalDataSetFactory; + import javax.datamining.data.SignatureAttribute; + import javax.datamining.modeldetail.svm.SVMClassificationModelDetail; + import javax.datamining.resource.ConnectionSpec; + import javax.datamining.supervised.classification.ClassificationApplySettings; + import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; + import javax.datamining.supervised.classification.ClassificationModel; + import javax.datamining.supervised.classification.ClassificationSettings; + import javax.datamining.supervised.classification.ClassificationSettingsFactory; + import javax.datamining.task.BuildTask; + import javax.datamining.task.BuildTaskFactory; + import javax.datamining.task.apply.DataSetApplyTask; + import javax.datamining.task.apply.DataSetApplyTaskFactory; + + import oracle.dmt.jdm.algorithm.svm.classification.OraSVMClassificationSettings; + import oracle.dmt.jdm.base.OraBuildSettings; + import oracle.dmt.jdm.modeldetail.svm.OraSVMClassificationModelDetail; + import oracle.dmt.jdm.resource.OraConnection; + import oracle.dmt.jdm.resource.OraConnectionFactory; + import oracle.dmt.jdm.supervised.classification.OraClassificationModel; + import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformImpl; +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using Support Vector Machines (SVM) +* algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Given demographic about a set of customers that are known to have +* an affinity card, 1) find the most atypical members of this group +* (outlier identification), 2) discover the common demographic +* characteristics of the most typical customers with affinity card, +* and 3) compute how typical a given new/hypothetical customer is. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created in the user +* schema using CUSTOMERS, COUNTRIES and SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_ONE_CLASS_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification one-class model using the SVM +* algorithm. +* +* Test Model: +* Classification model performance can be evaluated by computing test +* metrics like accuracy, confusion matrix, lift and ROC. The testModel() or +* computeTestMetrics() method illustrates how to perform the test operation to +* compute various metrics. We skip the test model in this demo. +* +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification one-class models. Depending on the business case, the +* model can be scored against the build data or against new, previously +* unseen data. New apply data needs to undergo the same transformations as +* the build data. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ + + +public class dmsvodemo extends Object { + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn ; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClassificationSettingsFactory m_clasFactory; + private static SVMClassificationSettingsFactory m_svmoFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClassificationApplySettingsFactory m_applySettingsFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + // Global data members + private static OraNormalizeTransformImpl m_normalizeDataXform; + + public static void main( String args[] ) { + try { + if (args.length != 3 ) { + System.out.println("Usage: java dmsvodemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build model - Please see dmnbdemo.java to see how to build a model + // with supplied prior probability. + buildModel(); + // 5. Apply the model + applyModel(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 7. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { } // Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_clasFactory = (ClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationSettings"); + m_svmoFactory = (SVMClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.algorithm.svm.classification.SVMClassificationSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = (ClassificationApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationApplySettings"); + } + + /** + * This method illustrates how to build a mining model using the + * SVMO_NORM_DATA_BUILD_JDM dataset and classification settings with + * SVM algorithm. + * + * By default, the SVM algorithm chooses a kernel type automatically. This + * choice can be overriden by the user. Linear kernel is preferred for high + * dimensional data, and Gaussian kernel for low dimensional data. Here we + * will let the data mining server choose the kernel type automatically, and + * define no target since this is a one-class classification demo. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("svmoBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // Create SVMC algorithm settings + SVMClassificationSettings svmoAlgo = m_svmoFactory.create(); + // Examples settings are: + // - Select a different rate of outliers in the data (default 0.1) + // svmoAlgo.setOutlierRate(0.05f); + // - Select a kernel type (default kernel: selected by the algorithm) + // svmoAlgo.setKernelFunction(KernelFunction.kLinear); + // svmoAlgo.setKernelFunction(KernelFunction.kGaussian); + // - Turn off active learning (enabled by default) + // svmoAlgo.setActiveLearning(false); + // + //Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(svmoAlgo); + //Set auto data preparation on + ((OraBuildSettings)buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject("svmoBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "svmoBuildData_jdm", //Build data specification + "svmoBuildSettings_jdm", //Mining function settings name + "svmoModel_jdm" //Mining model name + ); + buildTask.setDescription("svmoBuildTask_jdm"); + executeTask(buildTask, "svmoBuildTask_jdm"); + //4. Restore the model from the DME and explore the details of the model + ClassificationModel model = + (ClassificationModel)m_dmeConn.retrieveObject( + "svmoModel_jdm", NamedObject.model); + // Display model build settings + ClassificationSettings retrievedBuildSettings = + (ClassificationSettings)model.getBuildSettings(); + if(buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "svmoBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + // Display model details + displaySVMOModelDetails((Model)model); + } + + /** + * This method illustrates how to apply the mining model on the + * SVMO_NORM_DATA_BUILD_JDM dataset to predict customer + * response. After completion of the task, the apply output table with the + * predicted results is created at the user specified location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_BUILD_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "svmoApplyData_jdm", applyData, true ); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "svmoApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "svmoApplyData_jdm", "svmoModel_jdm", + "svmoApplySettings_jdm", "SVMO_APPLY_OUTPUT_JDM"); + executeTask(applyTask, "svmoApplyTask_jdm"); + // 4. Display apply result + displayTable("SVMO_APPLY_OUTPUT_JDM", // apply output table name + + "where PREDICTION = 0", // 0 means the record does not + // belong to the population + + "order by PROBABILITY DESC", // List from top probability to + // bottom + + 10); // List the first 10 rows + } + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful."); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() ); + } + return isTaskSuccess; + } + + private static void displayBuildSettings( + ClassificationSettings clasSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " object:"); + String objName = clasSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = clasSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = clasSettings.getCreationDate(); + String creator = clasSettings.getCreatorInfo(); + String targetAttrName = clasSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = clasSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: clasSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = clasSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: clasSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + // List of SVM algorithm settings availanle in one class model + KernelFunction kernelFunction = ((OraSVMClassificationSettings)algoSettings).getKernelFunction(); + System.out.println("Kernel Function: " + kernelFunction.name()); + double doubleValue = ((OraSVMClassificationSettings)algoSettings).getTolerance(); + System.out.println("Tolerance: " + m_df.format(doubleValue)); + boolean enable = ((OraSVMClassificationSettings)algoSettings).getActiveLearning(); + System.out.println("Is Active Learning enabled? " + enable); + doubleValue = ((OraSVMClassificationSettings)algoSettings).getOutlierRate(); + System.out.println("Outlier Rate: " + m_df.format(doubleValue)); + doubleValue = ((OraSVMClassificationSettings)algoSettings).getStandardDeviation(); + System.out.println("Standard Deviation: " + m_df.format(doubleValue)); + int intValue = ((OraSVMClassificationSettings)algoSettings).getKernelCacheSize(); + System.out.println("Kernel Cache Size: " + intValue); + } + + /** + * This method displayes SVMO model signature. + * + * @param model model object + * @exception JDMException if failed to retrieve model signature + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + /** + * This method displayes SVMO model details. The coefficient indicates the + * relative influence of a given (attribute, value) pair on the target value. + * A negative coefficient value indicates a negative influence. + * + * @param svmcModelDetails svm classification model details object + * @exception JDMException if failed to retrieve model details + */ + public static void displaySVMOModelDetails( + Model model) throws JDMException + { + // Obtains model details + SVMClassificationModelDetail svmcModelDetails = + (SVMClassificationModelDetail)model.getModelDetail(); + // Is linear model? + System.out.println("Is linear model? " + svmcModelDetails.isLinearSVMModel() ); + // Available targets + CategorySet targetSet = ((OraClassificationModel)model).getTargetCategorySet(); + Object[] targets = targetSet.getValues(); + // Attribute coefficient value will be available if it is a linear model + if (svmcModelDetails.isLinearSVMModel()) + { + System.out.println("Model Deatils: ( Target Value, Attribute Name, Attribute Value, Coefficient)"); + MessageFormat mfDetails = new MessageFormat(" ( {0}, {1}, {2}, {3} )"); + String[] vals = new String[4]; + for (int row =0; row < targets.length; row++) + { + // Print bias of the current target value by invoking getBias method. + vals[0] =(String) targets[row].toString(); + vals[1] = ""; + vals[2] = ""; + vals[3] = m_df.format(svmcModelDetails.getBias(targets[row])) + " (Bias)"; + System.out.println( mfDetails.format(vals) ); + //Get the signature attributes + ModelSignature modelSignature = model.getSignature(); + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + // Print all attribute coefficients -- The FIRST row in the SVM model + // details output shows the value for SVM bias under the COEFFICIENT + // column. + Map attrCoefficientMap = ((OraSVMClassificationModelDetail)svmcModelDetails).getCoefficients(targets[row],attr.getName()); + Object[] attrVals = attrCoefficientMap.keySet().toArray(); + if(attrVals != null) { + for(int iAttr=0; iAttr < attrVals.length; iAttr++) + { + vals[1] = attr.getName(); + vals[2] = ""; + if(attrVals[iAttr] != null) + vals[2] = attrVals[iAttr].toString(); + vals[3] = ""; + Number coefficient = (Number)attrCoefficientMap.get(attrVals[iAttr]); + if(coefficient != null) + vals[3] = m_df.format(coefficient); + System.out.println( mfDetails.format(vals) ); + } + } + } + } + } + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + displayTable(tableName, whereCause, orderByColumn, 0); // display all rows + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn, int maxRow) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + int row = 0; + while(rs.next()) + { + row = row + 1; + if (row > maxRow & maxRow > 0) + break; + + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + private static void clean() + { + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + //Drop prepared views + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW SVMO_NORM_DATA_BUILD_JDM"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW SVMO_NORM_DATA_APPLY_JDM"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop apply output table + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE SVMO_APPLY_OUTPUT_JDM"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop the model + try { + m_dmeConn.removeObject("svmoModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + } +} diff --git a/dmsvrdem.sql b/dmsvrdem.sql new file mode 100644 index 0000000..9e75ba0 --- /dev/null +++ b/dmsvrdem.sql @@ -0,0 +1,227 @@ +Rem +Rem $Header: dmsvrdem.sql 25-oct-2007.11:34:45 ramkrish Exp $ +Rem +Rem dmsvrdem.sql +Rem +Rem Copyright (c) 2003, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmsvrdem.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a regression model +Rem using the SVM algorithm +Rem and data in the SH (Sales History) schema in the RDBMS. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem jiawang 08/02/06 - ENABLE ADP +Rem ktaylor 07/11/05 - minor edits to comments +Rem ramkrish 12/09/04 - fix incorrect table names +Rem bmilenov 11/04/04 - Edit comments +Rem ramkrish 09/28/04 - add data analysis, comments, SQL functions +Rem bmilenov 05/18/04 - Change zscore to minmax normalization +Rem pstengar 12/11/03 - modified apply selection query +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic, purchase, and affinity card membership data for a +-- set of customers, predict customer's age. Since age is a continuous +-- variable, this is a regression problem. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE DATA +----------------------------------------------------------------------- + +-- The data for this sample is composed from base tables in the SH Schema +-- (See Sample Schema Documentation) and presented through these views: +-- mining_data_build_v (build data) +-- mining_data_test_v (test data) +-- mining_data_apply_v (apply data) +-- (See dmsh.sql for view definitions). +-- +----------- +-- ANALYSIS +----------- +-- For regression using SVM, perform the following on mining data. +-- +-- 1. Use Auto Data Preparation +-- + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old model with same name (if any) +BEGIN DBMS_DATA_MINING.DROP_MODEL('SVMR_SH_Regr_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE svmr_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- The default algorithm for regression is SVM. +-- see dmsvcdem.sql on choice of kernel function. +-- +CREATE TABLE svmr_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); + +BEGIN + -- Populate settings table + INSERT INTO svmr_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.svms_kernel_function, dbms_data_mining.svms_gaussian); + + INSERT INTO svmr_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.prep_auto,dbms_data_mining.prep_auto_on); + + -- Examples of other possible overrides are: + --(dbms_data_mining.svms_conv_tolerance,0.01); + --(dbms_data_mining.svms_epsilon,0.1); + --(dbms_data_mining.svms_kernel_cache_size,50000000); + --(dbms_data_mining.svms_kernel_function,dbms_data_mining.svms_linear); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'SVMR_SH_Regr_sample', + mining_function => dbms_data_mining.regression, + data_table_name => 'mining_data_build_v', + case_id_column_name => 'cust_id', + target_column_name => 'age', + settings_table_name => 'svmr_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'SVMR_SH_REGR_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'SVMR_SH_REGR_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Skip. GET_MODEL_DETAILS_SVM is supported only for Linear Kernels. +-- The current model is built using a Gaussian Kernel (see dmsvcdem.sql). +-- + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- + +CREATE VIEW svmr_sh_sample_test AS +SELECT A.cust_id, + PREDICTION(svmr_sh_regr_sample USING *) prediction + FROM mining_data_test_v A; + + +-- COMPUTE TEST METRICS +-- +-- 1. Root Mean Square Error - Sqrt(Mean((x - x')^2)) +-- +column rmse format 9999.99 +SELECT SQRT(AVG((A.prediction - B.age) * (A.prediction - B.age))) rmse + FROM svmr_sh_sample_test A, + mining_data_test_v B + WHERE A.cust_id = B.cust_id; + + + +-- 2. Mean Absolute Error - Mean(|(x - x')|) +-- +column mae format 9999.99 +SELECT AVG(ABS(a.prediction - B.age)) mae + FROM svmr_sh_sample_test A, + mining_data_test_v B + WHERE A.cust_id = B.cust_id; + +-- 3. Residuals +-- If the residuals show substantial variance between +-- the predicted value and the actual, you can consider +-- changing the algorithm parameters. +-- +SELECT TO_CHAR(ROUND(prediction, 4)) prediction, residual + FROM (SELECT A.prediction, (A.prediction - B.age) residual + FROM svmr_sh_sample_test A, + mining_data_test_v B + WHERE A.cust_id = B.cust_id + ORDER BY A.prediction ASC) + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- +------------------------------------------------- +-- SCORE NEW DATA USING SQL DATA MINING FUNCTIONS +-- +------------------ +-- BUSINESS CASE 1 +-- Predict the average age of customers, broken out by gender. +-- +SELECT A.cust_gender, + COUNT(*) AS cnt, + ROUND( + AVG(PREDICTION(svmr_sh_regr_sample USING A.*)),4) + AS avg_age + FROM mining_data_apply_v A +GROUP BY cust_gender +ORDER BY cust_gender; + + +column pred_age format 999.99 +------------------ +-- BUSINESS CASE 2 +-- Create a 10 bucket histogram of customers from Italy based on their age +-- and return each customer's age group. +-- +WITH +cust_italy AS ( +SELECT * + FROM mining_data_apply_v + WHERE country_name = 'Italy' +) +SELECT cust_id, + PREDICTION(svmr_sh_regr_sample USING A.*) pred_age, + WIDTH_BUCKET( + PREDICTION(svmr_sh_regr_sample USING A.*), 10, 100, 10) "Age Group" + FROM cust_italy A +ORDER BY pred_age; diff --git a/dmsvrdemo.java b/dmsvrdemo.java new file mode 100644 index 0000000..9da44ab --- /dev/null +++ b/dmsvrdemo.java @@ -0,0 +1,745 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmsvrdemo.java +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a regression problem using Support Vector Machines (SVM) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Given demographic, purchase, and affinity card membership data for a set of +* customers, predict customer's age. Since age is a continuous variable, this +* is a regression problem. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the +* previous affinity card programs. Data exploration and preparing the data is a +* common step before doing data mining. Here in this demo, the following views are +* created in the user schema using CUSTOMERS, COUNTRIES, and +* SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics, purchasing, +* and affinity card response details for predicting customer's age. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a regression model using SVM algorithm. +* +* Test Model: +* Regression models performance can be evaluated by computing different types +* of error rates. The testModel() or computeTestMetrics() method illustrates how +* to perform the test operation to compute various error rates. +* +* Apply Model: +* Predicting the target attribute values is the prime function of regression +* models. The applyModel() method illustrates how to predict the customer's age. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic Java api imports +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; + +import java.text.DecimalFormat; +import java.text.MessageFormat; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.algorithm.svm.KernelFunction; +import javax.datamining.algorithm.svm.regression.SVMRegressionSettings; +import javax.datamining.algorithm.svm.regression.SVMRegressionSettingsFactory; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.modeldetail.svm.SVMRegressionModelDetail; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationTestMetrics; +import javax.datamining.supervised.regression.RegressionApplySettings; +import javax.datamining.supervised.regression.RegressionApplySettingsFactory; +import javax.datamining.supervised.regression.RegressionModel; +import javax.datamining.supervised.regression.RegressionSettings; +import javax.datamining.supervised.regression.RegressionSettingsFactory; +import javax.datamining.supervised.regression.RegressionTestMetrics; +import javax.datamining.supervised.regression.RegressionTestMetricsTask; +import javax.datamining.supervised.regression.RegressionTestMetricsTaskFactory; +import javax.datamining.supervised.regression.RegressionTestTask; +import javax.datamining.supervised.regression.RegressionTestTaskFactory; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; + +import oracle.dmt.jdm.algorithm.svm.regression.OraSVMRegressionSettings; +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.modeldetail.svm.OraSVMRegressionModelDetail; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.supervised.regression.OraRegressionApplySettings; +import oracle.dmt.jdm.supervised.regression.OraRegressionTestMetrics; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformImpl; +import oracle.dmt.jdm.transform.normalize.OraNormalizeType; +// Java Data Mining (JDM) standard api imports +// Oracle Java Data Mining (JDM) implemented api imports + +public class dmsvrdemo extends Object { + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static RegressionSettingsFactory m_regrFactory; + private static SVMRegressionSettingsFactory m_svmrFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static RegressionTestTaskFactory m_testFactory; + private static RegressionApplySettingsFactory m_applySettingsFactory; + private static RegressionTestMetricsTaskFactory m_testMetricsTaskFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + // Global data members + private static OraNormalizeTransformImpl m_buildDataXform; + + public static void main( String args[] ) { + try { + if ( args.length != 3 ) { + System.out.println("Usage: java dmsvrdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build a model + buildModel(); + // 5a. Test model - To compute different type of error rates for the + // model from a test input data. + testModel(); + // 5b. Test model - To compute different type of error rates for the + // model from an apply output data. + computeTestMetrics(); + // 6. Apply the model + applyModel(); + // 7. Start execution of the first task in the sequnece + m_dmeConn.execute("svmrBuildTask_jdm"); + // 8. Monitor and display results (if any) + monitorTaskExecutionProcess(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { }//Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_regrFactory = (RegressionSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionSettings"); + m_svmrFactory = (SVMRegressionSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.algorithm.svm.regression.SVMRegressionSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_testFactory = (RegressionTestTaskFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionTestTask"); + m_applySettingsFactory = (RegressionApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionApplySettings"); + m_testMetricsTaskFactory = (RegressionTestMetricsTaskFactory) m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionTestMetricsTask"); + } + + /** + * This method illustrates how to build mining model using + * MINING_DATA_BUILD_V dataset and regression settings with + * SVM algorithm. + * + * By default SVM algorithm chooses a kernel type automatically. This + * choice can be overriden by the user. Linear kernel is preferred for high + * dimensional data, and Gaussian kernel for low dimensional data. Here we use + * Gaussian kernel in this demo. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("svmrBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // Create SVMR algorithm settings + SVMRegressionSettings svmrAlgo = m_svmrFactory.create(); + svmrAlgo.setKernelFunction(KernelFunction.kGaussian); + // Examples settings are: + // svmrAlgo.setKernelFunction(KernelFunction.kLinear); + // svmrAlgo.setEpsilon(0.1f); + // svmrAlgo.setTolerance(0.01f); + // svmrAlgo.setKernelCacheSize(50000000); + // + // Create RegressionSettings + RegressionSettings buildSettings = m_regrFactory.create(); + buildSettings.setAlgorithmSettings(svmrAlgo); + buildSettings.setTargetAttributeName("AGE"); + //Set auto data preparation on + ((OraBuildSettings)buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject("svmrBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "svmrBuildData_jdm", //Build data specification + "svmrBuildSettings_jdm", //Mining function settings name + "svmrModel_jdm" //Mining model name + ); + buildTask.setDescription("svmrBuildTask_jdm"); + saveTask(buildTask, "svmrBuildTask_jdm", null); + } + + /** + * This method illustrates how to test the mining model with the + * MINING_DATA_TEST_V dataset using regression test task. After + * completion of the task, a regression test metrics object is created + * in the DMS. Regression test metrics object encapsulates + * different types of error rates. + * + * @exception JDMException if model test failed + */ + public static void testModel() + throws JDMException + { + + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet testData = m_pdsFactory.create( + "MINING_DATA_TEST_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + testData.addAttribute( pa ); + m_dmeConn.saveObject( "svmrTestData_jdm", testData, true ); + // 2. Create, store & execute Test Task + RegressionTestTask testTask = m_testFactory.create( + "svmrTestData_jdm", "svmrModel_jdm", "svrTestMetrics_jdm" ); + // 3. Store the task + saveTask(testTask, "svmrTestTask_jdm", "svmrBuildTask_jdm"); + } + + /** + * This method illustrates how to compute test metrics using + * an apply output table that has actual and predicted target values. Here the + * apply operation is done on the MINING_DATA_TEST_V dataset. It creates + * an apply output table with actual and predicted target values. Using + * RegressionTestMetricsTask test metrics are computed. This produces + * the same test metrics results as RegressionTestTask. + * + * @exception JDMException if model test failed + */ + public static void computeTestMetrics() throws JDMException + { + + // 1. Do the apply on test data to create an apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create( "MINING_DATA_TEST_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "svmrTestApplyData_jdm", applyData, true ); + // 2. Create & save RegressionApplySettings + RegressionApplySettings regreAS = m_applySettingsFactory.create(); + HashMap sourceAttrMap = new HashMap(); + sourceAttrMap.put( "AGE", "AGE" ); + regreAS.setSourceDestinationMap( sourceAttrMap ); + m_dmeConn.saveObject( "svmrTestApplySettings_jdm", regreAS, true); + // 3. Create & store apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "svmrTestApplyData_jdm", "svmrModel_jdm", "svmrTestApplySettings_jdm", + "SVMR_TEST_APPLY_OUTPUT_JDM"); + saveTask(applyTask, "svmrTestApplyTask_jdm", "svmrBuildTask_jdm"); + // 4. Generate test metrics on the above new created apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyOutputData = m_pdsFactory.create( + "SVMR_TEST_APPLY_OUTPUT_JDM", false ); + applyOutputData.addAttribute( pa ); + m_dmeConn.saveObject( "svmrTestApplyOutput_jdm", applyOutputData, true ); + // 5. Create a RegressionTestMetricsTask + RegressionTestMetricsTask testMetricsTask = + m_testMetricsTaskFactory.create( "svmrTestApplyOutput_jdm", // apply output data used as input + "AGE", // actual target column + "PREDICTION", // predicted target column + "svrComputeTestMetrics_jdm" // test metrics result name + ); + // 6. Store & execute the task + saveTask(testMetricsTask, "svmrTestMetricsTask_jdm", "svmrTestApplyTask_jdm"); + } + + /** + * This method illustrates how to apply mining model on + * MINING_DATA_APPLY_V dataset to predict customer's age. + * After completion of the task apply output table with the + * predicted results is created at the user specified location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "svmrApplyData_jdm", applyData, true ); + // 2. Create & save RegressionApplySettings + RegressionApplySettings regrAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "svmrApplySettings_jdm", regrAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "svmrApplyData_jdm", "svmrModel_jdm", "svmrApplySettings_jdm", + "SVMR_APPLY_OUTPUT_JDM"); + saveTask(applyTask, "svmrApplyTask_jdm", "svmrBuildTask_jdm"); + } + + /** + * This method saves the given task with the specified task name and task + * dependency (parent task) in the DME. + * + * @param taskObj task object + * @param taskName name of the task + * @param parentTaskName name of the parent task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static void saveTask(Task taskObj, String taskName, + String parentTaskName) + throws JDMException + { + if (parentTaskName != null) + ((OraTask) taskObj).addDependency(parentTaskName); //Since OJDM 11.1 + ((OraTask) taskObj).overwriteOutput(true); //Since OJDM 11.1 + m_dmeConn.saveObject(taskName, taskObj, true); + } + + /** + * This method monitor task execution initiated by the first task + * in the sequence of dependent tasks. In addition, this method displays + * task output results (if any). + * @throws JDMException + */ + public static void monitorTaskExecutionProcess() + throws JDMException + { + //BuildTask + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of svmrBuildTask_jdm. "); + ExecutionStatus buildTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("svmrBuildTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(buildTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + // 3. Restore the model from the data mining server + RegressionModel model = + (RegressionModel)m_dmeConn.retrieveObject( + "svmrModel_jdm", NamedObject.model); + // 4. Explore the details of the restored model + // Display model build settings + RegressionSettings retrievedBuildSettings = + (RegressionSettings)model.getBuildSettings(); + if(retrievedBuildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "svmrBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + // Display model details + displaySVMRModelDetails(model); + + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model ---"); + System.out.println("---------------------------------------------------"); + + //If model build is successful, then do testData ApplyTask + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of svmcTestTask_jdm. "); + ExecutionStatus testTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("svmrTestTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(testTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + // Restore & display test metrics + RegressionTestMetrics testMetrics = + (RegressionTestMetrics)m_dmeConn.retrieveObject( + "svrTestMetrics_jdm", + NamedObject.testMetrics ); + // Display regression test metrics + displayTestMetricDetails(testMetrics); + } + else + { + System.out.println("It is at state:" + + testTaskCompletionStatus.getState().name() + + ((testTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + testTaskCompletionStatus.getDescription())); + } + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using apply output table ---"); + System.out.println("---------------------------------------------------"); + + //If model build is successful, then do testData ApplyTask + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of svmrTestMetricsTask_jdm. "); + ExecutionStatus testMetricsTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("svmrTestMetricsTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(testMetricsTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + // Restore & display test metrics + RegressionTestMetrics testMetrics = + (RegressionTestMetrics)m_dmeConn.retrieveObject( + "svrComputeTestMetrics_jdm", + NamedObject.testMetrics ); + // Display regression test metrics + displayTestMetricDetails(testMetrics); + } + else + { + System.out.println("It is at state:" + + testMetricsTaskCompletionStatus.getState().name() + + ((testMetricsTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + testMetricsTaskCompletionStatus.getDescription())); + } + + //ApplyTask(s) + //Waiting for apply task to complete + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + + ExecutionStatus applyTaskStatus = + m_dmeConn.getLastExecutionHandle("svmrApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + if (ExecutionState.success.equals(applyTaskStatus.getState())) + { + // Display apply result + displayTable("SVMR_APPLY_OUTPUT_JDM", "where ROWNUM < 11", + "order by CUST_ID"); + } + else + { + System.out.println("svmcApplyTask_jdm is at state:" + + applyTaskStatus.getState().name() + + ((applyTaskStatus.getDescription() == null)? + "": + "State Description:" + applyTaskStatus.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + buildTaskCompletionStatus.getState().name() + + ((buildTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + buildTaskCompletionStatus.getDescription())); + } + + } + + private static void displayBuildSettings( + RegressionSettings regrSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " object:"); + String objName = regrSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = regrSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = regrSettings.getCreationDate(); + String creator = regrSettings.getCreatorInfo(); + String targetAttrName = regrSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = regrSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: regrSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = regrSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: regrSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + // List of SVM algorithm settings availabe in linear kernel + KernelFunction kernelFunction = ((OraSVMRegressionSettings)algoSettings).getKernelFunction(); + System.out.println("Kernel Function: " + kernelFunction.name()); + double doubleValue = ((OraSVMRegressionSettings)algoSettings).getComplexityFactor(); + System.out.println("Complexity Factor: " + m_df.format(doubleValue)); + doubleValue = ((OraSVMRegressionSettings)algoSettings).getTolerance(); + System.out.println("Tolerance: " + m_df.format(doubleValue)); + boolean enable = ((OraSVMRegressionSettings)algoSettings).getActiveLearning(); + System.out.println("Is Active Learning enabled? " + enable); + doubleValue = ((OraSVMRegressionSettings)algoSettings).getEpsilon(); + System.out.println("Epsilon: " + m_df.format(doubleValue)); + } + + /** + * This method displayes SVMR model signature. + * + * @param model model object + * @exception JDMException if failed to retrieve model signature + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + /** + * This method displays SVMR model details. The coefficient indicates the + * relative influence of a given (attribute, value). A negative coefficient + * value indicates a negative influence. + * + * @param svmrModelDetails svm regression model details object + * @exception JDMException if failed to retrieve model details + */ + public static void displaySVMRModelDetails(Model model) + throws JDMException + { + SVMRegressionModelDetail svmrModelDetails = + (SVMRegressionModelDetail)model.getModelDetail(); + // Is linear model? + System.out.println("Is linear model? " + svmrModelDetails.isLinearSVMModel() ); + // Attribute coefficient value will be available if it is a linear model + if (svmrModelDetails.isLinearSVMModel()) + { + System.out.println("Model Deatils: ( Attribute Name, Attribute Value, Coefficient)"); + MessageFormat mfDetails = new MessageFormat(" ( {0}, {1}, {2}, {3} )"); + String[] vals = new String[4]; + // Print bias by invoking getBias method. + vals[0] = ""; + vals[1] = ""; + vals[2] = m_df.format(svmrModelDetails.getBias()) + " (Bias)"; + System.out.println( mfDetails.format(vals) ); + //Get the signature attributes + ModelSignature modelSignature = model.getSignature(); + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + // Print all attribute coefficients -- The FIRST row in the SVM model + // details output shows the value for SVM bias under the COEFFICIENT + // column. + Map attrCoefficientMap = ((OraSVMRegressionModelDetail)svmrModelDetails).getCoefficients(attr.getName()); + Object[] attrVals = attrCoefficientMap.keySet().toArray(); + if(attrVals != null) { + for(int iAttr=0; iAttr < attrVals.length; iAttr++) + { + vals[0] = attr.getName(); + vals[1] = ""; + if(attrVals[iAttr] != null) + vals[1] = attrVals[iAttr].toString(); + vals[2] = ""; + Number coefficient = (Number)attrCoefficientMap.get(attrVals[iAttr]); + if(coefficient != null) + vals[2] = m_df.format(coefficient); + System.out.println( mfDetails.format(vals) ); + } + } + } + } + } + + /** + * Display regression test metrics object + * + * @param testMetrics classification test metrics object + * @exception JDMException if failed to retrieve test metric details + */ + public static void displayTestMetricDetails( + RegressionTestMetrics testMetrics) throws JDMException + { + //Retrieve Oracle SVMR model test metrics deatils extensions + // Name + System.out.println("Test Metrics Name = " + testMetrics.getName()); + // Model Name + System.out.println("Model Name = " + testMetrics.getModelName()); + // Test Data Name + System.out.println("Test Data Name = " + testMetrics.getTestDataName()); + // Mean Absolute Error + System.out.println("Mean Absolute Error = " + m_df.format(testMetrics.getMeanAbsoluteError().doubleValue())); + // Mean Actual Value + System.out.println("Mean Actual Value = " + m_df.format(testMetrics.getMeanActualValue().doubleValue())); + // Mean Predicted Value + System.out.println("Mean Predicted Value = " + m_df.format(testMetrics.getMeanPredictedValue().doubleValue())); + // Root Mean Squared Error + System.out.println("Root Mean Squared Error = " + m_df.format(testMetrics.getRMSError().doubleValue())); + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while(rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + private static void clean() + { + //Drop the model + try { + m_dmeConn.removeObject("svmrModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + } +} diff --git a/dmtreedemo.java b/dmtreedemo.java new file mode 100644 index 0000000..b753d70 --- /dev/null +++ b/dmtreedemo.java @@ -0,0 +1,1230 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmtreedemo.java + +// Generic Java api imports +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; + +import java.text.DecimalFormat; +import java.text.MessageFormat; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Stack; +// Java Data Mining (JDM) standard api imports +import java.util.logging.Level; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.SizeUnit; +import javax.datamining.algorithm.tree.TreeHomogeneityMetric; +import javax.datamining.algorithm.tree.TreeSettings; +import javax.datamining.algorithm.tree.TreeSettingsFactory; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.CategoryProperty; +import javax.datamining.data.CategorySet; +import javax.datamining.data.CategorySetFactory; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.modeldetail.tree.TreeModelDetail; +import javax.datamining.modeldetail.tree.TreeNode; +import javax.datamining.resource.Connection; +import javax.datamining.resource.ConnectionFactory; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.rule.Predicate; +import javax.datamining.rule.Rule; +import javax.datamining.supervised.classification.ClassificationApplySettings; +import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.supervised.classification.ClassificationTestMetricOption; +import javax.datamining.supervised.classification.ClassificationTestMetrics; +import javax.datamining.supervised.classification.ClassificationTestMetricsTask; +import javax.datamining.supervised.classification.ClassificationTestMetricsTaskFactory; +import javax.datamining.supervised.classification.ClassificationTestTaskFactory; +import javax.datamining.supervised.classification.ConfusionMatrix; +import javax.datamining.supervised.classification.CostMatrix; +import javax.datamining.supervised.classification.CostMatrixFactory; +import javax.datamining.supervised.classification.Lift; +import javax.datamining.supervised.classification.ReceiverOperatingCharacterics; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.algorithm.tree.OraTreeSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.modeldetail.tree.OraTreeModelDetail; +import oracle.dmt.jdm.supervised.classification.OraClassificationTestMetrics; +import oracle.dmt.jdm.supervised.classification.OraLift; + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using Decision Tree (DT) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* How to predict whether a customer responds or not to the new affinity card +* program using a classifier based on DT algorithm? +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created in the user +* schema using CUSTOMERS, COUNTRIES, and SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics and purchasing +* details for predicting response for the new affinity card program. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* For decision tree data mining specific data preparations are done +* implicitely, user needs to do only required data cleansing, derived +* attributes etc. as part of the ETL. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification model using DT algorithm. +* +* Test Model: +* Classification model performance can be evaluated by computing test +* metrics like accuracy, confusion matrix, lift and ROC. The testModel() or +* computeTestMetrics() method illustrates how to perform a test operation to +* compute various metrics. +* +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification models. The applyModel() method illustrates how to +* predict the customer response for affinity card program. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +public class + +dmtreedemo +{ + //Connection related data members + private static Connection m_dmeConn; + private static ConnectionFactory m_dmeConnFactory; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClassificationSettingsFactory m_clasFactory; + private static TreeSettingsFactory m_treeFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClassificationTestTaskFactory m_testFactory; + private static ClassificationApplySettingsFactory m_applySettingsFactory; + private static CostMatrixFactory m_costMatrixFactory; + private static CategorySetFactory m_catSetFactory; + private static ClassificationTestMetricsTaskFactory m_testMetricsTaskFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + private static String m_costMatrixName = null; + + public static void main(String[] args) + { + try + { + if (args.length != 3) + { + System.out.println("Usage: java dmtreedemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + ((OraConnection) m_dmeConn).getLogger().setLevel(Level.FINEST); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + m_costMatrixName = createCostMatrix(); + // 4. Create and save task to build the model + buildModel(); + // 5. Create and save task to test model and add build task + // as its parent task. + computeTestMetrics("DT_TEST_APPLY_OUTPUT_JDM", m_costMatrixName); + // 6. Create and save task to apply the model + applyModel(); + //7. Start execution of the build task that trigger execution of + // its dependent task(s), here after completion of the build task + // test task starts executing and then apply task. + m_dmeConn.execute("treeBuildTask_jdm"); + //8. Monitor the task executions of current and its dependent tasks + // and display task output results + monitorTaskExecutionProcess(); + + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + //6. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + //Ignore + } + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() + throws JDMException + { + m_pdsFactory = + (PhysicalDataSetFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalDataSet"); + m_paFactory = + (PhysicalAttributeFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalAttribute"); + m_clasFactory = + (ClassificationSettingsFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationSettings"); + m_treeFactory = + (TreeSettingsFactory) m_dmeConn.getFactory("javax.datamining.algorithm.tree.TreeSettings"); + m_buildFactory = + (BuildTaskFactory) m_dmeConn.getFactory("javax.datamining.task.BuildTask"); + m_dsApplyFactory = + (DataSetApplyTaskFactory) m_dmeConn.getFactory("javax.datamining.task.apply.DataSetApplyTask"); + m_testFactory = + (ClassificationTestTaskFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationTestTask"); + m_applySettingsFactory = + (ClassificationApplySettingsFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationApplySettings"); + m_costMatrixFactory = + (CostMatrixFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.CostMatrix"); + m_catSetFactory = + (CategorySetFactory) m_dmeConn.getFactory("javax.datamining.data.CategorySet"); + m_testMetricsTaskFactory = + (ClassificationTestMetricsTaskFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationTestMetricsTask"); + } + + /** + * Create and save cost matrix. + * + * Consider an example where it costs $10 to mail a promotion to a + * prospective customer and if the prospect becomes a customer, the + * typical sale including the promotion, is worth $100. Then the cost + * of missing a customer (i.e. missing a $100 sale) is 10x that of + * incorrectly indicating that a person is good prospect (spending + * $10 for the promo). In this case, all prediction errors made by + * the model are NOT equal. To act on what the model determines to + * be the most likely (probable) outcome may be a poor choice. + * + * Suppose that the probability of a BUY reponse is 10% for a given + * prospect. Then the expected revenue from the prospect is: + * .10 * $100 - .90 * $10 = $1. + * + * The optimal action, given the cost matrix, is to simply mail the + * promotion to the customer, because the action is profitable ($1). + * + * In contrast, without the cost matrix, all that can be said is + * that the most likely response is NO BUY, so don't send the + * promotion. This shows that cost matrices can be very important. + * + * The caveat in all this is that the model predicted probabilities + * may NOT be accurate. For binary targets, a systematic approach to + * this issue exists. It is ROC, illustrated below. + * + * With ROC computed on a test set, the user can see how various model + * predicted probability thresholds affect the action of mailing a promotion. + * Suppose I promote when the probability to BUY exceeds 5, 10, 15%, etc. + * what return can I expect? Note that the answer to this question does + * not rely on the predicted probabilities being accurate, only that + * they are in approximately the correct rank order. + * + * Assuming that the predicted probabilities are accurate, provide the + * cost matrix table name as input to the RANK_APPLY procedure to get + * appropriate costed scoring results to determine the most appropriate + * action. + * + * In this demo, we will create the following cost matrix + * + * ActualTarget PredictedTarget Cost + * ------------ --------------- ---- + * 0 0 0 + * 0 1 1 + * 1 0 8 + * 1 1 0 + */ + private static String createCostMatrix() + throws JDMException + { + String costMatrixName = "treeCostMatrix"; + // Create categorySet + CategorySet catSet = + m_catSetFactory.create(AttributeDataType.integerType); + // Add category values + catSet.addCategory(new Integer(0), CategoryProperty.valid); + catSet.addCategory(new Integer(1), CategoryProperty.valid); + // Create cost matrix + CostMatrix costMatrix = m_costMatrixFactory.create(catSet); + // ActualTarget PredictedTarget Cost + // ------------ --------------- ---- + costMatrix.setCellValue(new Integer(0), new Integer(0), 0); + costMatrix.setCellValue(new Integer(0), new Integer(1), 1); + costMatrix.setCellValue(new Integer(1), new Integer(0), 8); + costMatrix.setCellValue(new Integer(1), new Integer(1), 0); + //save cost matrix + m_dmeConn.saveObject(costMatrixName, costMatrix, true); + return costMatrixName; + } + + /** + * This method illustrates how to build a mining model using the + * MINING_DATA_BUILD_V dataset and classification settings with + * DT algorithm. + * + * @exception JDMException if model build failed + */ + public static void buildModel() + throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + buildData.addAttribute(pa); + m_dmeConn.saveObject("treeBuildData_jdm", buildData, true); + //2. Create & save Mining Function Settings + // + // Create default tree algorithm settings + TreeSettings treeAlgo = m_treeFactory.create(); + // Set cost matrix. A cost matrix is used to influence the weighting of + // misclassification during model creation (and scoring). + // See Oracle Data Mining Concepts Guide for more details. + // + String costMatrixName = m_costMatrixName; + // + // Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(treeAlgo); + buildSettings.setCostMatrixName(costMatrixName); + buildSettings.setTargetAttributeName("AFFINITY_CARD"); + m_dmeConn.saveObject("treeBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = + m_buildFactory.create("treeBuildData_jdm", "treeBuildSettings_jdm", + "treeModel_jdm"); + buildTask.setDescription("treeBuildTask_jdm"); + saveTask(buildTask, "treeBuildTask_jdm", null); + } + + + /** + * This method illustrates how to compute test metrics using + * an apply output table that has actual and predicted target values. Here the + * apply operation is done on the MINING_DATA_TEST_V dataset. It creates + * an apply output table with actual and predicted target values. Using + * ClassificationTestMetricsTask test metrics are computed. This produces + * the same test metrics results as ClassificationTestTask. + * + * @param applyOutputName apply output table name + * @param costMatrixName table name of the supplied cost matrix + * + * @exception JDMException if model test failed + */ + public static void computeTestMetrics(String applyOutputName, + String costMatrixName) + throws JDMException + { + // 1. Do the apply on test data to create an apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_TEST_V", false); + PhysicalAttribute pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("treeTestApplyData_jdm", applyData, true); + // 2 Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + HashMap sourceAttrMap = new HashMap(); + sourceAttrMap.put("AFFINITY_CARD", "AFFINITY_CARD"); + clasAS.setSourceDestinationMap(sourceAttrMap); + m_dmeConn.saveObject("treeTestApplySettings_jdm", clasAS, true); + // 3 Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("treeTestApplyData_jdm", "treeModel_jdm", + "treeTestApplySettings_jdm", + applyOutputName); + saveTask(applyTask, "treeTestApplyTask_jdm", "treeBuildTask_jdm"); + + { + // Compute test metrics on new created apply output table + // 4. Create & save PhysicalDataSpecification + PhysicalDataSet applyOutputData = + m_pdsFactory.create(applyOutputName, false); + applyOutputData.addAttribute(pa); + m_dmeConn.saveObject("treeTestApplyOutput_jdm", applyOutputData, + true); + // 5. Create a ClassificationTestMetricsTask + ClassificationTestMetricsTask testMetricsTask = + // apply output data used as input + // actual target column + // predicted target column + // test metrics result name + m_testMetricsTaskFactory.create("treeTestApplyOutput_jdm", + "AFFINITY_CARD", "PREDICTION", + "dtTestMetrics_jdm"); // enable confusion matrix computation + testMetricsTask.computeMetric(ClassificationTestMetricOption.confusionMatrix, + true); // enable lift computation + testMetricsTask.computeMetric(ClassificationTestMetricOption.lift, + true); // enable ROC computation + testMetricsTask.computeMetric(ClassificationTestMetricOption.receiverOperatingCharacteristics, + true); + //testMetricsTask.setPositiveTargetValue(new Integer(1)); + testMetricsTask.setNumberOfLiftQuantiles(10); + testMetricsTask.setPredictionRankingAttrName("PROBABILITY"); + // Store & execute the task + saveTask(testMetricsTask, "treeTestMetricsTask_jdm", + "treeTestApplyTask_jdm"); + if (costMatrixName != null) + { + ClassificationTestMetricsTask testMetricsCostTask = + // apply output data used as input + // actual target column + // predicted target column + // test metrics result name + m_testMetricsTaskFactory.create("treeTestApplyOutput_jdm", + "AFFINITY_CARD", "PREDICTION", + "dtTestMetricsWithCost_jdm"); // enable confusion matrix computation + testMetricsCostTask.computeMetric(ClassificationTestMetricOption.confusionMatrix, + true); // enable lift computation + testMetricsCostTask.computeMetric(ClassificationTestMetricOption.lift, + true); // enable ROC computation + testMetricsCostTask.computeMetric(ClassificationTestMetricOption.receiverOperatingCharacteristics, + true); + //testMetricsCostTask.setPositiveTargetValue(new Integer(1)); + testMetricsCostTask.setNumberOfLiftQuantiles(10); + testMetricsCostTask.setPredictionRankingAttrName("PROBABILITY"); + testMetricsCostTask.setCostMatrixName(costMatrixName); + saveTask(testMetricsCostTask, "treeTMWithCostTask_jdm", + "treeTestApplyTask_jdm"); + } + } + } + + + /** + * This method illustrates how to apply the mining model on the + * MINING_DATA_APPLY_V dataset to predict customer + * response. After completion of the task apply output table with the + * predicted results is created at the user specified location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() + throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("treeApplyData_jdm", applyData, true); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + // Add source attributes + HashMap sourceAttrMap = new HashMap(); + sourceAttrMap.put("COUNTRY_NAME", "COUNTRY_NAME"); + clasAS.setSourceDestinationMap(sourceAttrMap); + // Add cost matrix + clasAS.setCostMatrixName(m_costMatrixName); + m_dmeConn.saveObject("treeApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("treeApplyData_jdm", "treeModel_jdm", + "treeApplySettings_jdm", + "TREE_APPLY_OUTPUT1_JDM"); + saveTask(applyTask, "treeApplyTask1_jdm", "treeBuildTask_jdm"); + + + // 1. Create & save PhysicalDataSpecification + applyData = m_pdsFactory.create("MINING_DATA_APPLY_V", false); + pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("treeApplyData_jdm", applyData, true); + // 2. Create & save ClassificationApplySettings + clasAS = m_applySettingsFactory.create(); + // Add cost matrix + clasAS.setCostMatrixName(m_costMatrixName); + m_dmeConn.saveObject("treeApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + applyTask = + m_dsApplyFactory.create("treeApplyData_jdm", "treeModel_jdm", + "treeApplySettings_jdm", + "TREE_APPLY_OUTPUT2_JDM"); + saveTask(applyTask, "treeApplyTask2_jdm", "treeBuildTask_jdm"); + + + // 1. Create & save PhysicalDataSpecification + applyData = m_pdsFactory.create("MINING_DATA_APPLY_V", false); + pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("treeApplyData_jdm", applyData, true); + // 2. Create & save ClassificationApplySettings + clasAS = m_applySettingsFactory.create(); + // Add source attributes + sourceAttrMap = new HashMap(); + sourceAttrMap.put("AGE", "AGE"); + sourceAttrMap.put("OCCUPATION", "OCCUPATION"); + clasAS.setSourceDestinationMap(sourceAttrMap); + m_dmeConn.saveObject("treeApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + applyTask = + m_dsApplyFactory.create("treeApplyData_jdm", "treeModel_jdm", + "treeApplySettings_jdm", + "TREE_APPLY_OUTPUT3_JDM"); + saveTask(applyTask, "treeApplyTask3_jdm", "treeBuildTask_jdm"); + + } + + /** + * This method saves the given task with the specified task name and task + * dependency (parent task) in the DME. + * + * @param taskObj task object + * @param taskName name of the task + * @param parentTaskName name of the parent task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static void saveTask(Task taskObj, String taskName, + String parentTaskName) + throws JDMException + { + if (parentTaskName != null) + ((OraTask) taskObj).addDependency(parentTaskName); //Since OJDM 11.1 + //if (!(taskObj instanceof BuildTask)) + ((OraTask) taskObj).overwriteOutput(true); //Since OJDM 11.1 + m_dmeConn.saveObject(taskName, taskObj, true); + } + + /** + * This method monitor task execution initiated by the first task + * in the sequence of dependent tasks. In addition, this method displays + * task output results (if any). + * @throws JDMException + */ + public static void monitorTaskExecutionProcess() + throws JDMException + { + //BuildTask + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of treeBuildTask_jdm. "); + ExecutionStatus buildTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("treeBuildTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(buildTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + displayModelDetails(); + + //If model build is successful, then do testData ApplyTask + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of treeTestApplyTask_jdm. "); + ExecutionStatus testApplyTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("treeTestApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(testApplyTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + //If testdata apply is successful, then wait for its child test metrics tasks + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of treeTestMetricsTask_jdm. "); + ExecutionStatus testTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("treeTestMetricsTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(testTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + displayTestMetrics("dtTestMetrics_jdm", null); + } + else + { + System.out.println("It is at state:" + + testTaskCompletionStatus.getState().name() + + ((testTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + testTaskCompletionStatus.getDescription())); + } + + //TestMetricsTask with cost matrix + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of treeTMWithCostTask_jdm. "); + ExecutionStatus tmCostTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("treeTMWithCostTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(tmCostTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + displayTestMetrics("dtTestMetricsWithCost_jdm", m_costMatrixName); + //If test metrics task is successful, then run the apply tasks + //ApplyTask(s) + //Waiting for all apply tasks to complete + ExecutionStatus applyTask1Status = + m_dmeConn.getLastExecutionHandle("treeApplyTask1_jdm").waitForCompletion(Integer.MAX_VALUE); + ExecutionStatus applyTask2Status = + m_dmeConn.getLastExecutionHandle("treeApplyTask2_jdm").waitForCompletion(Integer.MAX_VALUE); + ExecutionStatus applyTask3Status = + m_dmeConn.getLastExecutionHandle("treeApplyTask3_jdm").waitForCompletion(Integer.MAX_VALUE); + if (ExecutionState.success.equals(applyTask1Status.getState()) && + ExecutionState.success.equals(applyTask2Status.getState()) && + ExecutionState.success.equals(applyTask3Status.getState())) + { + displayApplyResults(); + } + else + { + System.out.println("treeApplyTask1_jdm is at state:" + + applyTask1Status.getState().name() + + ((applyTask1Status.getDescription() == + null)? "": + "State Description:" + applyTask1Status.getDescription())); + System.out.println("treeApplyTask2_jdm is at state:" + + applyTask2Status.getState().name() + + ((applyTask2Status.getDescription() == + null)? "": + "State Description:" + applyTask2Status.getDescription())); + System.out.println("treeApplyTask3_jdm is at state:" + + applyTask3Status.getState().name() + + ((applyTask3Status.getDescription() == + null)? "": + "State Description:" + applyTask3Status.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + tmCostTaskCompletionStatus.getState().name() + + ((tmCostTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + tmCostTaskCompletionStatus.getDescription())); + } + + + } + else + { + System.out.println("It is at state:" + + testApplyTaskCompletionStatus.getState().name() + + ((testApplyTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + testApplyTaskCompletionStatus.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + buildTaskCompletionStatus.getState().name() + + ((buildTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + buildTaskCompletionStatus.getDescription())); + } + } + + public static void trackTaskExecution(String taskName, + ExecutionHandle execHandle) + throws JDMException + { + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = + execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + boolean isTaskSuccess = + status.getState().equals(ExecutionState.success); + if (isTaskSuccess) //Task completed successfully + System.out.println(taskName + " is successful."); + else //Task failed + System.out.println(taskName + " failed.\nFailure Description: " + + status.getDescription()); + } + + private static void displayBuildSettings(ClassificationSettings clasSettings, + String buildSettingsName) + { + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + System.out.println("BuildSettings Details from the " + + buildSettingsName + + " model build settings object:"); + String objName = clasSettings.getName(); + if (objName != null) + System.out.println("Name = " + objName); + String objDescription = clasSettings.getDescription(); + if (objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = clasSettings.getCreationDate(); + String creator = clasSettings.getCreatorInfo(); + String targetAttrName = clasSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = clasSettings.getAlgorithmSettings(); + if (algoSettings == null) + System.out.println("Failure: clasSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if (algo == null) + System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = clasSettings.getMiningFunction(); + if (function == null) + System.out.println("Failure: clasSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + try + { + String costMatrixName = clasSettings.getCostMatrixName(); + if (costMatrixName != null) + { + System.out.println("Cost Matrix Details from the " + + costMatrixName + " table:"); + displayTable(costMatrixName, "", + "order by ACTUAL_TARGET_VALUE, PREDICTED_TARGET_VALUE"); + } + } + catch (Exception jdmExp) + { + System.out.println("Failure: clasSettings.getCostMatrixName()throws exception"); + jdmExp.printStackTrace(); + } + // List of DT algorithm settings + // treeAlgo.setBuildHomogeneityMetric(TreeHomogeneityMetric.gini); + // treeAlgo.setMaxDepth(7); + // ((OraTreeSettings)treeAlgo).setMinDecreaseInImpurity(0.1, SizeUnit.percentage); + // treeAlgo.setMinNodeSize( 0.05, SizeUnit.percentage ); + // treeAlgo.setMinNodeSize( 10, SizeUnit.count ); + // ((OraTreeSettings)treeAlgo).setMinDecreaseInImpurity(20, SizeUnit.count); + TreeHomogeneityMetric homogeneityMetric = + ((OraTreeSettings) algoSettings).getBuildHomogeneityMetric(); + System.out.println("Homogeneity Metric: " + homogeneityMetric.name()); + int intValue = ((OraTreeSettings) algoSettings).getMaxDepth(); + System.out.println("Max Depth: " + intValue); + double doubleValue = + ((OraTreeSettings) algoSettings).getMinNodeSizeForSplit(SizeUnit.percentage); + System.out.println("MinNodeSizeForSplit (percentage): " + + m_df.format(doubleValue)); + doubleValue = + ((OraTreeSettings) algoSettings).getMinNodeSizeForSplit(SizeUnit.count); + System.out.println("MinNodeSizeForSplit (count): " + + m_df.format(doubleValue)); + /* + doubleValue = ((OraTreeSettings)algoSettings).getMinNodeSize(); + SizeUnit unit = ((OraTreeSettings)algoSettings).getMinNodeSizeUnit(); + System.out.println("Min Node Size (" + unit.name() +"): " + m_df.format(doubleValue)); + */ + doubleValue = + ((OraTreeSettings) algoSettings).getMinNodeSize(SizeUnit.count); + System.out.println("Min Node Size (" + SizeUnit.count.name() + "): " + + m_df.format(doubleValue)); + doubleValue = + ((OraTreeSettings) algoSettings).getMinNodeSize(SizeUnit.percentage); + System.out.println("Min Node Size (" + SizeUnit.percentage.name() + + "): " + m_df.format(doubleValue)); + } + + /** + * This method displayes DT model signature. + * + * @param model model object + * @exception JDMException if failed to retrieve model signature + */ + public static void displayModelSignature(Model model) + throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("ModelSignature Deatils: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = + new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[3]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while (attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute) attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println(mfSign.format(vals)); + } + } + + public static void displayModelDetails() + throws JDMException + { + //4. Restore the model from the DME and explore the details of the model + ClassificationModel model = + (ClassificationModel) m_dmeConn.retrieveObject("treeModel_jdm", + NamedObject.model); + // Display model build settings + ClassificationSettings retrievedBuildSettings = + (ClassificationSettings) model.getBuildSettings(); + if (retrievedBuildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, + "treeBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model) model); + // Display model detail + TreeModelDetail treeModelDetails = + (TreeModelDetail) model.getModelDetail(); + displayTreeModelDetailsExtensions(treeModelDetails); + } + + + /** + * This method displayes DT model details. + * + * @param treeModelDetails tree model details object + * @exception JDMException if failed to retrieve model details + */ + public static void displayTreeModelDetailsExtensions(TreeModelDetail treeModelDetails) + throws JDMException + { + System.out.println("\nTreeModelDetail: Model name=" + "treeModel_jdm"); + TreeNode root = treeModelDetails.getRootNode(); + System.out.println("\nRoot node: " + root.getIdentifier()); + + // get the info for the tree model + int treeDepth = ((OraTreeModelDetail) treeModelDetails).getTreeDepth(); + System.out.println("Tree depth: " + treeDepth); + int totalNodes = + ((OraTreeModelDetail) treeModelDetails).getNumberOfNodes(); + System.out.println("Total number of nodes: " + totalNodes); + int totalLeaves = + ((OraTreeModelDetail) treeModelDetails).getNumberOfLeafNodes(); + System.out.println("Total number of leaf nodes: " + totalLeaves); + + Stack nodeStack = new Stack(); + nodeStack.push(root); + while (!nodeStack.empty()) + { + TreeNode node = (TreeNode) nodeStack.pop(); + // display this node + int nodeId = node.getIdentifier(); + long caseCount = node.getCaseCount(); + Object prediction = node.getPrediction(); + int level = node.getLevel(); + int children = node.getNumberOfChildren(); + TreeNode parent = node.getParent(); + System.out.println("\nNode id=" + nodeId + " at level " + level); + if (parent != null) + System.out.println("parent: " + parent.getIdentifier() + + ", children=" + children); + System.out.println("Case count: " + caseCount + ", prediction: " + + prediction); + Predicate predicate = node.getPredicate(); + System.out.println("Predicate: " + predicate.toString()); + Predicate[] surrogates = node.getSurrogates(); + if (surrogates != null) + for (int i = 0; i < surrogates.length; i++) + System.out.println("Surrogate[" + i + "]: " + surrogates[i]); + // add child nodes in the stack + if (children > 0) + { + TreeNode[] childNodes = node.getChildren(); + for (int i = 0; i < childNodes.length; i++) + nodeStack.push(childNodes[i]); + } + } + + TreeNode[] allNodes = treeModelDetails.getNodes(); + System.out.print("\nNode identifiers by getNodes():"); + for (int i = 0; i < allNodes.length; i++) + System.out.print(" " + allNodes[i].getIdentifier()); + System.out.println(); + + // display the node identifiers + int[] nodeIds = treeModelDetails.getNodeIdentifiers(); + System.out.print("Node identifiers by getNodeIdentifiers():"); + for (int i = 0; i < nodeIds.length; i++) + System.out.print(" " + nodeIds[i]); + System.out.println(); + + TreeNode node = treeModelDetails.getNode(nodeIds.length - 1); + System.out.println("Node identifier by getNode(" + + (nodeIds.length - 1) + "): " + + node.getIdentifier()); + Rule rule2 = treeModelDetails.getRule(nodeIds.length - 1); + System.out.println("Rule identifier by getRule(" + + (nodeIds.length - 1) + "): " + + rule2.getRuleIdentifier()); + + // get the rules and display them + Collection ruleColl = treeModelDetails.getRules(); + Iterator ruleIterator = ruleColl.iterator(); + while (ruleIterator.hasNext()) + { + Rule rule = (Rule) ruleIterator.next(); + int ruleId = rule.getRuleIdentifier(); + Predicate antecedent = (Predicate) rule.getAntecedent(); + Predicate consequent = (Predicate) rule.getConsequent(); + System.out.println("\nRULE " + ruleId + ": support=" + + rule.getSupport() + " (abs=" + + rule.getAbsoluteSupport() + "), confidence=" + + rule.getConfidence()); + System.out.println(antecedent); + System.out.println("=======>"); + System.out.println(consequent); + } + } + + public static void displayTestMetrics(String metricsName, + String costMatrixName) + throws JDMException + { + if (costMatrixName != null) + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using apply output table ---"); + System.out.println("--- - using cost matrix table ---"); + System.out.println("---------------------------------------------------"); + } + else + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using apply output table ---"); + System.out.println("--- - using no cost matrix table ---"); + System.out.println("---------------------------------------------------"); + } + // Restore & display test metrics + ClassificationTestMetrics testMetrics = + (ClassificationTestMetrics) m_dmeConn.retrieveObject(metricsName, + NamedObject.testMetrics); + // Display classification test metrics + displayTestMetricDetails(testMetrics); + } + + /** + * Display classification test metrics object + * + * @param testMetrics classification test metrics object + * @exception JDMException if failed to retrieve test metric details + */ + public static void displayTestMetricDetails(ClassificationTestMetrics testMetrics) + throws JDMException + { + // Retrieve Oracle ABN model test metrics deatils extensions + // Test Metrics Name + System.out.println("Test Metrics Name = " + testMetrics.getName()); + // Model Name + System.out.println("Model Name = " + testMetrics.getModelName()); + // Test Data Name + System.out.println("Test Data Name = " + + testMetrics.getTestDataName()); + // Accuracy + System.out.println("Accuracy = " + + m_df.format(testMetrics.getAccuracy().doubleValue())); + // Confusion Matrix + ConfusionMatrix confusionMatrix = testMetrics.getConfusionMatrix(); + Collection categories = confusionMatrix.getCategories(); + Iterator xIterator = categories.iterator(); + System.out.println("Confusion Matrix: Accuracy = " + + m_df.format(confusionMatrix.getAccuracy())); + System.out.println("Confusion Matrix: Error = " + + m_df.format(confusionMatrix.getError())); + System.out.println("Confusion Matrix:( Actual, Prection, Value )"); + MessageFormat mf = + new MessageFormat(" ( {0}, {1}, {2} )"); + String[] vals = new String[3]; + while (xIterator.hasNext()) + { + Object actual = xIterator.next(); + vals[0] = actual.toString(); + Iterator yIterator = categories.iterator(); + while (yIterator.hasNext()) + { + Object predicted = yIterator.next(); + vals[1] = predicted.toString(); + long number = + confusionMatrix.getNumberOfPredictions(actual, predicted); + vals[2] = Long.toString(number); + System.out.println(mf.format(vals)); + } + } + // Lift + Lift lift = ((OraClassificationTestMetrics)testMetrics).getLift("1"); + System.out.println("Lift Details:"); + System.out.println("Lift: Target Attribute Name = " + + lift.getTargetAttributeName()); + System.out.println("Lift: Positive Target Value = " + + lift.getPositiveTargetValue()); + System.out.println("Lift: Total Cases = " + lift.getTotalCases()); + System.out.println("Lift: Total Positive Cases = " + + lift.getTotalPositiveCases()); + int numberOfQuantiles = lift.getNumberOfQuantiles(); + System.out.println("Lift: Number Of Quantiles = " + numberOfQuantiles); + System.out.println("Lift: ( QUANTILE_NUMBER, TOTAL_CASES, QUANTILE_PERCENT_SIZE, POSITIVE_CASES, NEGATIVE_CASES, PROBABILITY_THRESHOLD, LIFT, CUMULATIVE_LIFT, GAIN, CUMULATIVE_GAIN, TARGET_DENSITY, CUMULATIVE_TARGET_DENSITY)"); + MessageFormat mfLift = + new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10} )"); + double[] totalCasesPerQuantile = ((OraLift)lift).getCases();//Total cases per quantile + double[] quantilePercentageSize = ((OraLift)lift).getPercentageSize();//Quantile pecentage size + double[] positiveCasesPerQuantile = ((OraLift)lift).getNumberOfPositiveCases();//Positive target cases per quantile + double[] negativeCasesPerQuantile = ((OraLift)lift).getNumberOfNegativeCases();//Negative target cases per quantile + double[] probabilityOrCostThresholdPerQuantile = ((OraLift)lift).getProbabilityOrCostThreshold();//Probability or cost threshold per quantile + double[] liftPerQuantile = ((OraLift)lift).getLift();//Lift values for all quantiles + double[] targetDensityPerQuantile = ((OraLift)lift).getTargetDensity();//Target densities per quantile + + double[] cumulativeLift = ((OraLift)lift).getCumulativeLift(); + double[] cumulativeGain = ((OraLift)lift).getCumulativeGain(); + double[] cumulativeTargetDensity = ((OraLift)lift).getCumulativeTargetDensity(); + + + + String[] messageParams = new String[11]; + + for (int iQuantile = 0; iQuantile < numberOfQuantiles; iQuantile++) + { + //Assign message parameters + messageParams[0] = Integer.toString(iQuantile+1); //QUANTILE_NUMBER + messageParams[1] = m_df.format(totalCasesPerQuantile[iQuantile]); //TOTAL_CASES + messageParams[2] = m_df.format(quantilePercentageSize[iQuantile]);//QUANTILE_PERCENT_SIZE + messageParams[3] = m_df.format(positiveCasesPerQuantile[iQuantile]); //POSITIVE_CASES + messageParams[4] = m_df.format(negativeCasesPerQuantile[iQuantile]); //NEGATIVE_CASES + messageParams[5] = m_df.format(probabilityOrCostThresholdPerQuantile[iQuantile]); //PROBABILITY_THRESHOLD + messageParams[6] = m_df.format(liftPerQuantile[iQuantile]); //LIFT + messageParams[7] = m_df.format(cumulativeLift[iQuantile]); //CUMULATIVE_LIFT + messageParams[8] = m_df.format(cumulativeGain[iQuantile]); //CUMULATIVE_GAIN + messageParams[9] = m_df.format(targetDensityPerQuantile[iQuantile]); //TARGET_DENSITY + messageParams[10] = m_df.format(cumulativeTargetDensity[iQuantile]); //CUMULATIVE_TARGET_DENSITY + System.out.println(mfLift.format(messageParams)); + } + // ROC + ReceiverOperatingCharacterics roc = ((OraClassificationTestMetrics)testMetrics).getROC("1"); + System.out.println("ROC Details:"); + System.out.println("ROC: Area Under Curve = " + + m_df.format(roc.getAreaUnderCurve())); + int nROCThresh = roc.getNumberOfThresholdCandidates(); + System.out.println("ROC: Number Of Threshold Candidates = " + + nROCThresh); + System.out.println("ROC: ( INDEX, PROBABILITY, TRUE_POSITIVES, FALSE_NEGATIVES, FALSE_POSITIVES, TRUE_NEGATIVES, TRUE_POSITIVE_FRACTION, FALSE_POSITIVE_FRACTION )"); + MessageFormat mfROC = + new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7} )"); + String[] rocVals = new String[8]; + for (int iROC = 1; iROC <= nROCThresh; iROC++) + { + rocVals[0] = Integer.toString(iROC); //INDEX + rocVals[1] = + m_df.format(roc.getProbabilityThreshold(iROC)); //PROBABILITY + rocVals[2] = + Long.toString(roc.getPositives(iROC, true)); //TRUE_POSITIVES + rocVals[3] = + Long.toString(roc.getNegatives(iROC, false)); //FALSE_NEGATIVES + rocVals[4] = + Long.toString(roc.getPositives(iROC, false)); //FALSE_POSITIVES + rocVals[5] = + Long.toString(roc.getNegatives(iROC, true)); //TRUE_NEGATIVES + rocVals[6] = + m_df.format(roc.getHitRate(iROC)); //TRUE_POSITIVE_FRACTION + rocVals[7] = + m_df.format(roc.getFalseAlarmRate(iROC)); //FALSE_POSITIVE_FRACTION + System.out.println(mfROC.format(rocVals)); + } + } + + public static void displayApplyResults() + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Business case 1 ---"); + System.out.println("--- Find the 10 customers who live in Italy ---"); + System.out.println("--- that are least expensive to be convinced to ---"); + System.out.println("--- use an affinity card. ---"); + System.out.println("---------------------------------------------------"); + // 4. Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + // + // Find the 10 customers who live in Italy that are least expensive to be + // convinced to use an affinity card. + displayTable("TREE_APPLY_OUTPUT1_JDM", + "where COUNTRY_NAME='Italy' and ROWNUM < 11 ", + "order by COST"); + + System.out.println("---------------------------------------------------"); + System.out.println("--- Business case 2 ---"); + System.out.println("--- List ten customers (ordered by their id) ---"); + System.out.println("--- along with likelihood and cost to use or ---"); + System.out.println("--- reject the affinity card. ---"); + System.out.println("---------------------------------------------------"); + // 4. Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + // + // List ten customers (ordered by their id) along with likelihood and cost + // to use or reject the affinity card (Note: while this example has a + // binary target, such a query is useful in multi-class classification - + // Low, Med, High for example). + displayTable("TREE_APPLY_OUTPUT2_JDM", "where ROWNUM < 21", + "order by CUST_ID, PREDICTION"); + + System.out.println("---------------------------------------------------"); + System.out.println("--- Business case 3 ---"); + System.out.println("--- Find the customers who work in Tech support ---"); + System.out.println("--- and are under 25 who is going to response ---"); + System.out.println("--- to the new affinity card program. ---"); + System.out.println("---------------------------------------------------"); + // 4. Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + // + // Find the customers who work in Tech support and are under 25 who is + // going to response to the new affinity card program. + displayTable("TREE_APPLY_OUTPUT3_JDM", + "where OCCUPATION = 'TechSup' " + "and AGE < 25 " + + "and PREDICTION = 1 ", "order by CUST_ID"); + } + + private static void displayTable(String tableName, String whereCause, + String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = + dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + //Build table header + for (int iCol = 1; iCol <= colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + //Write table data + while (rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for (int iCol = 1; iCol <= colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if (obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal) obj; + if (bd.scale() > 5) + { + colContent = m_df.format(obj); + } + else + { + colContent = bd.toString(); + } + } + catch (Exception anyExp) + { + colContent = m_df.format(obj); + } + } + else + { + if (obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + + rowContent.append(" " + + emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } + catch (Exception anySqlExp) + { + anySqlExp.printStackTrace(); + } //Ignore + } + + private static void clean() + { + //Drop the model + try + { + m_dmeConn.removeObject("treeModel_jdm", NamedObject.model); + } + catch (Exception jdmExp) + { + } + } +} diff --git a/dmtxtfe.sql b/dmtxtfe.sql new file mode 100644 index 0000000..755a87e --- /dev/null +++ b/dmtxtfe.sql @@ -0,0 +1,208 @@ +Rem +Rem $Header: dmtxtfe.sql 12-jul-2005.07:43:16 ktaylor Exp $ +Rem +Rem textfe.sql +Rem +Rem Copyright (c) 2003, 2005, Oracle. All rights reserved. +Rem +Rem NAME +Rem textfe.sql - Oracle TEXT Term (or Feature) Extractor +Rem +Rem DESCRIPTION +Rem This script demonstrates a means to extract terms for +Rem text mining from Oracle Text documents (i.e. CLOB or +Rem VARCHAR2 columns containing text documents) using a Text +Rem Index built on those documents. +Rem +Rem For more information on term extraction for text mining, +Rem see Oracle Data Mining Application Developer's Guide. +Rem +Rem This program uses the following schema object: +Rem +Rem . BUILD_TEXT_IDX - the Oracle Text Index built +Rem on MINING_BUILD_TEXT. Please see rdbms/demo/dmsh.sql +Rem to see how MINING_BUILD_TEXT is constructed from +Rem data from the Sample Schema. +Rem +Rem Given this Text Index, the program demonstrates how to +Rem extract terms from the documents using the Text Index. +Rem The terms are generated in an output table in the multi-record +Rem case format - i.e. in the form +Rem (sequence_id, attribute_name, attribute_value) +Rem +Rem This output table can then be used to generate a nested table +Rem column (DM_Nested_Numerical) in the final table that represents +Rem the training data that is to be used for model creation, or the +Rem scoring table that is to be used for model scoring. +Rem +Rem Simply put, terms extracted from text documents will become +Rem generic attributes in training or scoring data. This data can +Rem then be classified, clustered or feature-extracted using the +Rem DBMS_DATA_MINING package. +Rem +Rem Since the number of attributes (i.e. the terms) is typically +Rem greater than 1000, these attributes are composed into a nested +Rem column in the input table. +Rem +Rem The goal of this program is to enable users to build their +Rem own term extractors, given a document table with a text index +Rem built on the documents. +Rem +Rem NOTES +Rem +Rem MODIFIED (MM/DD/YY) +Rem ktaylor 07/12/05 - minor edits to comments +Rem ramkrish 10/28/04 - cleanup/comments +Rem ramkrish 09/16/04 - update for 10gR2 +Rem xbarr 06/25/04 - xbarr_dm_rdbms_migration +Rem ramkrish 02/06/04 - fix nested table +Rem ramkrish 12/09/03 - explain the steps with comments +Rem cbhagwat 11/11/03 - NMF_CLUSTERING to SVM_CLASSIFICATION +Rem cbhagwat 10/06/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +-- Cleanup for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE txt_sample_pref_terms'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE txt_sample_tf_out'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE txt_sample_term_out'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE txt_sample_terms'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE txt_sample_text_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE txt_sample_data_input'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nontxt_attrib'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN CTX_DDL.DROP_PREFERENCE(preference_name => 'txt_sample_pref'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Step 1. The sample Text document table is MINING_BUILD_TEXT +-- This table is constructed when you run rdbms/demo/dmsh.sql. + +-- Step 2. The sample Text Index is BUILD_TEXT_INDEX +-- This index is also constructed when you run rdbms/demo/dmsh.sql + +-- Given the presence of these two schema objects, you can now +-- proceed to extract terms from text documents in MINING_BUILD_TEXT +-- using the following steps: + +-- Step 3. Create preferences for Text term extraction +-- (This routine must be used exclusively with ODM; +-- it is a public, but undocumented, routine in Oracle10g) +-- +BEGIN CTX_DDL.CREATE_PREFERENCE('txt_sample_pref', 'SVM_CLASSIFIER'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +-- Step 4. Define an ancillary table for categories +-- (required to execute preference choices) +-- +CREATE TABLE txt_sample_text_cat (id NUMBER, cat NUMBER) +/ + +-- Step 5. Extract terms set up by preference into intermediate terms tables +-- 1. txt_sample_term_out - terms set by preference +-- 2. txt_sample_pref_terms - term definitions +-- +-- The parameters are: +-- 'BUILD_TEXT_IDX', -- index_name - Text index name +-- 'CUST_ID', -- doc_id - the case-id +-- 'txt_sample_text_cat', -- cattab - category table name +-- 'id', -- catdocid - docid for category tab +-- 'cat', -- catid - category id +-- 'txt_sample_pref_terms', -- restab - term definitions +-- 'txt_sample_pref' -- preference - Text preference name +-- +CREATE TABLE txt_sample_term_out AS +SELECT * + FROM TABLE(ctxsys.drvodm.feature_prep ( + 'BUILD_TEXT_IDX', + 'CUST_ID', + 'txt_sample_text_cat', + 'id', + 'cat', + 'txt_sample_pref_terms', + 'txt_sample_pref')); + +-- At the end of this step: +-- . txt_sample_term_out has the schema +-- (sequence_id, value) +-- sequence_id contains the values of CUST_ID, the case identifier +-- column in MINING_BUILD_TEXT. +-- + +-- Step 6. Explain the terms in the intermediate tables to generate +-- the final terms table. This table will contain the text +-- elements that can be used as attributes for mining. +-- (This drvodm routine must be used exclusively with ODM; +-- it is a public, but undocumented, routine in Oracle10g) +-- +CREATE TABLE txt_sample_terms AS +SELECT A.sequence_id, B.text, A.value + FROM txt_sample_term_out A, + TABLE(ctxsys.drvodm.feature_explain( + 'txt_sample_pref_terms')) B + WHERE A.attribute_id = B.id; + +-- Step 7. (Optional) Display the extracted terms +-- +column text format a45 +SELECT * + FROM (SELECT sequence_id,text,value + FROM txt_sample_terms + ORDER BY sequence_id, text) + WHERE ROWNUM < 10; + +-- Step 8. Now, assume that you have a table containing training data +-- with non-text attributes, with matching sequence ids +-- (i.e. matching values of CUST_ID). +-- +-- See MINING_BUILD_TEXT in rdbms/demo/dmsh.sql as an example +-- +-- Add the text mining attributes to this table as a nested table, +-- as shown below. +-- + +-- Just for the sake of this demo, create a dummy table with +-- NULL non-text attributes, using txt_sample_terms itself as +-- the source (to prepare a table with matching case-id's) +-- In an actual scenario, the non-text columns may be +-- projected from a different table. +-- +CREATE TABLE nontxt_attrib AS +SELECT A.sequence_id case_id, 1 age, 1 salary, 1 class + FROM txt_sample_terms A; + +-- You can now create the mining data input table (or a view) +-- with text and non-text attributes as follows: +-- +CREATE TABLE txt_sample_data_input + NESTED TABLE txt_terms STORE AS txt_terms AS +SELECT N.*, + CAST(MULTISET( + SELECT DM_Nested_Numerical (T.text, T.value) + FROM txt_sample_terms T + WHERE N.case_id = T.sequence_id) + AS DM_Nested_Numericals) txt_terms + FROM nontxt_attrib N; + +-- Step 9. Read rdbms/demo/dmsh.sql to revise the above steps +-- in the context of an end-to-end demo of Text Mining. +-- dmsh.sql performs all of the steps discussed above, +-- against tables in the Sample Schema. The text data +-- prepared in this manner can be classified using +-- dmtxtsvm.sql, or feature extracted using dmtxtnmf.sql. diff --git a/dmtxtnmf.sql b/dmtxtnmf.sql new file mode 100644 index 0000000..c055874 --- /dev/null +++ b/dmtxtnmf.sql @@ -0,0 +1,158 @@ +Rem +Rem $Header: dmtxtnmf.sql 25-oct-2007.11:34:46 ramkrish Exp $ +Rem +Rem nmfdemo.sql +Rem +Rem Copyright (c) 2003, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmtxtnmf.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a text mining model +Rem using non-negative matrix factorization. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem ktaylor 07/12/05 - minor edits to comments +Rem ramkrish 10/28/04 - cleanup/comments +Rem amozes 07/30/04 - format coefficient +Rem xbarr 06/25/04 - xbarr_dm_rdbms_migration +Rem cbhagwat 10/17/03 - feature_extraction +Rem cbhagwat 10/13/03 - cbhagwat_txn109175 +Rem cbhagwat 10/10/03 - fix +Rem cbhagwat 10/08/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Mine the text features extracted using dmtxtfe.sql using NMF +-- algorithm. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- +-- See dmtxtfe.sql. Note that the text features are input here +-- through a nested table. + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old model and objects for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('T_NMF_Sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE t_nmf_sample_norm'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW t_nmf_sample_build_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- +BEGIN + -- Create a normalization table + DBMS_DATA_MINING_TRANSFORM.CREATE_NORM_LIN ( + norm_table_name => 't_nmf_sample_norm'); + + -- Normalize appropriate columns + DBMS_DATA_MINING_TRANSFORM.INSERT_NORM_LIN_MINMAX ( + norm_table_name => 't_nmf_sample_norm', + data_table_name => 'mining_build_nested_text', + exclude_list => dbms_data_mining_transform.column_list ( + 'AFFINITY_CARD', + 'BULK_PACK_DISKETTES', + 'FLAT_PANEL_MONITOR', + 'HOME_THEATER_PACKAGE', + 'BOOKKEEPING_APPLICATION', + 'PRINTER_SUPPLIES', + 'Y_BOX_GAMES', + 'OS_DOC_SET_KANJI', + 'cust_id', + 'comments'), + round_num => 0 + ); + + -- Create the transformed view + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 't_nmf_sample_norm', + data_table_name => 'mining_build_nested_text', + xform_view_name => 't_nmf_sample_build_prepared'); +END; +/ +-- NMFS settings (For info only) +-- insert into nmfs_settings values +--(dbms_data_mining.nmfs_conv_tolerance,0.05); +--(dbms_data_mining.nmfs_num_iterations,50); +--(dbms_data_mining.nmfs_random_seed,-1); +--(dbms_data_mining.nmfs_stop_criteria,dbms_data_mining.nmfs_sc_iter_or_conv); + +--------------------- +-- CREATE A NEW MODEL +-- +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'T_NMF_Sample', + mining_function => dbms_data_mining.feature_extraction, + data_table_name => 't_nmf_sample_build_prepared', + case_id_column_name => 'cust_id'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30; +column setting_value format a30; +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'T_NMF_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'T_NMF_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +column attribute_name format a30; +column attribute_value format a20; +column coefficient format 9.99999; +set pages 15; +SET line 120; +break ON feature_id; + +SELECT t.feature_id, + a.attribute_name, + a.attribute_value, + a.coefficient + FROM TABLE(dbms_data_mining.get_model_details_nmf('T_NMF_Sample')) t, + TABLE(t.attribute_set) a +WHERE feature_id < 3 +ORDER BY 1,2,3,4; + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- +-- See dmnmdemo.sql for examples. The key difference here +-- is the nested table input, and you can adapt that sample +-- code to accept the table with a nested table column as +-- input. diff --git a/dmtxtnmfdemo.java b/dmtxtnmfdemo.java new file mode 100644 index 0000000..6201ccf --- /dev/null +++ b/dmtxtnmfdemo.java @@ -0,0 +1,843 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmtxtnmfdemo.java + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to build and apply a feature extraction model using the non-negative matrix +* factorization (NMF) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Given demographic data about a set of customers, extract features +* from the given dataset with text mining. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created +* in the user schema using CUSTOMERS, COUNTRIES, and SUPPLIMENTARY_DEMOGRAPHICS +* tables. +* +* MINING_BUILD_TEXT: +* This view collects the previous customers' comments(text), demographics, +* purchasing details, and affinity card response details for building the model. +* +* MINING_APPLY_TEXT: +* This view collects the prospective customers' comments(text), demographics, +* and purchasing details for predicting response to the new affinity card +* program. +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* In general, attributes need to be of similar scale in order to be treated +* equally during the model build. Therefore normalization is required. +* The prepareData() method illustrates the normalization of the build and apply +* data. +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a feature extraction model using the NMF algorithm. +* Apply Model: +* For a descriptive mining function like feature extraction, "scoring" +* involves providing the probability values for each feature. +* During model apply, an NMF model maps the original data into the +* new set of attributes (features) discovered by the model. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic api imports +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.DecimalFormat; +import java.text.MessageFormat; +import java.util.Collection; +import java.util.Iterator; +// Java Data Mining (JDM) standard imports +import java.util.Map; +import java.util.TreeMap; +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.resource.Connection; +import javax.datamining.resource.ConnectionFactory; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.algorithm.nmf.OraNMFAlgorithmSettingsFactory; +import oracle.dmt.jdm.algorithm.nmf.OraNMFAlgorithmSettings; +import oracle.dmt.jdm.featureextraction.OraFeature; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionApplySettings; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionApplySettingsFactory; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionModel; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionSettings; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionSettingsFactory; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransform; +import oracle.dmt.jdm.transform.normalize.OraNormalizeType; +import oracle.dmt.jdm.transform.text.OraTextTransform; +import oracle.dmt.jdm.transform.text.OraTextTransformFactory; + + +public class dmtxtnmfdemo extends Object{ + //Connection related data members + private static Connection m_dmeConn; + private static ConnectionFactory m_dmeConnFactory; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static OraFeatureExtractionSettingsFactory m_feSettingFactory; + private static OraNMFAlgorithmSettingsFactory m_feAlgFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static OraFeatureExtractionApplySettingsFactory m_applySettingsFactory; + private static OraTextTransformFactory m_textXformFactory; + private static OraNormalizeTransformFactory m_normalizeXformFactory; + private static OraTransformationTaskFactory m_xformTaskFactory; + // Global constants used for formatting output + private static String UNDERLINE = "*************************************"; + private static String TAB = " "; + private static char SPACE = ' '; + private static int SECOND_COLUMN = 40; + private static int THIRD_COLUMN = 70; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + private static boolean displayModelDeatils = false;//By default it is set to false. To view the details of the model this flag can be enabled + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmtxtnmfdemo "); + System.out.println(" or: java dmtxtnmfdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + //1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Prepare data + prepareData(); + // 5. Build a model + buildModel(); + // 6. Apply the model + applyModel(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 7. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { }//Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_feSettingFactory = (OraFeatureExtractionSettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.featureextraction.OraFeatureExtractionSettings"); + m_feAlgFactory = (OraNMFAlgorithmSettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.algorithm.nmf.OraNMFAlgorithmSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = (OraFeatureExtractionApplySettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.featureextraction.OraFeatureExtractionApplySettings"); + m_normalizeXformFactory = (OraNormalizeTransformFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.normalize.OraNormalizeTransform"); + m_textXformFactory = (OraTextTransformFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.text.OraTextTransform"); + m_xformTaskFactory = (OraTransformationTaskFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.task.OraTransformationTask"); + } + + /** + * This method illustrates preparation of the data for the build and apply + * operations by using normalization transformation. + * + * Here numerical attribute AGE is prepared using default normalization + * which is min-max normalization. The values for shift and scale are computed + * to be shift = min, and scale = (max - min) respectively. + * + * COLUMN_NAME DATA_TYPE DISTINCT NORMALIZING + * ------------------ --------- -------- ----------- + * CUST_ID NUMBER 1500 + * CUST_GENDER CHAR 2 + * AGE NUMBER 66 MINMAX + * CUST_MARITAL_STATUS VARCHAR2 7 + * COUNTRY_NAME VARCHAR2 19 + * CUST_INCOME_LEVEL VARCHAR2 12 + * EDUCATION VARCHAR2 16 + * OCCUPATION VARCHAR2 15 + * HOUSEHOLD_SIZE VARCHAR2 6 + * YRS_RESIDENCE NUMBER 15 MINMAX + * AFFINITY_CARD NUMBER 2 + * BULK_PACK_DISKETTES NUMBER 2 + * FLAT_PANEL_MONITOR NUMBER 2 + * HOME_THEATER_PACKAGE NUMBER 2 + * BOOKKEEPING_APPLICATION NUMBER 2 + * PRINTER_SUPPLIES NUMBER 1 + * Y_BOX_GAMES NUMBER 2 + * OS_DOC_SET_KANJI NUMBER 2 + * OS_DOC_SET_KANJI NUMBER 2 + * CPMMENTS VARCHAR2(4000) 44 + * + * The following views are created after the execution of this method. + * + * Unprepared Data ---> Prepared(Normalized) Data + * ------------------------ --------------------------- + * MINING_BUILD_TEXT TXTNMF_NORM_DATA_BUILD_JDM + * MINING_APPLY_TEXT TXTNMF_NORM_DATA_APPLY_JDM + * + * @exception JDMException if data preparation failed + */ + public static void prepareData() throws JDMException + { + boolean isOutputAsView = false; + String inputDataURI = null; + String outputDataURI = null; + String inputNormalizationDefinitionTable = null; + OraTransformationTask xformTask = null; + //------------------------------------------------------------------------ + // 1. Prepare build data + //------------------------------------------------------------------------ + // Text Transformation - Convert text column into a nested column in order + // to perform text mining + isOutputAsView = false; + inputDataURI = "MINING_BUILD_TEXT"; + outputDataURI = "TXTNMF_BUILD_NESTED_TEXT"; + String caseId = "CUST_ID"; + String[] textColumnList = {"COMMENTS"}; + OraTextTransform textDataXform = + (OraTextTransform)m_textXformFactory.create( + inputDataURI, outputDataURI, caseId, textColumnList); + xformTask = m_xformTaskFactory.create(textDataXform); + executeTask(xformTask, "txtnmfPrepareTextB_jdm"); + // Normalization + isOutputAsView = true; + inputDataURI = "TXTNMF_BUILD_NESTED_TEXT"; + outputDataURI = "TXTNMF_NORM_DATA_BUILD_JDM"; + OraNormalizeType normalizeType = OraNormalizeType.min_max; + Integer roundingNumber = new Integer(0); + OraNormalizeTransform buildDataXform = + (OraNormalizeTransform)m_normalizeXformFactory.create( + inputDataURI, outputDataURI, isOutputAsView, + normalizeType, roundingNumber); + String[] excludeColumnList = { + "CUST_ID", + "AFFINITY_CARD", + "BULK_PACK_DISKETTES", + "FLAT_PANEL_MONITOR", + "HOME_THEATER_PACKAGE", + "BOOKKEEPING_APPLICATION", + "PRINTER_SUPPLIES", + "Y_BOX_GAMES", + "OS_DOC_SET_KANJI", + "COMMENTS" + }; + buildDataXform.setExcludeColumnList(excludeColumnList); + xformTask = m_xformTaskFactory.create(buildDataXform); + executeTask(xformTask, "txtnmfPrepareBuild_jdm"); + //------------------------------------------------------------------------ + // 2. Prepare apply data + //------------------------------------------------------------------------ + // Text Transformation - Convert text column into a nested column in order + // to perform text mining + isOutputAsView = false; + inputDataURI = "MINING_APPLY_TEXT"; + outputDataURI = "TXTNMF_APPLY_NESTED_TEXT"; + caseId = "CUST_ID"; + textColumnList = new String[] {"COMMENTS"}; + //Get feature tables created by the build text transformation + OraTransformationTask buildTextXformTask = (OraTransformationTask)m_dmeConn.retrieveObject( + "txtnmfPrepareTextB_jdm", NamedObject.task); + String[] buildFeatureTables = ((OraTextTransform)buildTextXformTask.getTransformation()).getFeatureTables(); + textDataXform = + (OraTextTransform)m_textXformFactory.create( + inputDataURI, outputDataURI, caseId, textColumnList, + buildFeatureTables); + xformTask = m_xformTaskFactory.create(textDataXform); + executeTask(xformTask, "txtnmfPrepareTextA_jdm"); + // Normalization + isOutputAsView = true; + inputDataURI = "TXTNMF_APPLY_NESTED_TEXT"; + outputDataURI = "TXTNMF_NORM_DATA_APPLY_JDM"; + inputNormalizationDefinitionTable = buildDataXform.getNormalizationDefinitionTable(); + OraNormalizeTransform applyDataXform = + (OraNormalizeTransform)m_normalizeXformFactory.create( + inputDataURI, outputDataURI, isOutputAsView, inputNormalizationDefinitionTable); + xformTask = m_xformTaskFactory.create(applyDataXform); + executeTask(xformTask, "txtnmfPrepareApply_jdm"); + } + + /** + * This method illustrates how to build a mining model using the + * "TXTNMF_NORM_DATA_BUILD_JDM" dataset with the NMF algorithm. + * + * After completing the build task, the model named "txtnmfModel_jdm" will + * be created. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = m_pdsFactory.create("TXTNMF_NORM_DATA_BUILD_JDM", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("txtnmfBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + //Create NMF algorithm settings + OraNMFAlgorithmSettings nmfAlgo = + (OraNMFAlgorithmSettings)m_feAlgFactory.create(); + // Examples settings are: + // nmfAlgo.setMaxNumberOfIterations(10); + // nmfAlgo.setMinConvergenceTolerance(0.05); + // nmfAlgo.setSeedValue(-1); + // + // Create OraFeatureExtractionSettings + OraFeatureExtractionSettings buildSettings = m_feSettingFactory.create(); + buildSettings.setAlgorithmSettings(nmfAlgo); + buildSettings.setNumberOfFeatures(10); + m_dmeConn.saveObject("txtnmfBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "txtnmfBuildData_jdm", //Build data specification + "txtnmfBuildSettings_jdm", //Mining function settings name + "txtnmfModel_jdm" //Mining model name + ); + buildTask.setDescription("txtnmfBuildTask_jdm"); + executeTask(buildTask, "txtnmfBuildTask_jdm"); + // 4. Restore the model from the DME and explore the details of the model + OraFeatureExtractionModel model = (OraFeatureExtractionModel) + m_dmeConn.retrieveObject("txtnmfModel_jdm", NamedObject.model); + + // Display model build settings + OraFeatureExtractionSettings retrievedBuildSettings = + (OraFeatureExtractionSettings)model.getBuildSettings(); + if(buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "txtnmfBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + // Display model details + if(displayModelDeatils) + displayFEModelDetails(model); + } + + /** + * The Apply operation is performed by a task that requires the location of + * the dataset, the model name, the output specification, and the location + * of the output. + * + * The output table "nmf_apply_output_jdm" is specified by a MiningApplyOutput + * object to contain the feature identifier and the match quality for feature + * extraction models. + * + * In this example, the NMF model is applied with the + * "TXTNMF_NORM_DATA_APPLY_JDM" prepared dataset to obtain the feature + * identifier and the match quality. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "TXTNMF_NORM_DATA_APPLY_JDM", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "txtnmfNMFData_jdm", applyData, true ); + // 2. Create & save FeatureExtractionApplySettings + OraFeatureExtractionApplySettings feAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "txtnmfApplySettings_jdm", feAS, true); + + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "txtnmfNMFData_jdm", "txtnmfModel_jdm", "txtnmfApplySettings_jdm", + "TXTNMF_APPLY_OUTPUT_JDM"); + executeTask(applyTask, "txtnmfApplyTask_jdm"); + // 4. Display apply result -- the first 10 rows + displayTable("TXTNMF_APPLY_OUTPUT_JDM", + "where ROWNUM < 11", + "order by CUST_ID"); + } + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints the error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static boolean executeTask(Task taskObj, String taskName) throws JDMException + { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful."); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() ); + } + return isTaskSuccess; + } + + private static void displayBuildSettings( + OraFeatureExtractionSettings featureSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " model build settings object:"); + String objName = featureSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = featureSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = featureSettings.getCreationDate(); + String creator = featureSettings.getCreatorInfo(); + AlgorithmSettings algoSettings = featureSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: featureSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = featureSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: featureSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + // List of NMF algorithm settings + long intValue = ((OraNMFAlgorithmSettings)algoSettings).getMaxNumberOfIterations(); + System.out.println("Max Number Of Iterations: " + intValue); + double doubleValue = ((OraNMFAlgorithmSettings)algoSettings).getMinConvergenceTolerance(); + System.out.println("Min Convergence Tolerance: " + m_df.format(doubleValue)); + intValue = ((OraNMFAlgorithmSettings)algoSettings).getSeedValue(); + System.out.println("Seed Value: " + intValue); + intValue = featureSettings.getNumberOfFeatures(); + System.out.println("Number Of Features: " + intValue); + } + + /** + * This method displayes the NMF model signature. + * + * @param model model object + * @exception JDMException + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + // Display the first 10 rows only + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + + /****************************************************************/ + // this part of code sorts the columns by name + // to get the deterministic order of columns + // this code can be omitted otherwise + // sort the attributes by name + TreeMap treeMap = new TreeMap(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute) attrIterator.next(); + String attrName = attr.getName(); + treeMap.put( attrName, attr ); + } + Collection sortedSig = treeMap.values(); + attrIterator = sortedSig.iterator(); + /****************************************************************/ + + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + + /****************************************************************/ + // this part of code sorts the columns by name + // to get the deterministic order of columns + // this code can be omitted otherwise + TreeMap treeMap = new TreeMap(); + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + treeMap.put( colName, new Integer(iCol) ); + } + Collection colColl = treeMap.values(); + int[] colIndex = new int[colCount]; + Iterator colIt = colColl.iterator(); + for( int i=0; colIt.hasNext(); i++ ) + { + Integer index = (Integer) colIt.next(); + colIndex[i] = index.intValue(); + } + /****************************************************************/ + + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName( colIndex[iCol-1] ); + // if no ordering is needed (with the above code block omitted), + // this line can be used + // String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while(rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType( colIndex[iCol-1] ); + Object obj = rs.getObject( colIndex[iCol-1] ); + // if no ordering is needed (with the above code block omitted), + // the following two lines can be used + // int sqlType = rsMeta.getColumnType(iCol); + // Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + /** + * Each feature is a linear combination of the original attribute set; + * the coefficients of these linear combinations are non-negative. + * The model details return for each feature the coefficients + * associated with each one of the original attributes. Categorical + * attributes are described by (attribute_name, attribute_value) pairs. + * That is, for a given feature, each distinct value of a categorical + * attribute has its own coefficient. + * + * @param model model to be presented + * @exception JDMException if failed to retrieve model details + */ + public static void displayFEModelDetails(OraFeatureExtractionModel model) throws JDMException + { + System.out.println(UNDERLINE+"\n"+"NMF model details"+"\n"+UNDERLINE+"\n"); + System.out.println("\n"+TAB+"Listing all features:\n"+UNDERLINE); + Collection features = model.getFeatures(); + if ( features == null ){ + System.out.println(TAB+TAB+"Error printing features."); + return; + } + + /****************************************************************/ + // this part of code sorts the features by id + // to get the deterministic order of features + // this code can be omitted otherwise + // use tree map to sort the features/attributes for determinstic results + OraFeature sampleFeature = null; + Iterator it = features.iterator(); + + TreeMap treeMap = new TreeMap(); + while( it.hasNext() ) + { + OraFeature feature = (OraFeature)it.next(); + int featureId = feature.getFeatureIdentifier(); + treeMap.put( new Integer(featureId), feature ); + } + Collection featuresOrdered = treeMap.values(); + it = featuresOrdered.iterator(); + /****************************************************************/ + + while ( it.hasNext() ){ + OraFeature feature = (OraFeature)it.next(); + printFeature(feature); + if ( sampleFeature == null ) + sampleFeature = feature; + } + + System.out.println("\n"+TAB+"Listing Top 3 features:\n"+UNDERLINE); + Collection topNfeatures = model.getFeatures(3); + if ( topNfeatures == null ){ + System.out.println(TAB+TAB+"Error printing Top N features."); + return; + } + + Iterator itTopN = topNfeatures.iterator(); + while ( itTopN.hasNext() ){ + OraFeature feature = (OraFeature)itTopN.next(); + printFeature(feature); + } + + if ( sampleFeature != null ){ + System.out.println(TAB+"Listing all attribute names for the feature:" + sampleFeature.getFeatureIdentifier()); + System.out.println(TAB+"____________________________________________"); + String[] attrNames = sampleFeature.getAttributeNames(); + for ( int ni = 0 ; ni < attrNames.length ; ni++ ) { + Map attrValCoefficientMap = sampleFeature.getAttributeCoefficients(attrNames[ni]); + System.out.println("\n"+TAB+TAB+"Attribute Name:" + attrNames[ni] ); + printCoefficients(attrNames[ni], attrValCoefficientMap, false); + } + } + } + + /** + * Display a single feature + * + * @param feature specific feature to be displayed + * @throws JDMException if failed to retrieve the feature details + */ + public static void printFeature(OraFeature feature) throws JDMException + { + if ( feature == null ){ + System.out.println("Error: feature is null"); + return; + } + + System.out.println("\n" + TAB+TAB+"Feature : " + feature.getFeatureIdentifier() ); + String[] featureAttrNames = feature.getAttributeNames(); + //Print attributes coefficient details for each attribute + if(featureAttrNames != null) { + for(int iAttr=0; iAttr < featureAttrNames.length; iAttr++) + { + Map attrValCoefficientMap = feature.getAttributeCoefficients(featureAttrNames[iAttr]); + printCoefficients(featureAttrNames[iAttr], attrValCoefficientMap, true); + } + } + } + + + + private static void printCoefficients (String attrName, Map attrValCoefficientMap, boolean printAttrName) + throws JDMException + { + if ( attrValCoefficientMap == null ){ + System.out.println("Error printing coefficients for this feature."); + return; + } + + if ( printAttrName == true ) + print3Columns(new String[]{"Attribute","Value","Coefficient"} ); + else + print3Columns(new String[]{"","Value","Coefficient"} ); + + System.out.println(TAB+TAB+TAB +"____________________________________________________________________________" ); + Object[] attrVals = attrValCoefficientMap.keySet().toArray(); + if(attrVals != null) { + for(int iAttr=0; iAttr < attrVals.length; iAttr++) + { + print3Columns ( new String[]{ + ( printAttrName == true ? attrName : "" ) , + (( attrVals[iAttr] == null ? "" : attrVals[iAttr] )).toString(), + String.valueOf(m_df.format((Number)attrValCoefficientMap.get(attrVals[iAttr]))) + } + ); + } + } + + } + + private static void print3Columns(String[] names){ + if ( names == null || names.length != 3 ) + return; + + StringBuffer sbOut = new StringBuffer(TAB+TAB+TAB); + sbOut.append(names[0]); + + int padLength = Math.max ( SECOND_COLUMN - sbOut.length(), 0 ); + for ( int ni = 0 ; ni < padLength; ni++) + sbOut.append(SPACE); + + sbOut.append(names[1]); + padLength = Math.max ( THIRD_COLUMN - sbOut.length(), 0 ); + for ( int ni = 0 ; ni < padLength; ni++) + sbOut.append(SPACE); + + sbOut.append(names[2]); + System.out.println(sbOut.toString()); + } + + private static void clean() + { + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + // Drop prepared tables + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE TXTNMF_BUILD_NESTED_TEXT"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE TXTNMF_APPLY_NESTED_TEXT"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + // Drop prepared views + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW TXTNMF_NORM_DATA_BUILD_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW TXTNMF_NORM_DATA_APPLY_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + // Drop apply output table + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE TXTNMF_APPLY_OUTPUT_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try { + m_dmeConn.removeObject("txtnmfModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + } +} diff --git a/dmtxtsvm.sql b/dmtxtsvm.sql new file mode 100644 index 0000000..03ed409 --- /dev/null +++ b/dmtxtsvm.sql @@ -0,0 +1,229 @@ +Rem +Rem $Header: dmtxtsvm.sql 25-oct-2007.11:34:46 ramkrish Exp $ +Rem +Rem +Rem Copyright (c) 2003, 2007, Oracle. All rights reserved. +Rem +Rem dmtxtsvm.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a text mining model using +Rem SVM classification. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem ktaylor 07/12/05 - minor edits to comments +Rem ramkrish 01/28/05 - 4148186 - provide correct model names +Rem ramkrish 10/28/04 - cleanup/comments +Rem xbarr 06/25/04 - xbarr_dm_rdbms_migration +Rem bmilenov 05/18/04 - Change zscore to minmax normalization +Rem cbhagwat 02/25/04 - Format changes +Rem cbhagwat 10/13/03 - cbhagwat_txn109175 +Rem cbhagwat 10/10/03 - fix +Rem cbhagwat 10/08/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Mine the text features extracted using dmtxtfe.sql using SVM +-- algorithm. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- +-- See dmtxtfe.sql. Note that the text features are input here +-- through a nested table column called 'COMMENTS'. + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old model and objects for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('T_SVM_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE t_svmc_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Create settings table to choose linear kernel +CREATE TABLE t_svmc_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2 (30)); + +BEGIN + -- Populate settings table + INSERT INTO t_svmc_sample_settings VALUES + (dbms_data_mining.algo_name, + dbms_data_mining.algo_support_vector_machines); + --(dbms_data_mining.svms_conv_tolerance,0.01); + --(dbms_data_mining.svms_kernel_cache_size,50000000); + INSERT INTO t_svmc_sample_settings VALUES + (dbms_data_mining.svms_kernel_function,dbms_data_mining.svms_linear); + COMMIT; +END; +/ + +--------------- +-- CREATE MODEL + +-- Cleanup old objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE t_svmc_sample_norm'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW t_svmc_sample_build_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +-- Prepare mining_data_build data as appropriate +BEGIN + -- Make a numerical bin boundary table + DBMS_DATA_MINING_TRANSFORM.CREATE_NORM_LIN ( + norm_table_name => 't_svmc_sample_norm'); + + -- Normalize data + DBMS_DATA_MINING_TRANSFORM.INSERT_NORM_LIN_MINMAX ( + norm_table_name => 't_svmc_sample_norm', + data_table_name => 'mining_build_nested_text', + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'CUST_ID', + 'AFFINITY_CARD', + 'BULK_PACK_DISKETTES', + 'FLAT_PANEL_MONITOR', + 'HOME_THEATER_PACKAGE', + 'BOOKKEEPING_APPLICATION', + 'PRINTER_SUPPLIES', + 'Y_BOX_GAMES', + 'OS_DOC_SET_KANJI', + 'COMMENTS'), + round_num => 0 + ); + + -- Create the transformed view + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 't_svmc_sample_norm', + data_table_name => 'mining_build_nested_text', + xform_view_name => 't_svmc_sample_build_prepared'); +END; +/ + +-- Create SVM model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'T_SVM_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 't_svmc_sample_build_prepared', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + settings_table_name => 't_svmc_sample_settings'); +END; +/ + +-- Display the model settings +column setting_name format a30; +column setting_value format a30; +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'T_SVM_CLAS_SAMPLE' +ORDER BY setting_name; + +-- Display the model signature +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'T_SVM_CLAS_SAMPLE' +ORDER BY attribute_name; + +-- Display model details +-- Note how several text terms extracted from the COMMENTs documents +-- show up as predictors. +-- +SET line 120 +column class format a10 +column attribute_name format a25 +column attribute_value format a25 +column coefficient format 9.99 +WITH +mod_dtls AS ( +SELECT * + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_SVM('T_SVM_Clas_sample')) +), +model_details AS ( +SELECT d.class, a.attribute_name, a.attribute_value, a.coefficient + FROM mod_dtls d, + TABLE(d.attribute_set) a +ORDER BY class, ABS(coefficient) DESC +) +-- +SELECT TO_CHAR(class) class, + attribute_name, + attribute_value, + coefficient + FROM model_details + WHERE ROWNUM < 6; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- +-- See dmsvcdem.sql for examples. The key difference here +-- is the nested table input, and you can adapt that sample +-- code to accept the table with a nested table column as +-- input. + +----------------------------------------------------------------------- +-- SCORE NEW DATA USING SQL DATA MINING FUNCTIONS +----------------------------------------------------------------------- + +BEGIN EXECUTE IMMEDIATE 'DROP VIEW t_svmc_sample_apply_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Prepare scoring data +BEGIN + -- Create the transformed view + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 't_svmc_sample_norm', + data_table_name => 'mining_apply_nested_text', + xform_view_name => 't_svmc_sample_apply_prepared'); +END; +/ + +-- The key here is to demonstrate the use of these functions on +-- a scoring table with nested table input for attributes. + +------------------ +-- BUSINESS CASE 1 +-- +-- Find the 10 customers that are most likely to use an affinity card. +-- Note that the SQL data mining functions seamless work against +-- tables that contain nested table columns of type DM_Nested_Numerical +-- or DM_Nested_Categorical. The nested column COMMENT is also part +-- of this input. +-- +SELECT cust_id + FROM (SELECT cust_id + FROM t_svmc_sample_apply_prepared + ORDER BY PREDICTION_PROBABILITY(T_SVM_Clas_sample, 1 USING *) DESC, 1) +WHERE ROWNUM < 11; + +------------------ +-- BUSINESS CASE 2 +-- Find the average age of customers who are likely to use an +-- affinity card. Break out the results by gender. +-- +SELECT cust_gender, + COUNT(*) AS cnt, + ROUND(AVG(age)) AS avg_age + FROM t_svmc_sample_apply_prepared + WHERE PREDICTION(T_SVM_Clas_sample USING *) = 1 +GROUP BY cust_gender +ORDER BY cust_gender; diff --git a/dmtxtsvmdemo.java b/dmtxtsvmdemo.java new file mode 100644 index 0000000..f96f0e5 --- /dev/null +++ b/dmtxtsvmdemo.java @@ -0,0 +1,774 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmtxtsvmdemo.java +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using the Support Vector Machines (SVM) +* algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* How to predict whether a customer responds or not to the new affinity card +* program using a classifier based on the SVM algorithm with text mining? +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* comments(text), demographics, purchasing, and response details for the +* previous affinity card programs. Data exploration and preparing the data is a +* common step before doing data mining. Here in this demo, the following views are +* created in the user schema using CUSTOMERS, COUNTRIES, and +* SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_BUILD_TEXT: +* This view collects the previous customers' comments(text), demographics, +* purchasing, and affinity card response details for building the model. +* +* MINING_APPLY_TEXT: +* This view collects the prospective customers' comments(text), demographics, +* and purchasing details for predicting response for the new affinity card +* program. +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* 1. Missing Value treatment for Predictors in Build, Test and Apply data +* See dmsvcdemo.java for a definition of missing values, and the steps to be +* taken for missing value imputation. SVM interprets all NULL values for a +* given attribute as "sparse". We skip missing values treatment in this demo. +* +* 2. Outlier/Clipping Treatment for Predictors for Build data +* See dmsvcdemo.java for discussion of outlier treatment. We skip outlier +* treatment in this demo. +* +* 3. Normalize Predictors in Build, Test, and Apply data, unlike Regression +* using SVM, the target attribute is NOT normalized. +* +* The PrepareData() method in this demo program illustrates the preparation of the +* build and apply data. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification model using the SVM algorithm with +* text mining. +* +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification text mining models. The applyModel() method illustrates how to +* predict the customer response for an affinity card program. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic Java api imports +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.DecimalFormat; +import java.text.MessageFormat; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +// Java Data Mining (JDM) standard api imports +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.algorithm.svm.KernelFunction; +import javax.datamining.algorithm.svm.classification.SVMClassificationSettings; +import javax.datamining.algorithm.svm.classification.SVMClassificationSettingsFactory; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.CategorySet; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.modeldetail.svm.SVMClassificationModelDetail; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.classification.ClassificationApplySettings; +import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.supervised.classification.ClassificationTestMetricsTaskFactory; +import javax.datamining.supervised.classification.ClassificationTestTaskFactory; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.algorithm.svm.classification.OraSVMClassificationSettings; +import oracle.dmt.jdm.modeldetail.svm.OraSVMClassificationModelDetail; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.supervised.classification.OraClassificationModel; +import oracle.dmt.jdm.task.OraPredictTaskFactory; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.clipping.OraClippingTransformFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransform; +import oracle.dmt.jdm.transform.normalize.OraNormalizeType; +import oracle.dmt.jdm.transform.text.OraTextTransform; +import oracle.dmt.jdm.transform.text.OraTextTransformFactory; + + +public class dmtxtsvmdemo extends Object { + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClassificationSettingsFactory m_clasFactory; + private static SVMClassificationSettingsFactory m_svmcFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClassificationTestTaskFactory m_testFactory; + private static OraPredictTaskFactory m_predictFactory; + private static ClassificationApplySettingsFactory m_applySettingsFactory; + private static ClassificationTestMetricsTaskFactory m_testMetricsTaskFactory; + private static OraTextTransformFactory m_textXformFactory; + private static OraNormalizeTransformFactory m_normalizeXformFactory; + private static OraClippingTransformFactory m_clippingXformFactory; + private static OraTransformationTaskFactory m_xformTaskFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + // Global data members + private static OraNormalizeTransform m_normalizeDataXform; + + private static boolean displayModelDeatils = false;//By default it is set to false. To view the details of the model this flag can be enabled + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmtxtsvmdemo "); + System.out.println(" or: java dmtxtsvmdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Prepare data + prepareData(); + // 5. Build model + buildModel(); + // 6. Test model - See dmsvcdemo.java for examples. The key difference + // here is the nested table input, and you can adapt that sample code to + // accept the table with a nested table column as input. + // 7. Apply the model + applyModel(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { } // Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_clasFactory = (ClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationSettings"); + m_svmcFactory = (SVMClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.algorithm.svm.classification.SVMClassificationSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_predictFactory = (OraPredictTaskFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.task.OraPredictTask"); + m_testFactory = (ClassificationTestTaskFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationTestTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = (ClassificationApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationApplySettings"); + m_testMetricsTaskFactory = (ClassificationTestMetricsTaskFactory) m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationTestMetricsTask"); + m_clippingXformFactory = (OraClippingTransformFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.clipping.OraClippingTransform"); + m_normalizeXformFactory = (OraNormalizeTransformFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.normalize.OraNormalizeTransform"); + m_textXformFactory = (OraTextTransformFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.text.OraTextTransform"); + m_xformTaskFactory = (OraTransformationTaskFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.task.OraTransformationTask"); + } + + /** + * This method illustrates preparation of the data for build, test, and apply + * operations by using missing value, clipping and normalization + * transformation. + * + * The following table illustrates customer attributes available for building + * the mining model and data characteristics and type of transformation used + * for each attribute. + * + * Transformations: + * 1. Missing Value (MISSING): Skipped - see dmsvcdemo.java for example. + * + * 2. Clipping (CLIPPING): Skipped - see dmsvcdemo.java for example. + * + * 3. Normalization (NORMALIZING): Normalize numerical attributes AGE and + * YRS_RESIDENCE. We will use default(minmax) normalization type to + * treat these numerical attributes. + * + * COLUMN_NAME DATA_TYPE DISTINCT NORMALIZING + * ------------------ --------- -------- ----------- + * CUST_ID NUMBER 1500 + * CUST_GENDER CHAR 2 + * AGE NUMBER 66 MINMAX + * CUST_MARITAL_STATUS VARCHAR2 7 + * COUNTRY_NAME VARCHAR2 19 + * CUST_INCOME_LEVEL VARCHAR2 12 + * EDUCATION VARCHAR2 16 + * OCCUPATION VARCHAR2 15 + * HOUSEHOLD_SIZE VARCHAR2 6 + * YRS_RESIDENCE NUMBER 15 MINMAX + * AFFINITY_CARD NUMBER 2 + * BULK_PACK_DISKETTES NUMBER 2 + * FLAT_PANEL_MONITOR NUMBER 2 + * HOME_THEATER_PACKAGE NUMBER 2 + * BOOKKEEPING_APPLICATION NUMBER 2 + * PRINTER_SUPPLIES NUMBER 1 + * Y_BOX_GAMES NUMBER 2 + * OS_DOC_SET_KANJI NUMBER 2 + * OS_DOC_SET_KANJI NUMBER 2 + * COMMENTS VARCHAR2(4000) 44 + * + * The following tables are created after the execution of this method. + * + * Unprepared Data ---> Prepared(Normalized) Data + * ------------------------ --------------------------- + * MINING_BUILD_TEXT TXTSVM_NORM_DATA_BUILD_JDM + * MINING_APPLY_TEXT TXTSVM_NORM_DATA_APPLY_JDM + */ + public static void prepareData() throws JDMException + { + boolean isOutputAsView = false; + String inputDataURI = null; + String outputDataURI = null; + String inputNormalizationDefinitionTable = null; + String inputClippingDefinitionTable = null; + OraTransformationTask xformTask = null; + //------------------------------------------------------------------------ + // 1. Prepare build data + //------------------------------------------------------------------------ + // Text Transformation - Convert text column into a nested column in order + // to perform text mining + isOutputAsView = false; + inputDataURI = "MINING_BUILD_TEXT"; + outputDataURI = "TXTSVM_BUILD_NESTED_TEXT"; + String caseId = "CUST_ID"; + String[] textColumnList = {"COMMENTS"}; + OraTextTransform textDataXform = + (OraTextTransform)m_textXformFactory.create( + inputDataURI, outputDataURI, caseId, textColumnList); + xformTask = m_xformTaskFactory.create(textDataXform); + executeTask(xformTask, "txtsvmPrepareTextB_jdm"); + // Normalization - unlike SVM regression, the classification target is + // NOT normalized here. In addition, case id and binary numerical + // attributes do not need to be normalized in any case. + // + // Create normalization definition table from mining build nested data + isOutputAsView = true; + inputDataURI = "TXTSVM_BUILD_NESTED_TEXT"; + outputDataURI = "TXTSVM_NORM_DATA_BUILD_JDM"; + OraNormalizeType normalizeType = OraNormalizeType.min_max; + Integer roundingNumber = new Integer(0); + OraNormalizeTransform buildDataXform = + (OraNormalizeTransform)m_normalizeXformFactory.create( + inputDataURI, outputDataURI, isOutputAsView, + normalizeType, roundingNumber); + String[] excludeColumnList = { + "CUST_ID", + "AFFINITY_CARD", + "BULK_PACK_DISKETTES", + "FLAT_PANEL_MONITOR", + "HOME_THEATER_PACKAGE", + "BOOKKEEPING_APPLICATION", + "PRINTER_SUPPLIES", + "Y_BOX_GAMES", + "OS_DOC_SET_KANJI", + "COMMENTS" + }; + buildDataXform.setExcludeColumnList(excludeColumnList); + xformTask = m_xformTaskFactory.create(buildDataXform); + executeTask(xformTask, "txtsvmPrepareBuild_jdm"); + //------------------------------------------------------------------------ + // 2. Prepare apply data - if the data for model creation has been + // prepared, then the data to be scored using the model must be + // prepared in the same manner in order to obtain meaningful results. + //------------------------------------------------------------------------ + // Text Transformation - Convert text column into a nested column in order + // to perform text mining + isOutputAsView = false; + inputDataURI = "MINING_APPLY_TEXT"; + outputDataURI = "TXTSVM_APPLY_NESTED_TEXT"; + caseId = "CUST_ID"; + textColumnList = new String[] {"COMMENTS"}; + //Get feature tables created by the build text transformation + OraTransformationTask buildTextXformTask = (OraTransformationTask)m_dmeConn.retrieveObject( + "txtsvmPrepareTextB_jdm", NamedObject.task); + String[] buildFeatureTables = ((OraTextTransform)buildTextXformTask.getTransformation()).getFeatureTables(); + textDataXform = + (OraTextTransform)m_textXformFactory.create( + inputDataURI, outputDataURI, caseId, textColumnList, + buildFeatureTables); + xformTask = m_xformTaskFactory.create(textDataXform); + executeTask(xformTask, "txtsvmPrepareTextA_jdm"); + // Normalization + isOutputAsView = true; + inputDataURI = "TXTSVM_APPLY_NESTED_TEXT"; + outputDataURI = "TXTSVM_NORM_DATA_APPLY_JDM"; + inputNormalizationDefinitionTable = + buildDataXform.getNormalizationDefinitionTable(); + OraNormalizeTransform applyDataXform = + (OraNormalizeTransform)m_normalizeXformFactory.create( + inputDataURI, outputDataURI, + isOutputAsView, inputNormalizationDefinitionTable); + xformTask = m_xformTaskFactory.create(applyDataXform); + executeTask(xformTask, "txtsvmPrepareApply_jdm"); + } + + /** + * This method illustrates how to build a text mining model using the + * TXTSVM_NORM_DATA_BUILD_JDM dataset and classification settings with + * the SVM algorithm. + * + * By default, the SVM algorithm chooses a kernel type automatically. This + * choice can be overriden by the user. Linear kernel is preferred for high + * dimensional data, and Gaussian kernel for low dimensional data. Here we use + * linear kernel to demonstrate the getModelDetail() API, which applies only + * for models. + */ + public static void buildModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("TXTSVM_NORM_DATA_BUILD_JDM", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("txtsvmBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // Create SVMC algorithm settings + SVMClassificationSettings svmcAlgo = m_svmcFactory.create(); + svmcAlgo.setKernelFunction(KernelFunction.kLinear); + // Examples settings are: + // svmcAlgo.setKernelFunction(KernelFunction.kGaussian); + // svmcAlgo.setComplexityFactor(0.01f); + // svmcAlgo.setTolerance(0.01f); + // + //Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(svmcAlgo); + buildSettings.setTargetAttributeName("AFFINITY_CARD"); + m_dmeConn.saveObject("txtsvmBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "txtsvmBuildData_jdm", //Build data specification + "txtsvmBuildSettings_jdm", //Mining function settings name + "txtsvmModel_jdm" //Mining model name + ); + buildTask.setDescription("txtsvmBuildTask_jdm"); + executeTask(buildTask, "txtsvmBuildTask_jdm"); + //4. Restore the model from the DME and explore the details of the model + ClassificationModel model = + (ClassificationModel)m_dmeConn.retrieveObject( + "txtsvmModel_jdm", NamedObject.model); + // Display model build settings + ClassificationSettings retrievedBuildSettings = + (ClassificationSettings)model.getBuildSettings(); + if(buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "txtsvmBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + // Display model details + if(displayModelDeatils) + displaySVMCModelDetails((Model)model); + } + + /** + * This method illustrates how to apply the mining model on the + * TXTSVM_NORM_DATA_APPLY_JDM dataset to predict customer + * response. After completion of the task, an apply output table with the + * predicted results is created at the user-specified location. + */ + public static void applyModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + // The key here is to demonstrate the use of these functions on a scoring + // table with nested table input for attributes. + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "TXTSVM_NORM_DATA_APPLY_JDM", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "txtsvmApplyData_jdm", applyData, true ); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "txtsvmApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "txtsvmApplyData_jdm", "txtsvmModel_jdm", + "txtsvmApplySettings_jdm", "TXTSVM_APPLY_OUTPUT_JDM"); + executeTask(applyTask, "txtsvmApplyTask_jdm"); + // 4. Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + // + // Find the 10 customers who are most likely to use an affinity card. + // Note that the SQL data mining functions seamless work against + // tables that contain nested table columns of type DM_Nested_Numerical + // or DM_Nested_Categorical. The nested column COMMENT is also part + // of this input. + displayTable("TXTSVM_APPLY_OUTPUT_JDM", + "where PREDICTION =1 and ROWNUM < 11", + "order by PROBABILITY desc"); + } + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful."); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() ); + } + return isTaskSuccess; + } + + private static void displayBuildSettings( + ClassificationSettings clasSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " model build settings object:"); + String objName = clasSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = clasSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = clasSettings.getCreationDate(); + String creator = clasSettings.getCreatorInfo(); + String targetAttrName = clasSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = clasSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: clasSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = clasSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: clasSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + try { + Map map = clasSettings.getPriorProbabilitiesMap(targetAttrName); + if(map != null) System.out.println("Priors Map: " + map.toString()); + } catch(Exception jdmExp) + { + System.out.println("Failure: clasSettings.getPriorProbabilitiesMap(targetAttrName)throws exception"); + jdmExp.printStackTrace(); + } + // List of SVM algorithm settings availabe in linear kernel + KernelFunction kernelFunction = ((OraSVMClassificationSettings)algoSettings).getKernelFunction(); + System.out.println("Kernel Function: " + kernelFunction.name()); + double doubleValue = ((OraSVMClassificationSettings)algoSettings).getComplexityFactor(); + System.out.println("Complexity Factor: " + m_df.format(doubleValue)); + doubleValue = ((OraSVMClassificationSettings)algoSettings).getTolerance(); + System.out.println("Tolerance: " + m_df.format(doubleValue)); + boolean enable = ((OraSVMClassificationSettings)algoSettings).getActiveLearning(); + System.out.println("Is Active Learning enabled? " + enable); + } + + /** + * This method displayes SVMC model signature. + * + * @param model model object + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + /** + * This method displayes SVMC model details. The coefficient indicates the + * relative influence of a given (attribute, value) pair on the target value. + * A negative coefficient value indicates a negative influence. + * + * @param svmcModelDetails svm classification model details object + * @exception JDMException if failed to retrieve model details + */ + public static void displaySVMCModelDetails( + Model model) throws JDMException + { + // Obtains model details + SVMClassificationModelDetail svmcModelDetails = + (SVMClassificationModelDetail)model.getModelDetail(); + // Is linear model? + System.out.println("Is linear model? " + svmcModelDetails.isLinearSVMModel() ); + // Available targets + CategorySet targetSet = ((OraClassificationModel)model).getTargetCategorySet(); + Object[] targets = targetSet.getValues(); + // Attribute coefficient value will be available if it is a linear model + if (svmcModelDetails.isLinearSVMModel()) + { + System.out.println("Model Deatils: ( Target Value, Attribute Name, Attribute Value, Coefficient)"); + MessageFormat mfDetails = new MessageFormat(" ( {0}, {1}, {2}, {3} )"); + String[] vals = new String[4]; + for (int row =0; row < targets.length; row++) + { + // Print bias of the current target value by invoking getBias method. + vals[0] =(String) targets[row].toString(); + vals[1] = ""; + vals[2] = ""; + vals[3] = m_df.format(svmcModelDetails.getBias(targets[row])) + " (Bias)"; + System.out.println( mfDetails.format(vals) ); + //Get the signature attributes + ModelSignature modelSignature = model.getSignature(); + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + // Print all attribute coefficients -- The FIRST row in the SVM model + // details output shows the value for SVM bias under the COEFFICIENT + // column. + Map attrCoefficientMap = ((OraSVMClassificationModelDetail)svmcModelDetails).getCoefficients(targets[row],attr.getName()); + Object[] attrVals = attrCoefficientMap.keySet().toArray(); + if(attrVals != null) { + for(int iAttr=0; iAttr < attrVals.length; iAttr++) + { + vals[1] = attr.getName(); + vals[2] = ""; + if(attrVals[iAttr] != null) + vals[2] = attrVals[iAttr].toString(); + vals[3] = ""; + Number coefficient = (Number)attrCoefficientMap.get(attrVals[iAttr]); + if(coefficient != null) + vals[3] = m_df.format(coefficient); + System.out.println( mfDetails.format(vals) ); + } + } + } + } + } + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while(rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + private static void clean() + { + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + //Drop prepared tables + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE TXTSVM_BUILD_NESTED_TEXT"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE TXTSVM_APPLY_NESTED_TEXT"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop prepared views + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW TXTSVM_NORM_DATA_BUILD_JDM"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW TXTSVM_NORM_DATA_APPLY_JDM"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop apply output table + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE TXTSVM_APPLY_OUTPUT_JDM"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop the model + try { + m_dmeConn.removeObject("txtsvmModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + } +} diff --git a/dmxfdemo.java b/dmxfdemo.java new file mode 100644 index 0000000..8f66550 --- /dev/null +++ b/dmxfdemo.java @@ -0,0 +1,893 @@ +// Copyright (c) 2001, 2007, Oracle. All rights reserved. +// File: dmxfdemo.java + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to perform mining transformations: discretization, clipping, and normalization. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Data preparation is an important step preceding actual data mining. The following +* types of transformation are demonstrated: discretization, clipping and +* normalization. +* Discretization involves mapping both continuous and discrete values to discrete +* values of reduced cardinality. It can be performed on both categorical and +* numerical attributes. The following types of discretization are demonstrated +* for numerical attributes: equal width, quantile and custom. Top-N method can be +* applied to categorical attributes. +* Normalization involves scaling continuous values down to specific range - as +* in -1.0 to 1.0 or 0.0 to 1.0 such that xnew = (xold - shift)/scale. +* It applies only to numerical attributes. Min-Max Normalization and Z-Score +* Normalization are shown. +* Clipping involves setting the tail values of a particular attribute to some +* specified quantile of the data, or removing the tails. It applies only to +* numerical attributes. Winsorizing and trimming methods are presented. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created +* in the user schema using CUSTOMERS, COUNTRIES, and SUPPLIMENTARY_DEMOGRAPHICS +* tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographic, purchasing, and affinity +* card response details for building the model. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ + +// Generic api imports +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.DecimalFormat; +import java.text.MessageFormat; +import java.util.Vector; +import java.util.ArrayList; +// Java Data Mining (JDM) standard imports +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.base.Task; +import javax.datamining.resource.ConnectionSpec; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.OraTransformationFactory; +import oracle.dmt.jdm.transform.OraTransformationSequence; +import oracle.dmt.jdm.transform.binning.OraAttributeBins; +import oracle.dmt.jdm.transform.binning.OraBinningTransform; +import oracle.dmt.jdm.transform.binning.OraBinningTransformFactory; +import oracle.dmt.jdm.transform.binning.OraCategoricalAttributeBins; +import oracle.dmt.jdm.transform.binning.OraCategoricalBin; +import oracle.dmt.jdm.transform.binning.OraCategoricalBinningType; +import oracle.dmt.jdm.transform.binning.OraNumericalAttributeBins; +import oracle.dmt.jdm.transform.binning.OraNumericalBin; +import oracle.dmt.jdm.transform.binning.OraNumericalBinningType; +import oracle.dmt.jdm.transform.clipping.OraClippingTransform; +import oracle.dmt.jdm.transform.clipping.OraClippingTransformFactory; +import oracle.dmt.jdm.transform.clipping.OraClippingType; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransform; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeType; +import oracle.dmt.jdm.utils.OraSQLUtils; + +public class dmxfdemo extends Object{ + //Connection related data members + private static javax.datamining.resource.Connection m_dmeConn = null; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory = null; + //Object factories used in this demo program + private static OraTransformationFactory m_xformFactory = null; + private static OraTransformationTaskFactory m_xformTaskFactory = null; + private static OraBinningTransformFactory m_binXformFactory = null; + // Global constant used for formatting + protected static DecimalFormat m_df = new DecimalFormat("00.##E0"); + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmxfdemo "); + System.out.println(" or: java dmxfdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + //1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. custom binning + binDataCustom("MINING_DATA_BINNED_CUSTOM"); + // 5. discretize data using equal width + binDataEqWidth(); + // 6. discretize data using quantile + binDataQtile(); + // 7. bin using supervised method + binSupervised(); + // 8. clip data using trimming + clipDataTrim(); + // 9. clip data using winsorizing + clipDataWinsorize(); + // 10. normalize data using min-max + normalizeMinMax(); + // 11. normalize data using z-score + normalizeZScore(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 10. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { }//Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_xformFactory = (OraTransformationFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.OraTransformation"); + m_xformTaskFactory = (OraTransformationTaskFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.task.OraTransformationTask"); + + m_binXformFactory = (OraBinningTransformFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.binning.OraBinningTransform"); + + } + + /** + * Illustrates how to perform equal width data discretization + * + * @exception JDMException if discretization failed + */ + public static void binDataEqWidth() throws JDMException + { + binData("MINING_DATA_BINNED_EQW", OraNumericalBinningType.equi_width); + } + + /** + * Illustrates how to perform quantile data discretization + * + * @exception JDMException if discretization failed + */ + public static void binDataQtile() throws JDMException + { + binData("MINING_DATA_BINNED_QTL",OraNumericalBinningType.quantile); + } + + /** + * Illustrates how to perform data discretization. + * + * @param resultXformName name of the result discretized view + * @param binningType type of discretization to perform i.e., + * quantile, equal width or custom + * @throws JDMException if discretization failed + */ + public static void binData(String resultXformName, OraNumericalBinningType binningType) + throws JDMException + { + // Schema where the original data and resulting transformations reside + String schema = ( m_dmeConn.getConnectionSpec().getName() ).toUpperCase(); + + // Create discretization transformation instance + OraBinningTransform obt = m_xformFactory.createBinningTransform(); + obt.setTransformInputData(schema + "." + "MINING_DATA_BUILD_V"); + obt.setTransformOutputData(schema + "." + resultXformName); + + // Specify the number of numeric bins + obt.setNumberOfBinsForNumerical(10); + + // Specify the number of categoric bins + obt.setNumberOfBinsForCategorical(8); + + // Specify the list of excluded attributes + String[] excludedList = new String[]{ + "CUST_ID", "CUST_GENDER" + }; + obt.setExcludeColumnList(excludedList); + + // Specify the type of numeric binning: equal-width or quantile + // ( default is quantile ) + obt.setNumericalBinningType(binningType); + // Specify the type of categorical binning as Top-N: by default it is none + obt.setCategoricalBinningType(OraCategoricalBinningType.top_n); + + ArrayList xformList = new ArrayList(); + xformList.add(obt); + //Create a transformation sequence object + OraTransformationSequence xformSeq = + m_xformFactory.createTransformationSequence( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + xformList, //List of transformations. In this case only one type of transformation i.e., supervised binning + schema + "." + resultXformName // name of the transformation result + ); + String xformSeqName = "bin_" + binningType.name() + "_xfSeq"; + m_dmeConn.saveObject(xformSeqName, xformSeq, true); + + OraTransformationTask xformTask = m_xformTaskFactory.create( + xformSeqName, false); + + executeTask(xformTask, "xFormBin_jdm"); + displayDiscretizationResults( + binningType, + schema + "." + resultXformName, + new String[]{"CUST_INCOME_LEVEL","OCCUPATION"} + ); + } + + /** + * Illustrates how to perform custom data discretization. First discretization + * of 2 numerical attributes is performed. "AGE" is binned with equal width + * method with 10 bins and "YRS_RESIDENCE" with quantile method and 5 bins. + * Categorical attributes "EDUCATION" and "OCCUPATION" are discretized + * with the Top-N method into 15 and 10 bins. This method illustrates + * how additional attributes can be added to the existing discretization + * tables: "AFFINITY_CARD" and ""HOUSEHOLD_SIZE". Finally results are combined + * into a single array and custom transformation task is performed. + * + * @param resultXformName name of the result transformation view + * @throws JDMException if transformation failed + */ + public static void binDataCustom(String resultXformName) throws JDMException + { + System.out.println("Custom binning"); + System.out.println("--------------------------------------------"); + // Schema where the original data and resulting transformations reside + String schema = ( m_dmeConn.getConnectionSpec().getName() ).toUpperCase(); + + // Numeric custom binning + OraNumericalAttributeBins[] customNumBins = m_binXformFactory.computeNumericBins( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + new String[] { + "AGE", "YRS_RESIDENCE", + }, + new OraNumericalBinningType[] { + OraNumericalBinningType.equi_width, + OraNumericalBinningType.quantile + }, + new Integer[] {new Integer(10), new Integer(5)} + ); + + if ( customNumBins == null ){ + System.out.println("Error: no numeric bins were computed"); + return; + } + + //Categoric custom binning + OraCategoricalAttributeBins[] customCatBins = m_binXformFactory.computeCategoricBins( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + new String[] { + "EDUCATION", "OCCUPATION", + }, + new OraCategoricalBinningType[] { + OraCategoricalBinningType.top_n, + OraCategoricalBinningType.top_n, + }, + new Integer[] {new Integer(15), new Integer(10),} + ); + + if ( customCatBins == null ){ + System.out.println("Error: no categoric bins were computed"); + return; + } + + // combine custom bins into the single array + OraAttributeBins[] customBins = null; + customBins = incrementArray(customBins, (OraAttributeBins[])customNumBins); + customBins = incrementArray(customBins, (OraAttributeBins[])customCatBins); + + // show resulting array of custom bins + for ( int i = 0 ; i < customBins.length; i++ ) { + System.out.println("Attribute:" + customBins[i].getAttributeName() ); + + if ( customBins[i] instanceof OraNumericalAttributeBins ){ + OraNumericalAttributeBins oraNumBin = (OraNumericalAttributeBins)customBins[i]; + OraNumericalBin[] bs = oraNumBin.getBins(); + System.out.println("\tBin ID\tLower\tUpper" ); + for ( int j = 0 ; j < bs.length; j++ ) { + System.out.println("\t" + bs[j].getBinID() + "\t" + m_df.format(bs[j].getStartValue()) + + "\t" + m_df.format(bs[j].getEndValue()) ); + } + } + else if ( customBins[i] instanceof OraCategoricalAttributeBins ){ + OraCategoricalAttributeBins oraCatBin = (OraCategoricalAttributeBins)customBins[i]; + OraCategoricalBin[] bs = oraCatBin.getBins(); + System.out.println("\tBin ID\tCategory" ); + for ( int j = 0 ; j < bs.length; j++ ) { + Object[] categories = bs[j].getCategories(); + System.out.print("\t" + bs[j].getBinID() +"\t" ); + for ( int k = 0 ; k < categories.length; k++ ) { + System.out.print(categories[k].toString() ); + if ( k < categories.length - 1 ) + System.out.print(";"); + } + System.out.println(); + } + } + } + // Create discretization transformation instance + OraBinningTransform obt = m_xformFactory.createBinningTransform(customBins); + + // Specify the type of numeric binning: custom + obt.setNumericalBinningType(OraNumericalBinningType.custom); + // Specify the type of categoric binning: custom + obt.setCategoricalBinningType(OraCategoricalBinningType.custom); + + ArrayList xformList = new ArrayList(); + xformList.add(obt); + //Create a transformation sequence object + OraTransformationSequence xformSeq = + m_xformFactory.createTransformationSequence( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + xformList, //List of transformations. In this case only one type of transformation i.e., supervised binning + schema + "." + resultXformName // name of the transformation result + ); + String xformSeqName = "bin_" + OraNumericalBinningType.custom.name() + "_xfSeq"; + m_dmeConn.saveObject(xformSeqName, xformSeq, true); + + OraTransformationTask xformTask = m_xformTaskFactory.create(xformSeqName, true); + executeTask(xformTask, "xCustomBin_jdm"); + + // display content of the bin definition tables + showBinDefinitionTableContents(obt.getCategoricalBinTable(), "categorical"); + showBinDefinitionTableContents(obt.getNumericalBinTable(), "numerical"); + + displayDiscretizationResults( + OraNumericalBinningType.custom, + schema + "." + resultXformName, + new String[]{"AGE", "CUST_INCOME_LEVEL","EDUCATION", "OCCUPATION"} + ); + + // Bin additional attribute and add + // to the existing bin definition tables + //---------------------------------------------------------------- + // Numeric custom binning + OraNumericalAttributeBins[] customNumBinsAdd = m_binXformFactory.computeNumericBins( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + new String[] { + "AFFINITY_CARD", + }, + new OraNumericalBinningType[] { + OraNumericalBinningType.quantile, + }, + new Integer[] {new Integer(6)} + ); + + if ( customNumBins == null ){ + System.out.println("Error: no numeric bins were computed"); + return; + } + + //Categoric custom binning + OraCategoricalAttributeBins[] customCatBinsAdd = m_binXformFactory.computeCategoricBins( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + new String[] { + "HOUSEHOLD_SIZE", + }, + new OraCategoricalBinningType[] { + OraCategoricalBinningType.top_n, + }, + new Integer[] {new Integer(15), new Integer(10),} + ); + + if ( customCatBins == null ){ + System.out.println("Error: no categoric bins were computed"); + return; + } + + // combine custom bins into the single array + OraAttributeBins[] customBinsAdd = null; + customBinsAdd = incrementArray(customBinsAdd, (OraAttributeBins[])customNumBinsAdd); + customBinsAdd = incrementArray(customBinsAdd, (OraAttributeBins[])customCatBinsAdd); + + // clean up previous view + dropView ( null, resultXformName); + + OraBinningTransform obtAdd = m_xformFactory.createBinningTransform( + obt.getCategoricalBinTable(), + obt.getNumericalBinTable(), + customBinsAdd); + obtAdd.setTransformInputData(schema + "." + "MINING_DATA_BUILD_V"); + obtAdd.setTransformOutputData(schema + "." + resultXformName); + + // Specify the type of numeric binning: custom + obtAdd.setNumericalBinningType(OraNumericalBinningType.custom); + // Specify the type of categoric binning: custom + obtAdd.setCategoricalBinningType(OraCategoricalBinningType.custom); + + OraTransformationTask xformTaskAdd = m_xformTaskFactory.create(obtAdd); + executeTask(xformTaskAdd, "xCustomBinAdd_jdm"); + + // display content of the new bin definition tables + showBinDefinitionTableContents(obtAdd.getCategoricalBinTable(), "categorical"); + showBinDefinitionTableContents(obtAdd.getNumericalBinTable(), "numerical"); + + // show results + displayDiscretizationResults( + OraNumericalBinningType.custom, + schema + "." + resultXformName, + new String[]{"AFFINITY_CARD","HOUSEHOLD_SIZE"} + ); + } + + /** + * For supervised functions with the known target attribute, supervised + * binning is a recommended approach. It is a smart binning based on the + * target attribute values. This method is supported from 11.1 release + * of ODM. + */ + public static void binSupervised() throws JDMException { + // Schema where the original data and resulting transformations reside + String schema = ( m_dmeConn.getConnectionSpec().getName() ).toUpperCase(); + + // Create discretization transformation instance + OraBinningTransform obt = m_xformFactory.createBinningTransform(); + + + // Specify the list of excluded attributes + String[] excludedList = new String[]{ + "CUST_ID", "CUST_GENDER" + }; + obt.setExcludeColumnList(excludedList); + + // Specify the type of numeric binning: supervised + obt.setNumericalBinningType(OraNumericalBinningType.supervised); + // Specify the type of categorical binning as supervised + obt.setCategoricalBinningType(OraCategoricalBinningType.supervised); + obt.setTargetAttributeName("AFFINITY_CARD"); + + ArrayList xformList = new ArrayList(); + xformList.add(obt); + //Create a transformation sequence object + OraTransformationSequence xformSeq = + m_xformFactory.createTransformationSequence( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + xformList, //List of transformations. In this case only one type of transformation i.e., supervised binning + schema + "." + "MINING_DATA_BINNED_SUP" // name of the transformation result + ); + m_dmeConn.saveObject("superBin_xformSeq", xformSeq, true); + + OraTransformationTask xformTask = m_xformTaskFactory.create( + "superBin_xformSeq", false); + executeTask(xformTask, "xFormSuperBin_jdm"); + displayDiscretizationResults( + OraNumericalBinningType.supervised, + schema + "." + "MINING_DATA_BINNED_SUP", + new String[]{"CUST_INCOME_LEVEL","OCCUPATION"} + ); + } + + /** + * Shows histogram for selected binned attributes + * + * @param binningType type of discretization performed i.e., quantile, equal + * width or custom + * @param xformResult name of the result discretized view + * @param attributes names of attributes for which histogram is displayed + */ + public static void displayDiscretizationResults( + OraNumericalBinningType binningType, String xformResult, String[] attributes) + { + System.out.println("\nShowing results of the discretization transformation"); + System.out.println("\tType of discretization: " + binningType.name() ); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + for ( int i = 0; i < attributes.length; i++ ) { + String sqlQuery = MessageFormat.format( + "SELECT {0} BIN_NUMBER, COUNT(*) FREQUENCY FROM ({1}) GROUP BY {0} " + + "ORDER BY FREQUENCY DESC,BIN_NUMBER ASC", + new String[]{ + "\""+attributes[i]+"\"", + xformResult + } + ); + Statement stmt = null; + ResultSet rs = null; + System.out.println("\tHistogram for:" + attributes[i]); + try{ + stmt = dbConn.createStatement(); + rs = stmt.executeQuery(sqlQuery); + while ( rs.next() ){ + String binValue = rs.getString("BIN_NUMBER"); + int freq = rs.getInt("FREQUENCY"); + System.out.println("\t\t"+binValue + " " + freq); + } + } + catch(Exception e){ + System.out.println(e); + } + finally{ + try{rs.close(); stmt.close();} + catch(Exception e){} + } + } + } + + + /** + * Shows results of the clipping for selected attributes + * + * @param schema schema where result transformation view resides + * @param xformResult name of the resulting transformation view + * @param attribute name of the attribute for which transformation was performed + * @param clippingType type of clipping which was performed, i.e. + * trimming or winsorising + */ + public static void displayClippingResults( String schema, String xformResult, + String attribute, OraClippingType clippingType) + { + System.out.println("\nShowing results of the clipping transformation"); + System.out.println("\tClipping type: " + + ( true == clippingType.equals(OraClippingType.trim) ? "trim" : "winsorize") ); + System.out.println("\tMinimum and maximum values for:" + attribute + + " before clipping transformation"); + + String sqlQuery = MessageFormat.format( + "SELECT MIN ({0}) MIN_VALUE, MAX ({0}) MAX_VALUE FROM ({1})", + new String[]{ "\""+attribute+"\"", + schema + "." + "MINING_DATA_BUILD_V"} + ); + getMinMax(sqlQuery); + + System.out.println("\tMinimum and maximum values for:" + attribute + + " after clipping transformation."); + sqlQuery = MessageFormat.format( + "SELECT MIN ({0}) MIN_VALUE, MAX ({0}) MAX_VALUE FROM ({1})", + new String[]{ "\""+attribute+"\"", + schema + "." + xformResult} + ); + getMinMax(sqlQuery); + } + + private static void getMinMax(String sqlQuery) + { + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + ResultSet rs = null; + try{ + stmt = dbConn.createStatement(); + rs = stmt.executeQuery(sqlQuery); + while ( rs.next() ){ + String minValue = rs.getString("MIN_VALUE"); + String maxValue = rs.getString("MAX_VALUE"); + System.out.println( + "\t\tMin value=" + m_df.format(Double.parseDouble(minValue) ) + + ", Max value=" + m_df.format(Double.parseDouble(maxValue))); + } + } + catch(Exception e){ + System.out.println(e); + } + finally{ + try{rs.close(); stmt.close();} + catch(Exception e){} + } + } + + private static void clean() + { + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + + dropView( dbConn, "MINING_DATA_BINNED_EQW"); + dropView( dbConn, "MINING_DATA_BINNED_QTL"); + dropView( dbConn, "MINING_DATA_CLIP_TRIM"); + dropView( dbConn, "MINING_DATA_CLIP_WINS"); + dropView( dbConn, "MINING_DATA_BINNED_CUSTOM"); + dropView( dbConn, "MINING_DATA_NORMALIZE_MIN_MAX"); + dropView( dbConn, "MINING_DATA_NORMALIZE_Z_SCORE"); + } + + private static void dropView(java.sql.Connection dbConn, String viewName) + { + if ( dbConn == null ) + dbConn = ((OraConnection)m_dmeConn).getDatabaseConnection(); + + Statement stmt = null; + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW " + viewName); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try{stmt.close();} + catch(SQLException anySqlExp) {} + } + } + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints the error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print("\n"+taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful.\n"); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() + "\n" ); + } + return isTaskSuccess; + } + + /** + * Illustrates how to perform trimming type of clipping which involves + * removing the tail values of the attribute. + * + * @throws JDMException if transformation failed + */ + public static void clipDataTrim() throws JDMException + { + clipData(OraClippingType.trim, "MINING_DATA_CLIP_TRIM"); + } + + /** + * Illustrates how to perform winsorising type of clipping which involves + * setting the tail values of a particular attribute to some specified + * quantile of the data. + * + * @throws JDMException if transformation failed + */ + public static void clipDataWinsorize() throws JDMException + { + clipData(OraClippingType.winsorize, "MINING_DATA_CLIP_WINS"); + } + /** + * Illustrates how to perform data clipping + * + * @param clippingType type of clipping to perform + * @param xformResult name of the result transformation view + * @throws JDMException if transformation failed + */ + public static void clipData(OraClippingType clippingType, String xformResult) + throws JDMException + { + // Schema where the original data and resulting transformations reside + String schema = ( m_dmeConn.getConnectionSpec().getName() ).toUpperCase(); + + OraClippingTransform oct = m_xformFactory.createClippingTransform(); + oct.setTransformInputData(schema + "." + "MINING_DATA_BUILD_V"); + oct.setTransformOutputData(schema + "." + xformResult); + + // Specify the list of excluded attributes + String[] excludedList = new String[]{ + "CUST_ID", "CUST_GENDER" + }; + oct.setExcludeColumnList(excludedList); + + // Specify the type of clipping: trim of winsorize ( default is trimming). + oct.setClippingType(clippingType); + + // Specify the tail fraction as 3% of values on both ends + oct.setTailFraction(0.03); + + ArrayList xformList = new ArrayList(); + xformList.add(oct); + //Create a transformation sequence object + OraTransformationSequence xformSeq = + m_xformFactory.createTransformationSequence( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + xformList, //List of transformations. In this case only one type of transformation i.e., supervised binning + schema + "." + xformResult // name of the transformation result + ); + String xformSeqName = "clp_" + clippingType.name() + "_xfSeq"; + m_dmeConn.saveObject(xformSeqName, xformSeq, true); + + OraTransformationTask xformTask = m_xformTaskFactory.create( + xformSeqName, false); + executeTask(xformTask, "xfromClip_jdm"); + + displayClippingResults( schema, xformResult, "AGE", clippingType); + } + + /** + * Illustrates how to perform Min-Max Normalization. The normalization + * definition for each attribute is computed based on the min and max + * values that are computed from the data. The values for shift and scale + * are computed to be shift = min, and scale = (max - min) respectively. + * + * @throws JDMException if transformation failed + */ + public static void normalizeMinMax() throws JDMException + { + normalizeData(OraNormalizeType.min_max, "MINING_DATA_NORMALIZE_MIN_MAX"); + } + + /** + * Illustrates how to perform Z-Score Normalization. The normalization + * definition for each attribute is computed based on the values for mean + * and standard deviation that are computed from the data. The values for + * shift and scale are computed to be shift = mean, and scale = standard + * deviation respectively. + * + * @throws JDMException if transformation failed + */ + public static void normalizeZScore() throws JDMException + { + normalizeData(OraNormalizeType.z_Score, "MINING_DATA_NORMALIZE_Z_SCORE"); + } + + /** + * Illustrates how to perform data normalization + * + * @param normalizeType type of normalization to perform + * @param xformResult name of the result transformation view + * @throws JDMException if transformation failed + */ + public static void normalizeData(OraNormalizeType normalizeType, String xformResult) + throws JDMException + { + // Schema where the original data and resulting transformations reside + String schema = ( m_dmeConn.getConnectionSpec().getName() ).toUpperCase(); + + OraNormalizeTransform ont = m_xformFactory.createNormalizeTransform( + normalizeType, + new Integer(6) + ); + + // Specify the list of excluded attributes + String[] excludedList = new String[]{ + "CUST_ID", "CUST_GENDER" + }; + ont.setExcludeColumnList(excludedList); + + ArrayList xformList = new ArrayList(); + xformList.add(ont); + //Create a transformation sequence object + OraTransformationSequence xformSeq = + m_xformFactory.createTransformationSequence( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + xformList, //List of transformations. In this case only one type of transformation i.e., supervised binning + schema + "." + xformResult // name of the transformation result + ); + String xformSeqName = "nmz_" + normalizeType.name() + "_xfSeq"; + m_dmeConn.saveObject(xformSeqName, xformSeq, true); + + OraTransformationTask xformTask = m_xformTaskFactory.create( + xformSeqName, false); + executeTask(xformTask, "xformNormalize_jdm"); + displayNormalizeResults( schema, "AGE", normalizeType, xformResult); + } + + /** + * Shows results of the normalization for selected attribute + * + * @param schema schema where result transformation view resides + * @param attribute name of the attribute which was normalized + * @param normalizeType type of normalization performed + * @param xformResult name of the result transformation view + */ + public static void displayNormalizeResults(String schema, + String attribute, + OraNormalizeType normalizeType, + String xformResult) + { + System.out.println("\nShowing results of the normalization transformation"); + System.out.println("\tNormalize type: " + + ( true == normalizeType.equals(OraNormalizeType.min_max) ? "min_max" : "z_score") ); + System.out.println("\tMinimum and maximum values for:" + attribute + + " before normalize transformation"); + + String sqlQuery = MessageFormat.format( + "SELECT MIN ({0}) MIN_VALUE, MAX ({0}) MAX_VALUE FROM ({1})", + new String[]{ "\""+attribute+"\"", + schema + "." + "MINING_DATA_BUILD_V"} + ); + getMinMax(sqlQuery); + + System.out.println("\tMinimum and maximum values for:" + attribute + + " after normalize transformation"); + sqlQuery = MessageFormat.format( + "SELECT MIN ({0}) MIN_VALUE, MAX ({0}) MAX_VALUE FROM ({1})", + new String[]{ "\""+attribute+"\"", + schema + "." + xformResult} + ); + getMinMax(sqlQuery); + } + + private static void showBinDefinitionTableContents(String tableName, String tableType) + { + //Bin definition tables have 3 columns + java.sql.Connection dbConn = ((OraConnection)m_dmeConn).getDatabaseConnection(); + String sql = "SELECT * FROM " + tableName; + + try{ + Vector results = OraSQLUtils.execSqlQuery(dbConn, sql, null ); + System.out.println("The contents of the " + tableType + " bin definition table."); + System.out.println("\n\tCOL\t\tVAL\t\tBIN"); + for ( int row = 0 ; row < results.size(); row++ ) { + StringBuffer sb = new StringBuffer("\t"); + Object element = results.elementAt(row); + if ( element == null ) + throw new Exception("Failure reading " + tableType + + " table. Reason: data is null"); + if ( false == element instanceof Object[] ) + throw new Exception("Failure reading " + tableType + + " table. Wrong data format."); + Object[] singleRow = (Object[])element; + for ( int col = 0 ; col < singleRow.length; col++ ) { + if ( singleRow[col] != null && singleRow[col] instanceof BigDecimal ) + sb.append( m_df.format(singleRow[col]) + "\t\t"); + else + sb.append( (singleRow[col] != null ? singleRow[col].toString() : "") + + "\t\t"); + } + System.out.println(sb.toString()); + } + } + catch(Exception e){ + System.out.println("Failed to display the contents of the table: " + + tableName + ". Reason: "); + } + } + + private static OraAttributeBins[] incrementArray(OraAttributeBins[] srcArray, + OraAttributeBins[] newArray) + { + if ( newArray == null ) + return srcArray; + + // if final array has not been created yet, check + // wheather new array contains data + if ( srcArray == null ) { + if (newArray == null) + return null; + + // if the new array has data, allocate a new array, + // copies the newArray into the resultArray and returns resultArray + OraAttributeBins[] resultArray = new OraAttributeBins[newArray.length]; + System.arraycopy(newArray, 0, resultArray, 0, newArray.length); + return resultArray; + } + + //srcArray already has some data + OraAttributeBins[] resultArray = new OraAttributeBins[srcArray.length + + newArray.length]; + // copy original data into the result array + System.arraycopy(srcArray, 0, resultArray, 0, srcArray.length); + // copy the new data into the result array + System.arraycopy(newArray, 0, resultArray, srcArray.length, newArray.length); + return resultArray; + } +} diff --git a/epgdemo.sql b/epgdemo.sql new file mode 100644 index 0000000..9cb45a2 --- /dev/null +++ b/epgdemo.sql @@ -0,0 +1,80 @@ +Rem +Rem $Header: epgdemo.sql 02-nov-2006.11:39:35 rpang Exp $ +Rem +Rem epgdemo.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem epgdemo.sql - Demo program for the embedded PL/SQL gateway +Rem +Rem DESCRIPTION +Rem This is a sample program to demonstrate the usage of the embedded +Rem PL/SQL gateway. +Rem +Rem NOTES +Rem This demo requires Oracle XML DB installed and the demo account SCOTT. +Rem +Rem To execute this demo, you need to start the XML DB HTTP listener and +Rem to unlock the database account "anonymous". +Rem +Rem > sqlplus system/ +Rem +Rem SQL> Rem Start XML DB HTTP listener: +Rem SQL> exec dbms_xdb.setHttpPort(8080); +Rem +Rem SQL> Rem Unlock the database account "anonymous": +Rem SQL> alter user anonymous account unlock; +Rem +Rem Then, execute this demo script to set up the database access +Rem descriptor (DAD) and to create the demo program in the account SCOTT: +Rem +Rem SQL> @epgdemo.sql +Rem +Rem Then, open the URL http://:8080/demo/plsql/hello +Rem +Rem *** Security notes *** +Rem This demo requires the database account "anonymous" to be unlocked +Rem so that the demo program "hello" can be accessed from the browser +Rem without authentication. You should ensure that all XML DB repository +Rem resources and servlets which are not intended for unauthenticated +Rem access are properly secured. Please refer to the XML DB documentation +Rem on protecting its repository resources and servlets. +Rem ********************** +Rem +Rem MODIFIED (MM/DD/YY) +Rem rpang 11/02/06 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +Rem Set up the database access descriptor (DAD) as SYSTEM + +begin + dbms_epg.create_dad('DemoDAD', '/demo/plsql/*'); + dbms_epg.set_dad_attribute('DemoDAD', 'database-username', 'SCOTT'); +end; +/ + +Rem Create the demo program as SCOTT + +connect scott/tiger + +begin + /* Authorize DemoDAD to use my schema and my privileges */ + dbms_epg.authorize_dad('DemoDAD'); +end; +/ + +create or replace procedure hello is +begin + /* Generate "Hello, World!" in HTML */ + htp.print('Hello, World!'); +end; +/ diff --git a/exfdemo.sql b/exfdemo.sql new file mode 100644 index 0000000..6e8bfc9 --- /dev/null +++ b/exfdemo.sql @@ -0,0 +1,718 @@ +Rem +Rem $Header: exfdemo.sql 16-sep-2003.10:14:13 ayalaman Exp $ +Rem +Rem exfdemo.sql +Rem +Rem Copyright (c) 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem exfdemo.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ayalaman 09/16/03 - ayalaman_quoted_names_bug +Rem ayalaman 08/27/03 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +connect scott/tiger +set linesize 200; +column associated_table format a12; +column attribute format a15; +column attribute_exp format a13; +column attribute_set_name format a8; +column data_type format a12; +column expr_table format a10; +column expr_column format a10; +column expset_table format a10; +column expset_column format a10; +column index_name format a18; +column interest format a40; +column operator_list format a25; +column subexpression format a12; +column udf_name format a20; +column xmltype_attr format a10; + +/***************************************************************** + The tests in this file are organized as follows: + 1. Basic Functionality + 1.1 Creation of the attribute set + 1.2 Adding user-defined functions to the attribute set + 1.3 Creation of an Expression datatype column in a user table + 1.4 Multiple forms of EVALUATE operator + 2. Expression Filter Index (EE) + 2.1 Using Default index parameters + 2.2 Using Exact index parameters + 2.3 Using Expression Statistics + 3. EVALUATE operator used in joins + 3.1 Batch evaluation + 3.2 Active application using trigger + 4. Expressions defined for table data + 5. XPath predicates in expressions + 5.1 Use of XMLType attribute + 5.2 Indexing XPath expressions + 6. DML With EVALUATE Operator +******************************************************************/ +-------------------------- +--- 1. Basic functionality +-------------------------- + +-- 1.1 Creation of attribute set + +--- create the attribute set incrementally +BEGIN + dbms_expfil.create_attribute_set(attr_set => 'Car4Sale'); + + dbms_expfil.add_elementary_attribute (attr_set => 'Car4Sale', + attr_name => 'Model', + attr_type => 'VARCHAR2(20)'); + + dbms_expfil.add_elementary_attribute (attr_set => 'Car4Sale', + attr_name => 'Year', + attr_type => 'NUMBER'); + + dbms_expfil.add_elementary_attribute (attr_set => 'Car4Sale', + attr_name => 'Price', + attr_type => 'NUMBER'); + + dbms_expfil.add_elementary_attribute (attr_set => 'Car4Sale', + attr_name => 'Mileage', + attr_type => 'NUMBER'); +END; +/ + +select attribute_set_name, attribute, data_type + from user_expfil_attributes; + +exec dbms_expfil.drop_attribute_set (attr_set => 'Car4Sale'); + +--- create the same attribute set using an abstract type +CREATE OR REPLACE TYPE Car4Sale AS OBJECT + (Model VARCHAR2(20), + Year NUMBER, + Price NUMBER, + Mileage NUMBER); +/ + +BEGIN + dbms_expfil.create_attribute_set (attr_set => 'Car4Sale', + from_type => 'YES'); +END; +/ + +select attribute_set_name, attribute, data_type + from user_expfil_attributes; + +-- 1.2 Adding user-defined functions to the attribute set + +--- create the functions required in the expressions +CREATE or REPLACE FUNCTION HorsePower(Model VARCHAR2, Year VARCHAR2) + return NUMBER is +BEGIN + return 200; +END HorsePower; +/ + +CREATE or REPLACE FUNCTION CrashTestRating(Model VARCHAR2, Year VARCHAR2) + return NUMBER is +BEGIN + return 5; +END CrashTestRating; +/ + +--- add the functions to the attribute set so that they can be used +--- in the corresponding expressions +BEGIN + dbms_expfil.add_functions (attr_set => 'Car4Sale', + funcs_name => 'HorsePower'); + dbms_expfil.add_functions (attr_set => 'Car4Sale', + funcs_name => 'CrashTestRating'); +END; +/ + +select attribute_set_name, udf_name, object_type + from user_expfil_aset_functions; + +-- 1.3 Creation of an Expression datatype column in a user table + +--- create a table with a VARCHAR2 column to hold expressions -- +CREATE TABLE Consumer (CId NUMBER, + Zipcode NUMBER, + Phone VARCHAR2(12), + Interest VARCHAR2(200)); + +--- assign the attribute set to the VARCHAR2 column to convert it -- +--- into an expression column -- +BEGIN + dbms_expfil.assign_attribute_set (attr_set => 'Car4Sale', + expr_tab => 'Consumer', + expr_col => 'Interest'); +END; +/ + +select expr_table, expr_column, attribute_set + from user_expfil_expression_sets; + +--- insert data (with expressions) into the Consumer table -- +INSERT INTO Consumer VALUES (1, 32611, '917 768 4633', + 'Model=''Taurus'' and Price < 15000 and Mileage < 25000'); +INSERT INTO Consumer VALUES (2, 03060, '603 983 3464', + 'Model=''Mustang'' and Year > 1999 and Price < 20000'); +INSERT INTO Consumer VALUES (3, 03060, '603 484 7013', + 'HorsePower(Model, Year) > 200 and Price < 20000'); + + +-- 1.4 Multiple forms of EVALUATE operator to evaluate the expressions +--- string formatted data item +SELECT * FROM Consumer + WHERE EVALUATE (Consumer.Interest, 'Model =>''Mustang'', + Year => 2000, + Price => 18000, + Mileage => 22000') = 1; + +--- data item as an Anydata instance +SELECT * FROM Consumer + WHERE EVALUATE (Consumer.Interest, + AnyData.convertObject(Car4Sale('Mustang', + 2000, + 18000, + 22000))) = 1; + +--- string formatted data item generated by STATIC getVarchar API +SELECT * FROM Consumer + WHERE EVALUATE (Consumer.Interest, + Car4Sale.getVarchar('Mustang', + 2000, + 18000, + 22000)) = 1; + +--- string formatted data item generated by MEMBER getVarchar API +SELECT * FROM Consumer + WHERE EVALUATE (Consumer.Interest, + Car4Sale('Mustang', + 2000, + 18000, + 22000).getVarchar()) = 1; + +--- applying additional predicates in the same query +SELECT * FROM Consumer + WHERE Zipcode between 03060 and 03070 and + EVALUATE (Consumer.Interest, + Car4Sale.getVarchar('Mustang', + 2000, + 18000, + 22000)) = 1 + +----------------------------------------------------- +--- 2. Expression Filter indexes on Expression column +----------------------------------------------------- + +-- 2.1 Default parameters associated with the attribute set + +--- assign default index parameters to the attribute set +BEGIN + dbms_expfil.default_index_parameters ( + attr_set => 'Car4Sale', + attr_list => exf$attribute_list ( + exf$attribute (attr_name => 'Model', --- LHS for predicate group + attr_oper => exf$indexoper('='), + attr_indexed => 'TRUE'), --- indexed predicate group + exf$attribute (attr_name => 'Price', + attr_oper => exf$indexoper('all'), + attr_indexed => 'TRUE'), + exf$attribute (attr_name => 'HorsePower(Model, Year)', + attr_oper => exf$indexoper('=','<','>','>=','<='), + attr_indexed => 'FALSE') --- stored predicate group + )); +END; +/ + +select attribute_set_name, attribute, indexed, operator_list + from user_expfil_def_index_params; + +--- create the index using default parameters +CREATE INDEX InterestIndex ON Consumer (Interest) + INDEXTYPE IS EXFSYS.EXPFILTER; + +select index_name, subexpression, indexed, operator_list + from user_expfil_predtab_attributes; + +DROP INDEX InterestIndex; + +--- extend the default parameters at the time of index creation +CREATE INDEX InterestIndex ON Consumer (Interest) + INDEXTYPE IS EXFSYS.EXPFILTER PARAMETERS ( + 'ADD TO DEFAULTS STOREATTRS (CrashTestRating(Model, Year))'); + +select index_name, subexpression, indexed, operator_list + from user_expfil_predtab_attributes; + +DROP INDEX InterestIndex; + +-- 2.2 Exact index paremeters for each expression column + +--- associate the index parameters with the expression column by +--- deriving from defaults and fine tuning them +BEGIN + -- derive index parameters from defaults + dbms_expfil.index_parameters ( + expr_tab => 'Consumer', + expr_col => 'Interest', + attr_list => null, + operation => 'DEFAULT'); + + -- fine-tune the parameters by adding another stored attribute + dbms_expfil.index_parameters( + expr_tab => 'Consumer', + expr_col => 'Interest', + attr_list => exf$attribute_list ( + exf$attribute ( + attr_name => 'CrashTestRating(Model, Year)', + attr_oper => exf$indexoper('all'), + attr_indexed => 'FALSE')), + operation => 'ADD'); +END; +/ + +select expset_table, expset_column, attribute, indexed, operator_list + from user_expfil_index_params; + +-- create the index; uses the parameters associated with expression column +CREATE INDEX InterestIndex ON Consumer (Interest) + INDEXTYPE IS EXFSYS.EXPFILTER; + +select index_name, subexpression, indexed, operator_list + from user_expfil_predtab_attributes; + +DROP INDEX InterestIndex; + +-- 2.3 Using Expression Statistics for the expression column + +--- collect the expression set statistics -- +BEGIN + dbms_expfil.get_exprset_stats (expr_tab => 'Consumer', + expr_col => 'Interest'); +END; +/ + +select expr_table, expr_column, attribute_exp, pct_occurrence, + pct_eq_oper + from user_expfil_exprset_stats order by pct_occurrence, attribute_exp desc; + +--- clear the exact parameters so that we can use the statistics +BEGIN + -- derive index parameters from defaults + dbms_expfil.index_parameters ( + expr_tab => 'Consumer', + expr_col => 'Interest', + attr_list => null, + operation => 'CLEAR'); +END; +/ + +--- create the index using the statistics --- +CREATE INDEX InterestIndex ON Consumer (Interest) + INDEXTYPE IS EXFSYS.EXPFILTER PARAMETERS ( + 'STOREATTRS TOP 4 INDEXATTRS TOP 2'); + +select index_name, subexpression, indexed, operator_list + from user_expfil_predtab_attributes; + +-------------------------------------- +--- 3. EVALUATE Operator used in joins +-------------------------------------- + +--- 3.1 Batch evaluation of expression using joins + +--- Create a table to store information about cars --- +CREATE TABLE CarInventory OF Car4Sale; + +INSERT INTO CarInventory VALUES ('Mustang',2000, 18000,22000); +INSERT INTO CarInventory VALUES ('Mustang',2000, 18000,22000); +INSERT INTO CarInventory VALUES ('Taurus',1997, 14000,24500); + +--- Join the CarInventory with the Consumer table -- +SELECT Consumer.CId, Consumer.Interest, Car.Model + FROM Consumer, CarInventory Car + WHERE EVALUATE (Consumer.Interest, Car.getVarchar()) = 1; + +DROP TABLE CarInventory; + +--- A table not relying on the Car4Sale object type -- +CREATE TABLE inventory (Model VARCHAR2(20), + Year NUMBER, + Price NUMBER, + Mileage NUMBER); + +INSERT INTO Inventory VALUES ('Mustang',2000, 18000, 22000); +INSERT INTO Inventory VALUES ('Mustang',2000, 18000, 22000); +INSERT INTO Inventory VALUES ('Taurus',1997, 14000, 24500); + +--- simple join -- +SELECT Consumer.CId, Consumer.Interest, Inventory.Model + FROM Consumer, Inventory + WHERE EVALUATE (Consumer.Interest, + Car4Sale.getVarchar(Inventory.Model, + Inventory.Year, + Inventory.Price, + Inventory.Mileage)) = 1; + + +--- demand analysis for the cars in the inventory +SELECT DISTINCT Inventory.Model, count(*) as Demand + FROM Consumer, Inventory + WHERE EVALUATE (Consumer.Interest, + Car4Sale.getVarchar(Inventory.Model, + Inventory.Year, + Inventory.Price, + Inventory.Mileage)) = 1 + GROUP BY Inventory.Model + ORDER BY Demand DESC; + +truncate table Inventory; + +-- 3.2 Active application using trigger + +--- create a trigger on the inventory table to track new data +CREATE TRIGGER activechk AFTER insert OR update ON Inventory + FOR EACH ROW +DECLARE + cursor c1 (ditem VARCHAR2) is + SELECT CId, Phone FROM Consumer WHERE EVALUATE (Interest, ditem) = 1; + ditem VARCHAR2(200); +BEGIN + ditem := Car4Sale.getVarchar(:new.Model, :new.Year, :new.Price, :new.Mileage); + for cur in c1(ditem) loop + dbms_output.put_line(' For Model '||:new.Model||' Call '||cur.CId|| + ' @ '||cur.Phone); + end loop; +END; +/ + +set serveroutput on; +--- insert data into the inventory table +INSERT INTO Inventory VALUES ('Mustang',2000, 18000,22000); +INSERT INTO Inventory VALUES ('Mustang',2000, 18000,22000); +INSERT INTO Inventory VALUES ('Taurus',1997, 14000, 24500); + +set serveroutput off; + +drop table Inventory; +drop table Consumer; +exec dbms_expfil.drop_attribute_set (attr_set => 'Car4Sale'); +drop type Car4Sale; +drop function HorsePower; +drop function CrashTestRating; + +---------------------------------------------------------------- +--- 4. Expressions defined for table data (use of table aliases) +---------------------------------------------------------------- + +--- create an attribute set with two table alias attributes referring +--- to SCOTT schema's EMP and DEPT tables. + +BEGIN + dbms_expfil.create_attribute_set('hrdb'); + -- add elementary attributes to the Attribute Set -- + dbms_expfil.add_elementary_attribute('hrdb', 'hrmgr', 'VARCHAR2(20)'); + + -- define elementary attributes of EXF$TABLE_ALIAS type -- + dbms_expfil.add_elementary_attribute('hrdb', 'emp', + exf$table_alias('scott.emp')); + dbms_expfil.add_elementary_attribute('hrdb', 'dept', + exf$table_alias('scott.dept')); +END; +/ + +select attribute_set_name, attribute, data_type, associated_table + from user_expfil_attributes; + +--- create an expression column in a user table and configure it with +--- HEDB attribute set. +CREATE TABLE HRInterest (SubId number, Interest VARCHAR2(100)); + +BEGIN + dbms_expfil.assign_attribute_set('hrdb', 'HRInterest', 'Interest'); +END; +/ + +--- insert expressions referring to table data -- +INSERT INTO HRInterest VALUES (1, + 'hrmgr=''Greg'' and emp.job=''SALESMAN'' and emp.deptno = dept.deptno + and dept.loc = ''CHICAGO'''); +INSERT INTO HRInterest VALUES (2, + 'emp.job=''MANAGER'' and emp.sal < 2500'); + +--- create index for the expression column -- +CREATE INDEX HRIndex ON HRInterest (Interest) + INDEXTYPE IS EXFSYS.EXPFILTER PARAMETERS ( + 'STOREATTRS (emp.job, dept.loc, hrmgr) INDEXATTRS (emp.job, hrmgr)'); + +--- assign values for table alias attributes through joins -- +SELECT empno, job, sal, loc, SubId, Interest + FROM emp, dept, HRInterest + WHERE emp.deptno = dept.deptno and + EVALUATE(Interest, + hrdb.getVarchar('Greg',emp.rowid,dept.rowid)) = 1; + +SELECT empno, job, sal, loc, SubId, Interest + FROM emp, dept, HRInterest + WHERE emp.deptno = dept.deptno and emp.sal > 1400 and + EVALUATE(Interest, + hrdb.getVarchar('Greg',emp.rowid,dept.rowid)) = 1; + +drop table HRInterest; +exec dbms_expfil.drop_attribute_set('hrdb'); + +-------------------------------------- +--- 5. XPath predicates in expressions +-------------------------------------- + +--- 5.1 SYS.XMLType attribute in the attribute set +CREATE OR REPLACE TYPE Car4Sale AS OBJECT + (Model VARCHAR2(20), + Year NUMBER, + Price NUMBER, + Mileage NUMBER, + Details sys.XMLType); +/ + +BEGIN + dbms_expfil.create_attribute_set (attr_set => 'Car4Sale', + from_type => 'YES'); +END; +/ + +--- create expression column in a user table +CREATE TABLE Consumer (CId NUMBER, + Zipcode NUMBER, + Phone VARCHAR2(12), + Interest VARCHAR2(200)); + +BEGIN + dbms_expfil.assign_attribute_set (attr_set => 'Car4Sale', + expr_tab => 'Consumer', + expr_col => 'Interest'); +END; +/ + +--- insert expression with XPath predicates in the table +INSERT INTO Consumer VALUES (1, 32611, '917 768 4633', +'Model=''Taurus'' and Price < 15000 and Mileage < 25000 and +extract(Details, ''//stereo[@make="Koss"]'') is not null'); + +INSERT INTO Consumer VALUES (2, 03060, '603 983 3464', +'Model=''Mustang'' and Year > 1999 and Price < 20000 and +extract(Details, ''//stereo[@make="Koss" and /*/*/GPS/memory[text()="64MB"]]'') is not null'); + +INSERT INTO Consumer VALUES (3, 03060, '603 484 7013', +'Model=''Taurus'' and Price < 15000 and Mileage < 25000 and +existsNode(Details, ''//stereo[@make="Koss"]'') = 1'); + +--- evaluate the expressions for a data item -- +SELECT * FROM Consumer + WHERE EVALUATE (Consumer.Interest, + 'Model => ''Mustang'', + Year => 2000, + Price => 18000, + Mileage => 22000, + Details => + sys.XMLType(''
+ White + + CD + + 1FT + 64MB + + +
'')') = 1; + +SELECT * FROM Consumer + WHERE EVALUATE (Consumer.Interest, + AnyData.convertObject( + Car4Sale('Mustang', + 2000, + 18000, + 22000, + '
+ White + + CD + + 1FT + 64MB + + +
'))) = 1; + +--- 5.2 Indexing XPath expressions + +--- default index parameters associated with the attribute set +BEGIN + --- parameters for non-XMLType attributes + dbms_expfil.default_index_parameters( + attr_set => 'Car4Sale', + attr_list => exf$attribute_list ( + exf$attribute (attr_name => 'Model', + attr_oper => exf$indexoper('='), + attr_indexed => 'TRUE'), + exf$attribute (attr_name => 'Price', + attr_oper => exf$indexoper('all'), + attr_indexed => 'FALSE') + )); + + --- parameters for XMLType attributes + dbms_expfil.default_xpindex_parameters ( + attr_set => 'Car4Sale', + xmlt_attr => 'Details', --- XMLType Attribute + xptag_list => --- Tag list + exf$xpath_tags( + exf$xpath_tag(tag_name => 'stereo@make', --- XML Attribute + tag_indexed => 'TRUE', + tag_type => 'VARCHAR(15)'), --- value filter + exf$xpath_tag(tag_name => 'stereo', --- XML Element + tag_indexed => 'FALSE', + tag_type => null), --- positional filter + exf$xpath_tag(tag_name => 'memory', --- XML Element + tag_indexed => 'TRUE', + tag_type => 'VARCHAR(10)') --- value filter + )); +END; +/ + +select attribute_set_name, attribute, indexed, operator_list, xmltype_attr + from user_expfil_def_index_params; + +--- create the index using defaults -- +CREATE INDEX InterestIndex ON Consumer (Interest) + INDEXTYPE IS EXFSYS.EXPFILTER; + +select index_name, subexpression, indexed, operator_list, xptag_type, + xpfilter_type +from user_expfil_predtab_attributes; + +DROP INDEX InterestIndex; + +--- index paramters assigned to the expression column -- +BEGIN + -- Derive the index parameters from defaults -- + dbms_expfil.index_parameters ( + expr_tab => 'Consumer', + expr_col => 'Interest', + attr_list => null, + operation => 'DEFAULT'); + + -- fine-tune the XPath index parameters by adding another Tag -- + dbms_expfil.xpindex_parameters ( + expr_tab => 'Consumer', + expr_col => 'Interest', + xmlt_attr => 'Details', + xptag_list => + exf$xpath_tags ( + exf$xpath_tag(tag_name => 'GPS', + tag_indexed => 'TRUE', + tag_type => null)), + operation => 'ADD'); +END; +/ + +select expset_table, expset_column, attribute, indexed, operator_list, + xmltype_attr + from user_expfil_index_params; + +--- create the index using the parameters associated with the expr col. +CREATE INDEX InterestIndex ON Consumer (Interest) + INDEXTYPE IS EXFSYS.EXPFILTER; + +select index_name, subexpression, indexed, operator_list, xptag_type, + xpfilter_type +from user_expfil_predtab_attributes; + +SELECT * FROM Consumer + WHERE EVALUATE (Consumer.Interest, + 'Model => ''Mustang'', + Year => 2000, + Price => 18000, + Mileage => 22000, + Details => + sys.XMLType(''
+ White + + CD + + 1FT + 64MB + + +
'')') = 1; + +drop table Consumer; +exec dbms_expfil.drop_attribute_set('Car4Sale'); +drop type Car4Sale; + +--- 6. DML with EVALUATE Operator + +--- create the attribute set +CREATE OR REPLACE TYPE ITTicket AS OBJECT ( + Priority NUMBER, + Environment VARCHAR2(10), + Organization VARCHAR2(10)); +/ + +BEGIN + dbms_expfil.create_attribute_set(attr_set => 'ITTicket', + from_type => 'Yes'); +END; +/ + +--- create the table storing expressions +CREATE TABLE ITResource (RId NUMBER, + Duties VARCHAR2(100)); + +BEGIN +dbms_expfil.assign_attribute_set(attr_set => 'ITTicket', + expr_tab => 'ITResource', + expr_col => 'Duties'); +END; +/ + +INSERT INTO ITResource (RId, Duties) VALUES + (1, 'Priority <= 2 and Environment = ''NT'' and Organization = ''Research'''); + +INSERT INTO ITResource (RId, Duties) VALUES + (2, 'Priority = 1 and (Environment = ''UNIX'' or Environment = ''LINUX'') + and Organization = ''APPS'''); + +--- create the table for data items +CREATE TABLE ITProblem (PId NUMBER, + Description ITTicket, + AssignedTo NUMBER); + +insert into ITProblem values (1, ITTicket(2,'NT','Research'), NULL); +insert into ITProblem values (2, ITTicket(1,'UNIX','APPS'), NULL); + +--- Update the ITProblem to table to assign the tickets to appropriate +--- ITResource +UPDATE ITProblem p SET AssignedTo = + (SELECT RId FROM ITResource r + WHERE EVALUATE(r.Duties, p.Description.getVarchar()) = 1 and + rownum < 2) +WHERE AssignedTo is NULL; + +drop table itproblem; +drop table itresource; +exec dbms_expfil.drop_attribute_set('itticket'); +drop type itticket; + diff --git a/extdemo0.sql b/extdemo0.sql new file mode 100644 index 0000000..ed51bcc --- /dev/null +++ b/extdemo0.sql @@ -0,0 +1,34 @@ +rem +rem $Header: extdemo0.sql 14-jul-99.13:55:39 mjaeger Exp $ +rem +rem extdemo0.sql +rem +rem Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem extdemo0.sql - explain plan script +rem +rem DESCRIPTION +rem This file contains the SQL statements to print +rem the output of explain plan. +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem hdnguyen 07/26/99 - sqlplus conversion +rem rmurthy 09/25/98 - minor changes +rem rmurthy 07/15/98 - extensibility - explain plan script +rem rmurthy 07/15/98 - Created + +SELECT operation operations, + decode(options, 'BY INDEX ROWID', 'BY ROWID', + 'BY USER ROWID', 'BY ROWID', + options) options, + object_name +FROM plan_table +ORDER BY id; + +TRUNCATE TABLE plan_table; + diff --git a/extdemo1.sql b/extdemo1.sql new file mode 100644 index 0000000..f67538f --- /dev/null +++ b/extdemo1.sql @@ -0,0 +1,2016 @@ +rem +rem $Header: extdemo1.sql 16-oct-2002.11:53:50 ayoaz Exp $ +rem +rem extdemo1.sql +rem +rem Copyright (c) 1998, 2002, Oracle Corporation. All rights reserved. +rem +rem NAME +rem extdemo1.sql - A power company example +rem +rem DESCRIPTION +rem This is an example of a data cartridge which uses +rem object types and the extensible indexing framework. +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem ayoaz 10/16/02 - add cardinality arg to ODCIArgDesc +rem ddas 03/12/01 - use 9i interfaces +rem rmurthy 03/09/01 - bug 1676437 - change call to extdemo0 +rem hdnguyen 02/15/01 - added order by to selects +rem ddas 02/10/01 - modify table data and cost functions +rem ddas 05/25/00 - 8.2 interface change +rem rmurthy 01/12/00 - add path name while calling utlxplan +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem hdnguyen 07/26/99 - sqlplus conversion +rem ddas 06/25/99 - extend example to use extensible optimizer +rem rmurthy 09/25/98 - add explain plans +rem rmurthy 07/15/98 - extensibility demo +rem rmurthy 07/15/98 - Created + +SET ECHO ON +CONNECT sys/knl_test7 AS sysdba; + +-- Clean up from any previous running of this procedure. +DROP USER PowerCartUser CASCADE; + +-- Create the user for schema objects. +CREATE USER PowerCartUser IDENTIFIED BY PowerCartUser; + +------------------------------------------------------------------- +-- INITIAL SET-UP +------------------------------------------------------------------- +-- Grant privileges -- +GRANT connect, resource to PowerCartUser; +GRANT create table to PowerCartUser; + +------------------------------------------------------------------- +-- CREATE POWERTYPE -- +------------------------------------------------------------------- +CONNECT PowerCartUser/PowerCartUser +set echo off +@'?/rdbms/admin/utlxplan.sql' +set echo on + +-- Create table for user-defined statistics +CREATE TABLE PowerCartUserStats ( + -- Table for which statistics are collected + tab VARCHAR2(30), + -- Column for which statistics are collected + col VARCHAR2(30), + -- Cell position + cpos NUMBER, + -- Minimum power demand for the given cell + lo NUMBER, + -- Maximum power demand for the given cell + hi NUMBER, + -- Number of (non-null) power demands for the given cell + nrows NUMBER +); + +-- Type used in the definition of PowerDemand_Typ + +CREATE OR REPLACE TYPE PowerGrid_Typ as VARRAY(100) of NUMBER; +/ +CREATE OR REPLACE TYPE NumTab_Typ as TABLE of NUMBER; +/ +-- The object type used for this example. Contains 3 +-- attributes that will be set by the 3 member procedures; +-- also a power demand grid (array) and the date/time for +-- the samplings (readings). + +CREATE OR REPLACE TYPE PowerDemand_Typ AS OBJECT ( + -- Total power demand for the grid + TotGridDemand NUMBER, + -- Call with maximum/minimum power demand for the grid + MaxCellDemand NUMBER, + MinCellDemand NUMBER, + -- Power grid: 10X10 array represented as Varray(100) + -- using previously defined PowerGrid_Typ + CellDemandValues PowerGrid_Typ, + -- Date/time for power-demand samplings: Every hour, + -- 100 power stations transmit their power demand + -- readings. + SampleTime DATE, + -- + -- Methods (Set...) for this type: + -- Total demand for the entire power grid for a + -- SampleTime: sets the value of TotGridDemand. + Member Procedure SetTotalDemand, + -- Maximum demand for the entire power grid for a + -- SampleTime: sets the value of MaxCellDemand. + Member Procedure SetMaxDemand, + -- Minimum demand for the entire power grid for a + -- SampleTime: sets the value of MinCellDemand. + Member Procedure SetMinDemand +); +/ +show errors; + +CREATE OR REPLACE TYPE BODY PowerDemand_Typ +IS + -- + -- Methods (Set...) for this type: + -- Total demand for the entire power grid for a + -- SampleTime: sets the value of TotGridDemand. + Member Procedure SetTotalDemand + IS + I BINARY_INTEGER; + Total NUMBER; + BEGIN + Total :=0; + I := CellDemandValues.FIRST; + WHILE I IS NOT NULL LOOP + Total := Total + CellDemandValues(I); + I := CellDemandValues.NEXT(I); + END LOOP; + TotGridDemand := Total; + END; + + -- Maximum demand for the entire power grid for a + -- SampleTime: sets the value of MaxCellDemand. + Member Procedure SetMaxDemand + IS + I BINARY_INTEGER; + Temp NUMBER; + BEGIN + I := CellDemandValues.FIRST; + Temp := CellDemandValues(I); + WHILE I IS NOT NULL LOOP + IF Temp < CellDemandValues(I) THEN + Temp := CellDemandValues(I); + END IF; + I := CellDemandValues.NEXT(I); + END LOOP; + MaxCellDemand := Temp; + END; + + -- Minimum demand for the entire power grid for a + -- SampleTime: sets the value of MinCellDemand. + Member Procedure SetMinDemand + IS + I BINARY_INTEGER; + Temp NUMBER; + BEGIN + I := CellDemandValues.FIRST; + Temp := CellDemandValues(I); + WHILE I IS NOT NULL LOOP + IF Temp > CellDemandValues(I) THEN + Temp := CellDemandValues(I); + END IF; + I := CellDemandValues.NEXT(I); + END LOOP; + MinCellDemand := Temp; + END; +END; +/ +show errors; + +------------------------------------------------------------------- +-- CREATE FUNCTIONS AND OPERATORS +------------------------------------------------------------------- + +CREATE FUNCTION Power_EqualsSpecific_Func( + object PowerDemand_Typ, cell NUMBER, value NUMBER) +RETURN NUMBER AS + BEGIN + IF cell <= object.CellDemandValues.LAST + THEN + IF (object.CellDemandValues(cell) = value) THEN + RETURN 1; + ELSE + RETURN 0; + END IF; + ELSE + RETURN NULL; + END IF; + END; +/ + +CREATE FUNCTION Power_GreaterThanSpecific_Func( + object PowerDemand_Typ, cell NUMBER, value NUMBER) +RETURN NUMBER AS + BEGIN + IF cell <= object.CellDemandValues.LAST + THEN + IF (object.CellDemandValues(cell) > value) THEN + RETURN 1; + ELSE + RETURN 0; + END IF; + ELSE + RETURN NULL; + END IF; + END; +/ + +CREATE FUNCTION Power_LessThanSpecific_Func( + object PowerDemand_Typ, cell NUMBER, value NUMBER) +RETURN NUMBER AS + BEGIN + IF cell <= object.CellDemandValues.LAST + THEN + IF (object.CellDemandValues(cell) < value) THEN + RETURN 1; + ELSE + RETURN 0; + END IF; + ELSE + RETURN NULL; + END IF; + END; +/ + +CREATE FUNCTION Power_EqualsAny_Func( + object PowerDemand_Typ, value NUMBER) +RETURN NUMBER AS + idx NUMBER; + BEGIN + FOR idx IN object.CellDemandValues.FIRST..object.CellDemandValues.LAST LOOP + IF (object.CellDemandValues(idx) = value) THEN + RETURN 1; + END IF; + END LOOP; + + RETURN 0; + END; +/ + +CREATE FUNCTION Power_GreaterThanAny_Func( + object PowerDemand_Typ, value NUMBER) +RETURN NUMBER AS + idx NUMBER; + BEGIN + FOR idx IN object.CellDemandValues.FIRST..object.CellDemandValues.LAST LOOP + IF (object.CellDemandValues(idx) > value) THEN + RETURN 1; + END IF; + END LOOP; + + RETURN 0; + END; +/ + +CREATE FUNCTION Power_LessThanAny_Func( + object PowerDemand_Typ, value NUMBER) +RETURN NUMBER AS + idx NUMBER; + BEGIN + FOR idx IN object.CellDemandValues.FIRST..object.CellDemandValues.LAST LOOP + IF (object.CellDemandValues(idx) < value) THEN + RETURN 1; + END IF; + END LOOP; + + RETURN 0; + END; +/ + + +CREATE OPERATOR Power_Equals BINDING(PowerDemand_Typ, NUMBER, NUMBER) + RETURN NUMBER USING Power_EqualsSpecific_Func; +CREATE OPERATOR Power_GreaterThan BINDING(PowerDemand_Typ, NUMBER, NUMBER) + RETURN NUMBER USING Power_GreaterThanSpecific_Func; +CREATE OPERATOR Power_LessThan BINDING(PowerDemand_Typ, NUMBER, NUMBER) + RETURN NUMBER USING Power_LessThanSpecific_Func; + +CREATE OPERATOR Power_EqualsAny BINDING(PowerDemand_Typ, NUMBER) + RETURN NUMBER USING Power_EqualsAny_Func; +CREATE OPERATOR Power_GreaterThanAny BINDING(PowerDemand_Typ, NUMBER) + RETURN NUMBER USING Power_GreaterThanAny_Func; +CREATE OPERATOR Power_LessThanAny BINDING(PowerDemand_Typ, NUMBER) + RETURN NUMBER USING Power_LessThanAny_Func; + +------------------------------------------------------------------- +-- Create package used by ODCIIndexGetMetadata +------------------------------------------------------------------- +CREATE OR REPLACE PACKAGE power_pkg AS + FUNCTION getversion(idxschema IN VARCHAR2, idxname IN VARCHAR2, + newblock OUT PLS_INTEGER) RETURN VARCHAR2; + PROCEDURE checkversion (version IN VARCHAR2); +END power_pkg; +/ +SHOW ERRORS; + +CREATE OR REPLACE PACKAGE BODY power_pkg AS + +-- iterate is a package level variable used to maintain state across calls +-- by export in this session. + +iterate NUMBER := 0; + +FUNCTION getversion(idxschema IN VARCHAR2, idxname IN VARCHAR2, + newblock OUT PLS_INTEGER) RETURN VARCHAR2 IS + +BEGIN + +-- We are generating only one PL/SQL block consisting of one line of code. + newblock := 1; + + IF iterate = 0 + THEN +-- Increment iterate so we'll know we're done next time we're called. + iterate := iterate + 1; + +-- Return a string that calls checkversion with a version 'V1.0' +-- Note that export adds the surrounding BEGIN/END pair to form the anon. +-- block... we don't have to. + + RETURN 'power_pkg.checkversion(''V1.0'');'; + ELSE +-- reset iterate for next index + iterate := 0; +-- Return a 0-length string; we won't be called again for this index. + RETURN ''; + END IF; +END getversion; + +PROCEDURE checkversion (version IN VARCHAR2) IS + + wrong_version EXCEPTION; + +BEGIN + IF version != 'V1.0' THEN + RAISE wrong_version; + END IF; +END checkversion; + +END power_pkg; +/ +SHOW ERRORS; + +------------------------------------------------------------------- +-- CREATE INDEXTYPE IMPLEMENTATION TYPE +------------------------------------------------------------------- +CREATE OR REPLACE TYPE power_idxtype_im AS OBJECT +( + curnum NUMBER, + STATIC FUNCTION ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + RETURN NUMBER, + STATIC FUNCTION ODCIIndexCreate (ia sys.odciindexinfo, parms VARCHAR2, + env sys.ODCIEnv) + RETURN NUMBER, + STATIC FUNCTION ODCIIndexDrop(ia sys.odciindexinfo, + env sys.ODCIEnv) RETURN NUMBER, + STATIC FUNCTION ODCIIndexStart(sctx IN OUT power_idxtype_im, + ia sys.odciindexinfo, + op sys.odciPredInfo, qi sys.ODCIQueryInfo, + strt NUMBER, stop NUMBER, + cmppos NUMBER, cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER, + STATIC FUNCTION ODCIIndexStart(sctx IN OUT power_idxtype_im, + ia sys.odciindexinfo, + op sys.odciPredInfo, qi sys.ODCIQueryInfo, + strt NUMBER, stop NUMBER, + cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER, + MEMBER FUNCTION ODCIIndexFetch(nrows NUMBER, + rids OUT sys.odciridlist, env sys.ODCIEnv) + RETURN NUMBER, + MEMBER FUNCTION ODCIIndexClose(env sys.ODCIEnv) RETURN NUMBER, + STATIC FUNCTION ODCIIndexInsert(ia sys.odciindexinfo, rid VARCHAR2, + newval PowerDemand_Typ, env sys.ODCIEnv) RETURN NUMBER, + STATIC FUNCTION ODCIIndexDelete(ia sys.odciindexinfo, rid VARCHAR2, + oldval PowerDemand_Typ, env sys.ODCIEnv) RETURN NUMBER, + STATIC FUNCTION ODCIIndexUpdate(ia sys.odciindexinfo, rid VARCHAR2, + oldval PowerDemand_Typ, newval PowerDemand_Typ, env sys.ODCIEnv) + RETURN NUMBER, + STATIC FUNCTION ODCIIndexGetMetadata(ia sys.odciindexinfo, + expversion VARCHAR2, newblock OUT PLS_INTEGER, env sys.ODCIEnv) + RETURN VARCHAR2 +); +/ +show errors; + +create or replace type body power_idxtype_im +is + STATIC FUNCTION ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return number is + BEGIN + ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCIINDEX2')); + return ODCIConst.Success; + END ODCIGetInterfaces; + + STATIC FUNCTION ODCIIndexCreate (ia sys.odciindexinfo, + parms VARCHAR2, env sys.ODCIEnv) + RETURN NUMBER + is + i INTEGER; + r ROWID; + p NUMBER; + v NUMBER; + stmt1 VARCHAR2(1000); + stmt2 VARCHAR2(1000); + stmt3 VARCHAR2(1000); + cnum1 INTEGER; + cnum2 INTEGER; + cnum3 INTEGER; + junk NUMBER; + BEGIN + -- Construct the SQL statement. + stmt1 := 'CREATE TABLE ' || + ia.IndexSchema || '.' || ia.IndexName || '_pidx' || + '( r ROWID, cpos NUMBER, cval NUMBER)'; + + -- Dump the SQL statement. + dbms_output.put_line('ODCIIndexCreate>>>>>'); + sys.ODCIIndexInfoDump(ia); + dbms_output.put_line('ODCIIndexCreate>>>>>'||stmt1); + + -- Execute the statement. + cnum1 := dbms_sql.open_cursor; + dbms_sql.parse(cnum1, stmt1, dbms_sql.native); + junk := dbms_sql.execute(cnum1); + dbms_sql.close_cursor(cnum1); + + -- Now populate the table. + stmt2 := ' INSERT INTO '|| + ia.IndexSchema || '.' || ia.IndexName || '_pidx' || + ' SELECT :rr, ROWNUM, column_value FROM THE' || + ' (SELECT CAST (P.'|| ia.IndexCols(1).ColName || + '.CellDemandValues AS NumTab_Typ)' || + ' FROM ' || ia.IndexCols(1).TableSchema || '.' || + ia.IndexCols(1).TableName || ' P' || + ' WHERE P.ROWID = :rr)'; + + -- Execute the statement. + dbms_output.put_line('ODCIIndexCreate>>>>>'||stmt2); + + -- Parse the statement. + cnum2 := dbms_sql.open_cursor; + dbms_sql.parse(cnum2, stmt2, dbms_sql.native); + + stmt3 := 'SELECT ROWID FROM '|| + ia.IndexCols(1).TableSchema || '.' || ia.IndexCols(1).TableName; + dbms_output.put_line('ODCIIndexCreate>>>>>'||stmt3); + cnum3 := dbms_sql.open_cursor; + dbms_sql.parse(cnum3, stmt3, dbms_sql.native); + dbms_sql.define_column_rowid(cnum3, 1, r); + junk := dbms_sql.execute(cnum3); + + WHILE dbms_sql.fetch_rows(cnum3) > 0 LOOP + -- Get column values of the row. -- + dbms_sql.column_value_rowid(cnum3, 1, r); + -- Bind the row into the cursor for the next insert. -- + dbms_sql.bind_variable_rowid(cnum2, ':rr', r); + junk := dbms_sql.execute(cnum2); + END LOOP; + + dbms_sql.close_cursor(cnum2); + dbms_sql.close_cursor(cnum3); + RETURN ODCICONST.SUCCESS; + END; + + STATIC FUNCTION ODCIIndexDrop(ia sys.odciindexinfo, env sys.ODCIEnv) + RETURN NUMBER is + stmt VARCHAR2(1000); + cnum INTEGER; + junk INTEGER; + BEGIN + -- Construct the SQL statement. + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || '_pidx'; + + dbms_output.put_line('ODCIIndexDrop>>>>>'); + sys.ODCIIndexInfoDump(ia); + dbms_output.put_line('ODCIIndexDrop>>>>>'||stmt); + + -- Execute the statement. + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + RETURN ODCICONST.SUCCESS; + END; + + -- This definition of ODCIIndexStart is for queries on a specific + -- cell. (The next definition is for queries on any cell.) + STATIC FUNCTION ODCIIndexStart(sctx IN OUT power_idxtype_im, + ia sys.odciindexinfo, + op sys.odciPredInfo, qi sys.ODCIQueryInfo, + strt NUMBER, stop NUMBER, + cmppos NUMBER, cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER is + cnum INTEGER; + rid ROWID; + nrows INTEGER; + relop VARCHAR2(2); + stmt VARCHAR2(1000); + BEGIN + dbms_output.put_line('ODCIIndexStart>>>>>'); + sys.ODCIIndexInfoDump(ia); + sys.ODCIPredInfoDump(op); + dbms_output.put_line('start key : '||strt); + dbms_output.put_line('stop key : '||stop); + dbms_output.put_line('compare position : '||cmppos); + dbms_output.put_line('compare value : '||cmpval); + + -- Take care of some error cases. + -- The only predicates in which operators can appear are + -- op() = 1 OR op() = 0 + if (strt != 1) and (strt != 0) then + raise_application_error(-20101, 'Incorrect predicate for operator'); + END if; + + if (stop != 1) and (stop != 0) then + raise_application_error(-20101, 'Incorrect predicate for operator'); + END if; + + -- Generate the SQL statement to be executed. + -- First, figure out the relational operator needed for the statement. + -- Take into account the operator name and the start and stop keys. + -- For now, the start and stop keys can both be 1 (= TRUE) or + -- both be 0 (= FALSE). + if op.ObjectName = 'POWER_EQUALS' then + if strt = 1 then + relop := '='; + else + relop := '!='; + end if; + elsif op.ObjectName = 'POWER_LESSTHAN' then + if strt = 1 then + relop := '<'; + else + relop := '>='; + end if; + elsif op.ObjectName = 'POWER_GREATERTHAN' then + if strt = 1 then + relop := '>'; + else + relop := '<='; + end if; + else + raise_application_error(-20101, 'Unsupported operator'); + end if; + + stmt := 'select r from '||ia.IndexSchema||'.'||ia.IndexName||'_pidx'|| + ' where cpos '|| '=' ||''''||cmppos||''''|| + ' and cval '||relop||''''||cmpval||''''; + + dbms_output.put_line('ODCIIndexStart>>>>>' || stmt); + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + dbms_sql.define_column_rowid(cnum, 1, rid); + nrows := dbms_sql.execute(cnum); + + -- Set context as the cursor number. + sctx := power_idxtype_im(cnum); + + -- Return success. + RETURN ODCICONST.SUCCESS; + END; + + -- This definition of ODCIIndexStart is for queries on any + -- cell. (The preceding definition was for queries on a + -- specific cell.) + STATIC FUNCTION ODCIIndexStart(sctx IN OUT power_idxtype_im, + ia sys.odciindexinfo, + op sys.odciPredInfo, qi sys.ODCIQueryInfo, + strt NUMBER, stop NUMBER, + cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER is + cnum INTEGER; + rid ROWID; + nrows INTEGER; + relop VARCHAR2(2); + stmt VARCHAR2(1000); + BEGIN + dbms_output.put_line('ODCIIndexStart>>>>>'); + sys.ODCIIndexInfoDump(ia); + sys.ODCIPredInfoDump(op); + dbms_output.put_line('start key : '||strt); + dbms_output.put_line('stop key : '||stop); + dbms_output.put_line('compare value : '||cmpval); + + -- Take care of some error cases. + -- The only predicates in which btree operators can appear are + -- op() = 1 OR op() = 0 + if (strt != 1) and (strt != 0) then + raise_application_error(-20101, 'Incorrect predicate for operator'); + END if; + + if (stop != 1) and (stop != 0) then + raise_application_error(-20101, 'Incorrect predicate for operator'); + END if; + + -- Generate the SQL statement to be executed. + -- First, figure out the relational operator needed for the statement. + -- Take into account the operator name and the start and stop keys. + -- For now, the start and stop keys can both be 1 (= TRUE) or + -- both be 0 (= FALSE). + if op.ObjectName = 'POWER_EQUALSANY' then + relop := '='; + elsif op.ObjectName = 'POWER_LESSTHANANY' then + relop := '<'; + elsif op.ObjectName = 'POWER_GREATERTHANANY' then + relop := '>'; + else + raise_application_error(-20101, 'Unsupported operator'); + end if; + + -- This statement returns the qualifying rows for the TRUE case. + stmt := 'select distinct r from ' || + ia.IndexSchema || '.' || ia.IndexName || '_pidx' || + ' where cval ' || relop || '''' || cmpval || ''''; + -- In the FALSE case, we need to find the complement of the rows. + if (strt = 0) then + stmt := 'select distinct r from ' || + ia.IndexSchema || '.' || ia.IndexName||'_pidx' || + ' minus '||stmt; + end if; + + dbms_output.put_line('ODCIIndexStart>>>>>' || stmt); + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + dbms_sql.define_column_rowid(cnum, 1, rid); + nrows := dbms_sql.execute(cnum); + + -- Set context as the cursor number. + sctx := power_idxtype_im(cnum); + + -- Return success. + RETURN ODCICONST.SUCCESS; + END; + + MEMBER FUNCTION ODCIIndexFetch(nrows NUMBER, rids OUT sys.odciridlist, + env sys.ODCIEnv) + RETURN NUMBER is + cnum INTEGER; + idx INTEGER := 1; + rlist sys.odciridlist := sys.odciridlist(); + done boolean := FALSE; + BEGIN + dbms_output.put_line('ODCIIndexFetch>>>>>'); + dbms_output.put_line('Nrows : '||round(nrows)); + + cnum := self.curnum; + + WHILE not done LOOP + if idx > nrows then + done := TRUE; + else + rlist.extend; + if dbms_sql.fetch_rows(cnum) > 0 then + dbms_sql.column_value_rowid(cnum, 1, rlist(idx)); + idx := idx + 1; + else + rlist(idx) := null; + done := TRUE; + END if; + END if; + END LOOP; + + rids := rlist; + RETURN ODCICONST.SUCCESS; + END; + + MEMBER FUNCTION ODCIIndexClose(env sys.ODCIEnv) RETURN NUMBER is + cnum INTEGER; + BEGIN + dbms_output.put_line('ODCIIndexClose>>>>>'); + + cnum := self.curnum; + dbms_sql.close_cursor(cnum); + RETURN ODCICONST.SUCCESS; + END; + + STATIC FUNCTION ODCIIndexInsert(ia sys.odciindexinfo, rid VARCHAR2, + newval PowerDemand_Typ, env sys.ODCIEnv) + RETURN NUMBER as + cid INTEGER; + i BINARY_INTEGER; + nrows INTEGER; + stmt VARCHAR2(1000); + BEGIN + dbms_output.put_line(' '); + dbms_output.put_line('ODCIIndexInsert>>>>>'|| + ' TotGridDemand= '||newval.TotGridDemand || + ' MaxCellDemand= '||newval.MaxCellDemand || + ' MinCellDemand= '||newval.MinCellDemand) ; + sys.ODCIIndexInfoDump(ia); + + -- Construct the statement. + stmt := ' INSERT INTO ' || + ia.IndexSchema || '.' || ia.IndexName || '_pidx' || + ' VALUES (:rr, :pos, :val)'; + + -- Execute the statement. + dbms_output.put_line('ODCIIndexInsert>>>>>'||stmt); + -- Parse the statement. + cid := dbms_sql.open_cursor; + dbms_sql.parse(cid, stmt, dbms_sql.native); + dbms_sql.bind_variable_rowid(cid, ':rr', rid); + + -- Iterate over the rows of the Varray and insert them. + i := newval.CellDemandValues.FIRST; + WHILE i IS NOT NULL LOOP + -- Bind the row into the cursor for insert. + dbms_sql.bind_variable(cid, ':pos', i); + dbms_sql.bind_variable(cid, ':val', newval.CellDemandValues(i)); + -- Execute. + nrows := dbms_sql.execute(cid); + dbms_output.put_line('ODCIIndexInsert>>>>>('|| + 'RID' ||' , '|| + i || ' , '|| + newval.CellDemandValues(i)|| ')'); + i := newval.CellDemandValues.NEXT(i); + END LOOP; + dbms_sql.close_cursor(cid); + RETURN ODCICONST.SUCCESS; + END ODCIIndexInsert; + + STATIC FUNCTION ODCIIndexDelete(ia sys.odciindexinfo, rid VARCHAR2, + oldval PowerDemand_Typ, env sys.ODCIEnv) + RETURN NUMBER as + cid INTEGER; + stmt VARCHAR2(1000); + nrows INTEGER; + BEGIN + dbms_output.put_line(' '); + dbms_output.put_line('ODCIIndexDelete>>>>>'|| + ' TotGridDemand= '||oldval.TotGridDemand || + ' MaxCellDemand= '||oldval.MaxCellDemand || + ' MinCellDemand= '||oldval.MinCellDemand) ; + sys.ODCIIndexInfoDump(ia); + + -- Construct the statement. + stmt := ' DELETE FROM ' || + ia.IndexSchema || '.' || ia.IndexName || '_pidx' || + ' WHERE r=:rr'; + dbms_output.put_line('ODCIIndexDelete>>>>>'||stmt); + + -- Parse and execute the statement. + cid := dbms_sql.open_cursor; + dbms_sql.parse(cid, stmt, dbms_sql.native); + dbms_sql.bind_variable_rowid(cid, ':rr', rid); + nrows := dbms_sql.execute(cid); + dbms_sql.close_cursor(cid); + + RETURN ODCICONST.SUCCESS; + END ODCIIndexDelete; + + STATIC FUNCTION ODCIIndexUpdate(ia sys.odciindexinfo, rid VARCHAR2, + oldval PowerDemand_Typ, newval PowerDemand_Typ, env sys.ODCIEnv) + RETURN NUMBER as + cid INTEGER; + cid2 INTEGER; + stmt VARCHAR2(1000); + stmt2 VARCHAR2(1000); + nrows INTEGER; + i NUMBER; + BEGIN + dbms_output.put_line(' '); + dbms_output.put_line('ODCIIndexUpdate>>>>> Old'|| + ' TotGridDemand= '||oldval.TotGridDemand || + ' MaxCellDemand= '||oldval.MaxCellDemand || + ' MinCellDemand= '||oldval.MinCellDemand) ; + dbms_output.put_line('ODCIIndexUpdate>>>>> New'|| + ' TotGridDemand= '||newval.TotGridDemand || + ' MaxCellDemand= '||newval.MaxCellDemand || + ' MinCellDemand= '||newval.MinCellDemand) ; + sys.ODCIIndexInfoDump(ia); + + -- Delete old entries. + stmt := ' DELETE FROM ' || + ia.IndexSchema || '.' || ia.IndexName || '_pidx' || + ' WHERE r=:rr'; + dbms_output.put_line('ODCIIndexUpdate>>>>>'||stmt); + + -- Parse and execute the statement. + cid := dbms_sql.open_cursor; + dbms_sql.parse(cid, stmt, dbms_sql.native); + dbms_sql.bind_variable_rowid(cid, ':rr', rid); + nrows := dbms_sql.execute(cid); + dbms_sql.close_cursor(cid); + + -- Insert new entries. + stmt2 := ' INSERT INTO ' || + ia.IndexSchema || '.' || ia.IndexName || '_pidx' || + ' VALUES (:rr, :pos, :val)'; + dbms_output.put_line('ODCIIndexUpdate>>>>>'||stmt2); + + -- Parse and execute the statement. + cid2 := dbms_sql.open_cursor; + dbms_sql.parse(cid2, stmt2, dbms_sql.native); + dbms_sql.bind_variable_rowid(cid2, ':rr', rid); + + -- Iterate over the rows of the Varray and insert them. + i := newval.CellDemandValues.FIRST; + WHILE i IS NOT NULL LOOP + -- Bind the row into the cursor for insert. + dbms_sql.bind_variable(cid2, ':pos', i); + dbms_sql.bind_variable(cid2, ':val', newval.CellDemandValues(i)); + nrows := dbms_sql.execute(cid2); + dbms_output.put_line('ODCIIndexUpdate>>>>>('|| + 'RID' || ' , '|| + i || ' , '|| + newval.CellDemandValues(i)|| ')'); + i := newval.CellDemandValues.NEXT(i); + END LOOP; + dbms_sql.close_cursor(cid2); + + RETURN ODCICONST.SUCCESS; + END ODCIIndexUpdate; + + STATIC FUNCTION ODCIIndexGetMetadata(ia sys.odciindexinfo, + expversion VARCHAR2, newblock OUT PLS_INTEGER, env sys.ODCIEnv) + RETURN VARCHAR2 is + BEGIN + -- Let getversion do all the work since it has to maintain + -- state across calls. + + RETURN power_pkg.getversion (ia.IndexSchema, ia.IndexName, newblock); + + EXCEPTION + WHEN OTHERS THEN + RAISE; + + END ODCIIndexGetMetaData; + +END; +/ + +show errors; +------------------------------------------------------------------- +-- CREATE INDEXTYPE +------------------------------------------------------------------- +CREATE OR REPLACE INDEXTYPE power_idxtype +FOR + Power_Equals(PowerDemand_Typ, NUMBER, NUMBER), + Power_GreaterThan(PowerDemand_Typ, NUMBER, NUMBER), + Power_LessThan(PowerDemand_Typ, NUMBER, NUMBER), + Power_EqualsAny(PowerDemand_Typ, NUMBER), + Power_GreaterThanAny(PowerDemand_Typ, NUMBER), + Power_LessThanAny(PowerDemand_Typ, NUMBER) +USING power_idxtype_im; + +------------------------------------------------------------------- +-- Create table and populate it -- +------------------------------------------------------------------- +CREATE TABLE PowerDemand_Tab ( + -- Region for which these power demand readings apply + region NUMBER, + -- Values for each "sampling" time (for a given hour) + sample PowerDemand_Typ +); + +-- The next INSERT statements "cheat" by supplying +-- only 5 grid values (instead of 100). + +-- INSERT statements are for region 1 to get enough timestamps +-- for a moving average using the Time Series cartridge. +-- (Time Series cartridge tests are in a separate file.) + +declare + i integer; +begin + i := 0; + + while i < 2000 loop + INSERT INTO PowerDemand_Tab VALUES( + 1, + PowerDemand_Typ(NULL, NULL, NULL, + PowerGrid_Typ(i,i+1,i+2,i+3,i+4),SYSDATE)); + + i := i+5; + END LOOP; +end; +/ + +-- Also insert some rows for region 2. + +INSERT INTO PowerDemand_Tab VALUES(2, + PowerDemand_Typ(NULL, NULL, NULL, PowerGrid_Typ(9,8,11,16,5), + to_date('02-01-1998 01','MM-DD-YYYY HH')) +); + +INSERT INTO PowerDemand_Tab VALUES(2, + PowerDemand_Typ(NULL, NULL, NULL, PowerGrid_Typ(9,8,11,20,5), + to_date('02-01-1998 02','MM-DD-YYYY HH')) +); + + +DECLARE +CURSOR c1 IS SELECT Sample FROM PowerDemand_Tab FOR UPDATE; +s PowerDemand_Typ; +BEGIN + OPEN c1; + LOOP + FETCH c1 INTO s; + EXIT WHEN c1%NOTFOUND; + s.SetTotalDemand; + s.SetMaxDemand; + s.SetMinDemand; + dbms_output.put_line(s.TotGridDemand); + dbms_output.put_line(s.MaxCellDemand); + dbms_output.put_line(s.MinCellDemand); + UPDATE PowerDemand_Tab SET Sample = s WHERE CURRENT of c1; + END LOOP; + CLOSE c1; +END; +/ + +------------------------------------------------------------------- +-- CREATE GENERIC FUNCTION TO COMPUTE SELECTIVITY OF PREDICATE +------------------------------------------------------------------- + +CREATE FUNCTION get_selectivity(relop VARCHAR2, value NUMBER, + lo NUMBER, hi NUMBER, ndv NUMBER) + RETURN NUMBER AS + sel NUMBER := NULL; +BEGIN + -- This function computes the selectivity (as a percentage) + -- of a predicate + -- col + -- where is one of: =, !=, <, <=, >, >= + -- is one of: 0, 1 + -- lo and hi are the minimum and maximum values of the column in + -- the table. This function performs a simplistic estimation of the + -- selectivity by assulog that the range of distinct values of + -- the column is distributed uniformly in the range lo..hi and that + -- each distinct value occurs nrows/(hi-lo+1) times (where nrows is + -- the number of rows). + + IF ndv IS NULL OR ndv <= 0 THEN + RETURN 0; + END IF; + + -- col != + IF relop = '!=' THEN + IF value between lo and hi THEN + sel := 1 - 1/ndv; + ELSE + sel := 1; + END IF; + + -- col = + ELSIF relop = '=' THEN + IF value between lo and hi THEN + sel := 1/ndv; + ELSE + sel := 0; + END IF; + + -- col >= + ELSIF relop = '>=' THEN + IF lo = hi THEN + IF value <= lo THEN + sel := 1; + ELSE + sel := 0; + END IF; + ELSIF value between lo and hi THEN + sel := (hi-value)/(hi-lo) + 1/ndv; + ELSIF value < lo THEN + sel := 1; + ELSE + sel := 0; + END IF; + + -- col < + ELSIF relop = '<' THEN + IF lo = hi THEN + IF value > lo THEN + sel := 1; + ELSE + sel := 0; + END IF; + ELSIF value between lo and hi THEN + sel := (value-lo)/(hi-lo); + ELSIF value < lo THEN + sel := 0; + ELSE + sel := 1; + END IF; + + -- col <= + ELSIF relop = '<=' THEN + IF lo = hi THEN + IF value >= lo THEN + sel := 1; + ELSE + sel := 0; + END IF; + ELSIF value between lo and hi THEN + sel := (value-lo)/(hi-lo) + 1/ndv; + ELSIF value < lo THEN + sel := 0; + ELSE + sel := 1; + END IF; + + -- col > + ELSIF relop = '>' THEN + IF lo = hi THEN + IF value < lo THEN + sel := 1; + ELSE + sel := 0; + END IF; + ELSIF value between lo and hi THEN + sel := (hi-value)/(hi-lo); + ELSIF value < lo THEN + sel := 1; + ELSE + sel := 0; + END IF; + + END IF; + + RETURN least(100, ceil(100*sel)); + +END; +/ + +------------------------------------------------------------------- +-- CREATE STATISTICS IMPLEMENTATION TYPE +------------------------------------------------------------------- +CREATE OR REPLACE TYPE power_statistics AS OBJECT +( + curnum NUMBER, + STATIC FUNCTION ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + RETURN NUMBER, + STATIC FUNCTION ODCIStatsCollect(col sys.ODCIColInfo, + options sys.ODCIStatsOptions, rawstats OUT RAW, env sys.ODCIEnv) + RETURN NUMBER, + STATIC FUNCTION ODCIStatsDelete(col sys.ODCIColInfo, + statistics OUT RAW, env sys.ODCIEnv) + RETURN NUMBER, + STATIC FUNCTION ODCIStatsCollect(ia sys.ODCIIndexInfo, + options sys.ODCIStatsOptions, rawstats OUT RAW, env sys.ODCIEnv) + RETURN NUMBER, + STATIC FUNCTION ODCIStatsDelete(ia sys.ODCIIndexInfo, + statistics OUT RAW, env sys.ODCIEnv) + RETURN NUMBER, + STATIC FUNCTION ODCIStatsSelectivity(pred sys.ODCIPredInfo, + sel OUT NUMBER, args sys.ODCIArgDescList, strt NUMBER, stop NUMBER, + object PowerDemand_Typ, cell NUMBER, value NUMBER, env sys.ODCIEnv) + RETURN NUMBER, + PRAGMA restrict_references(ODCIStatsSelectivity, WNDS, WNPS), + STATIC FUNCTION ODCIStatsSelectivity(pred sys.ODCIPredInfo, + sel OUT NUMBER, args sys.ODCIArgDescList, strt NUMBER, stop NUMBER, + object PowerDemand_Typ, value NUMBER, env sys.ODCIEnv) + RETURN NUMBER, + PRAGMA restrict_references(ODCIStatsSelectivity, WNDS, WNPS), + STATIC FUNCTION ODCIStatsIndexCost(ia sys.ODCIIndexInfo, + sel NUMBER, cost OUT sys.ODCICost, qi sys.ODCIQueryInfo, + pred sys.ODCIPredInfo, args sys.ODCIArgDescList, + strt NUMBER, stop NUMBER, cmppos NUMBER, cmpval NUMBER, env sys.ODCIEnv) + RETURN NUMBER, + PRAGMA restrict_references(ODCIStatsIndexCost, WNDS, WNPS), + STATIC FUNCTION ODCIStatsIndexCost(ia sys.ODCIIndexInfo, + sel NUMBER, cost OUT sys.ODCICost, qi sys.ODCIQueryInfo, + pred sys.ODCIPredInfo, args sys.ODCIArgDescList, + strt NUMBER, stop NUMBER, cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER, + PRAGMA restrict_references(ODCIStatsIndexCost, WNDS, WNPS), + STATIC FUNCTION ODCIStatsFunctionCost(func sys.ODCIFuncInfo, + cost OUT sys.ODCICost, args sys.ODCIArgDescList, + object PowerDemand_Typ, cell NUMBER, value NUMBER, env sys.ODCIEnv) + RETURN NUMBER, + PRAGMA restrict_references(ODCIStatsFunctionCost, WNDS, WNPS), + STATIC FUNCTION ODCIStatsFunctionCost(func sys.ODCIFuncInfo, + cost OUT sys.ODCICost, args sys.ODCIArgDescList, + object PowerDemand_Typ, value NUMBER, env sys.ODCIEnv) RETURN NUMBER, + PRAGMA restrict_references(ODCIStatsFunctionCost, WNDS, WNPS) +); +/ +show errors; + +CREATE OR REPLACE TYPE BODY power_statistics +IS + STATIC FUNCTION ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + RETURN NUMBER IS + BEGIN + ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCISTATS2')); + RETURN ODCIConst.Success; + END ODCIGetInterfaces; + + STATIC FUNCTION ODCIStatsCollect(col sys.ODCIColInfo, + options sys.ODCIStatsOptions, + rawstats OUT RAW, env sys.ODCIEnv) + RETURN NUMBER IS + cnum INTEGER; + stmt VARCHAR2(1000); + junk INTEGER; + + cval NUMBER; + colname VARCHAR2(30) := rtrim(ltrim(col.colName, '"'), '"'); + statsexists BOOLEAN := FALSE; + pdemands PowerDemand_Tab%ROWTYPE; + user_defined_stats PowerCartUserStats%ROWTYPE; + CURSOR c1(tname VARCHAR2, cname VARCHAR2) IS + SELECT * FROM PowerCartUserStats + WHERE tab = tname + AND col = cname; + CURSOR c2 IS + SELECT * FROM PowerDemand_Tab; + + BEGIN + sys.ODCIColInfoDump(col); + sys.ODCIStatsOptionsDump(options); + + IF (col.TableSchema IS NULL OR col.TableName IS NULL + OR col.ColName IS NULL) THEN + RETURN ODCIConst.Error; + END IF; + + dbms_output.put_line('ODCIStatsCollect>>>>>'); + dbms_output.put_line('**** Analyzing column ' + || col.TableSchema + || '.' || col.TableName + || '.' || col.ColName); + + -- Check if statistics exist for this column + FOR user_defined_stats IN c1(col.TableName, colname) LOOP + statsexists := TRUE; + EXIT; + END LOOP; + + IF not statsexists THEN + -- column statistics don't exist; create entries for + -- each of the 100 cells + cnum := dbms_sql.open_cursor; + FOR i in 1..100 LOOP + stmt := 'INSERT INTO PowerCartUserStats VALUES( ' + || '''' || col.TableName || ''', ' + || '''' || colname || ''', ' + || to_char(i) || ', ' + || 'NULL, NULL, NULL)'; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + END LOOP; + dbms_sql.close_cursor(cnum); + ELSE + -- column statistics exist; initialize to NULL + cnum := dbms_sql.open_cursor; + stmt := 'UPDATE PowerCartUserStats' + || ' SET lo = NULL, hi = NULL, nrows = NULL' + || ' WHERE tab = ' || col.TableName + || ' AND col = ' || colname; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + END IF; + + -- For each cell position, the following statistics are collected: + -- maximum value + -- minimum value + -- number of rows (excluding NULLs) + cnum := dbms_sql.open_cursor; + FOR i in 1..100 LOOP + FOR pdemands IN c2 LOOP + IF i BETWEEN pdemands.sample.CellDemandValues.FIRST AND + pdemands.sample.CellDemandValues.LAST THEN + cval := pdemands.sample.CellDemandValues(i); + stmt := 'UPDATE PowerCartUserStats SET ' + || 'lo = least(' || 'NVL(' || to_char(cval) || ', lo), ' + || 'NVL(' || 'lo, ' || to_char(cval) || ')), ' + || 'hi = greatest(' || 'NVL(' || to_char(cval) || ', hi), ' + || 'NVL(' || 'hi, ' || to_char(cval) || ')), ' + || 'nrows = decode(nrows, NULL, decode(' + || to_char(cval) || ', NULL, NULL, 1), decode(' + || to_char(cval) || ', NULL, nrows, nrows+1)) ' + || 'WHERE cpos = ' || to_char(i) + || ' AND tab = ''' || col.TableName || '''' + || ' AND col = ''' || colname || ''''; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + END IF; + END LOOP; + END LOOP; + dbms_sql.close_cursor(cnum); + + rawstats := NULL; + + return ODCIConst.Success; + + END; + + STATIC FUNCTION ODCIStatsDelete(col sys.ODCIColInfo, statistics OUT RAW, + env sys.ODCIEnv) + RETURN NUMBER IS + cnum INTEGER; + stmt VARCHAR2(1000); + junk INTEGER; + + colname VARCHAR2(30) := rtrim(ltrim(col.colName, '"'), '"'); + statsexists BOOLEAN := FALSE; + user_defined_stats PowerCartUserStats%ROWTYPE; + CURSOR c1(tname VARCHAR2, cname VARCHAR2) IS + SELECT * FROM PowerCartUserStats + WHERE tab = tname + AND col = cname; + BEGIN + sys.ODCIColInfoDump(col); + + IF (col.TableSchema IS NULL OR col.TableName IS NULL + OR col.ColName IS NULL) THEN + RETURN ODCIConst.Error; + END IF; + + dbms_output.put_line('ODCIStatsDelete>>>>>'); + dbms_output.put_line('**** Analyzing (delete) column ' + || col.TableSchema + || '.' || col.TableName + || '.' || col.ColName); + + -- Check if statistics exist for this column + FOR user_defined_stats IN c1(col.TableName, colname) LOOP + statsexists := TRUE; + EXIT; + END LOOP; + + -- If user-defined statistics exist, delete them + IF statsexists THEN + stmt := 'DELETE FROM PowerCartUserStats' + || ' WHERE tab = ''' || col.TableName || '''' + || ' AND col = ''' || colname || ''''; + cnum := dbms_sql.open_cursor; + dbms_output.put_line('ODCIStatsDelete>>>>>'); + dbms_output.put_line('ODCIStatsDelete>>>>>' || stmt); + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + END IF; + + RETURN ODCIConst.Success; + END; + + STATIC FUNCTION ODCIStatsCollect (ia sys.ODCIIndexInfo, + options sys.ODCIStatsOptions, rawstats OUT RAW, env sys.ODCIEnv) + RETURN NUMBER IS + cnum INTEGER; + stmt VARCHAR2(1000); + junk INTEGER; + BEGIN + -- To analyze a domain index, simply analyze the table that + -- implements the index + + sys.ODCIIndexInfoDump(ia); + sys.ODCIStatsOptionsDump(options); + + stmt := 'ANALYZE TABLE ' + || ia.IndexSchema || '.' || ia.IndexName || '_pidx' + || ' COMPUTE STATISTICS'; + + dbms_output.put_line('**** Analyzing index ' + || ia.IndexSchema || '.' || ia.IndexName); + dbms_output.put_line('SQL Statement: ' || stmt); + + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + rawstats := NULL; + + RETURN ODCIConst.Success; + END; + + STATIC FUNCTION ODCIStatsDelete(ia sys.ODCIIndexInfo, + statistics OUT RAW, env sys.ODCIEnv) + RETURN NUMBER IS + cnum INTEGER; + stmt VARCHAR2(1000); + junk INTEGER; + BEGIN + -- To delete statistics for a domain index, simply delete the + -- statistics for the table implementing the index + + sys.ODCIIndexInfoDump(ia); + + stmt := 'ANALYZE TABLE ' + || ia.IndexSchema || '.' || ia.IndexName || '_pidx' + || ' DELETE STATISTICS'; + + dbms_output.put_line('**** Analyzing (delete) index ' + || ia.IndexSchema || '.' || ia.IndexName); + dbms_output.put_line('SQL Statement: ' || stmt); + + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + RETURN ODCIConst.Success; + END; + + STATIC FUNCTION ODCIStatsSelectivity(pred sys.ODCIPredInfo, + sel OUT NUMBER, args sys.ODCIArgDescList, strt NUMBER, stop NUMBER, + object PowerDemand_Typ, cell NUMBER, value NUMBER, env sys.ODCIEnv) + RETURN NUMBER IS + fname varchar2(30); + relop varchar2(2); + lo NUMBER; + hi NUMBER; + nrows NUMBER; + colname VARCHAR2(30); + statsexists BOOLEAN := FALSE; + stats PowerCartUserStats%ROWTYPE; + CURSOR c1(cell NUMBER, tname VARCHAR2, cname VARCHAR2) IS + SELECT * FROM PowerCartUserStats + WHERE cpos = cell + AND tab = tname + AND col = cname; + BEGIN + -- compute selectivity only when predicate is of the form: + -- fn(col, , ) + -- In all other cases, return an error and let the optimizer + -- make a guess. We also assume that the function "fn" has + -- a return value of 0, 1, or NULL. + + -- start value + IF (args(1).ArgType != ODCIConst.ArgLit AND + args(1).ArgType != ODCIConst.ArgNull) THEN + RETURN ODCIConst.Error; + END IF; + + -- stop value + IF (args(2).ArgType != ODCIConst.ArgLit AND + args(2).ArgType != ODCIConst.ArgNull) THEN + RETURN ODCIConst.Error; + END IF; + + -- first argument of function + IF (args(3).ArgType != ODCIConst.ArgCol) THEN + RETURN ODCIConst.Error; + END IF; + + -- second argument of function + IF (args(4).ArgType != ODCIConst.ArgLit AND + args(4).ArgType != ODCIConst.ArgNull) THEN + RETURN ODCIConst.Error; + END IF; + + -- third argument of function + IF (args(5).ArgType != ODCIConst.ArgLit AND + args(5).ArgType != ODCIConst.ArgNull) THEN + RETURN ODCIConst.Error; + END IF; + + colname := rtrim(ltrim(args(3).colName, '"'), '"'); + + -- Check if the statistics table exists (we are using a + -- user-defined table to store the user-defined statistics). + -- Get user-defined statistics: MIN, MAX, NROWS + FOR stats IN c1(cell, args(3).TableName, colname) LOOP + -- Get user-defined statistics: MIN, MAX, NROWS + lo := stats.lo; + hi := stats.hi; + nrows := stats.nrows; + statsexists := TRUE; + EXIT; + END LOOP; + + -- If no user-defined statistics were collected, return error + IF not statsexists THEN + RETURN ODCIConst.Error; + END IF; + + -- selectivity is 0 for "fn(col, , ) < 0" + IF (stop = 0 AND + bitand(pred.Flags, ODCIConst.PredIncludeStop) = 0) THEN + sel := 0; + RETURN ODCIConst.Success; + END IF; + + -- selectivity is 0 for "fn(col, , ) > 1" + IF (strt = 1 AND + bitand(pred.Flags, ODCIConst.PredIncludeStart) = 0) THEN + sel := 0; + RETURN ODCIConst.Success; + END IF; + + -- selectivity is 100% for "fn(col, , ) >= 0" + IF (strt = 0 AND + bitand(pred.Flags, ODCIConst.PredExactMatch) = 0 AND + bitand(pred.Flags, ODCIConst.PredIncludeStart) > 0) THEN + sel := 100; + RETURN ODCIConst.Success; + END IF; + + -- selectivity is 100% for "fn(col, , ) <= 1" + IF (stop = 1 AND + bitand(pred.Flags, ODCIConst.PredExactMatch) = 0 AND + bitand(pred.Flags, ODCIConst.PredIncludeStop) > 0) THEN + sel := 100; + RETURN ODCIConst.Success; + END IF; + + -- get function name + IF bitand(pred.Flags, ODCIConst.PredObjectFunc) > 0 THEN + fname := pred.ObjectName; + ELSE + fname := pred.MethodName; + END IF; + + -- convert prefix relational operator to infix; + -- e.g., "Power_EqualsSpecific_Func(col, , ) = 1" + -- becomes "col[] = " + + -- Power_EqualsSpecific_Func(col, , ) = 0 + -- Power_EqualsSpecific_Func(col, , ) <= 0 + -- Power_EqualsSpecific_Func(col, , ) < 1 + -- can be transformed to + -- col[] != + IF (fname LIKE upper('Power_Equals%') AND + (stop = 0 OR + (stop = 1 AND + bitand(pred.Flags, ODCIConst.PredIncludeStop) = 0))) THEN + relop := '!='; + + -- Power_LessThanSpecific_Func(col, , ) = 0 + -- Power_LessThanSpecific_Func(col, , ) <= 0 + -- Power_LessThanSpecific_Func(col, , ) < 1 + -- can be transformed to + -- col[] >= + ELSIF (fname LIKE upper('Power_LessThan%') AND + (stop = 0 OR + (stop = 1 AND + bitand(pred.Flags, ODCIConst.PredIncludeStop) = 0))) THEN + relop := '>='; + + -- Power_GreaterThanSpecific_Func(col, , ) = 0 + -- Power_GreaterThanSpecific_Func(col, , ) <= 0 + -- Power_GreaterThanSpecific_Func(col, , ) < 1 + -- can be transformed to + -- col[] <= + ELSIF (fname LIKE upper('Power_GreaterThan%') AND + (stop = 0 OR + (stop = 1 AND + bitand(pred.Flags, ODCIConst.PredIncludeStop) = 0))) THEN + relop := '<='; + + -- Power_EqualsSpecific_Func(col, , ) = 1 + -- Power_EqualsSpecific_Func(col, , ) >= 1 + -- Power_EqualsSpecific_Func(col, , ) > 0 + -- can be transformed to + -- col[] = + ELSIF (fname LIKE upper('Power_Equals%') AND + (strt = 1 OR + (strt = 0 AND + bitand(pred.Flags, ODCIConst.PredIncludeStart) = 0))) THEN + relop := '='; + + -- Power_LessThanSpecific_Func(col, , ) = 1 + -- Power_LessThanSpecific_Func(col, , ) >= 1 + -- Power_LessThanSpecific_Func(col, , ) > 0 + -- can be transformed to + -- col[] < + ELSIF (fname LIKE upper('Power_LessThan%') AND + (strt = 1 OR + (strt = 0 AND + bitand(pred.Flags, ODCIConst.PredIncludeStart) = 0))) THEN + relop := '<'; + + -- Power_GreaterThanSpecific_Func(col, , ) = 1 + -- Power_GreaterThanSpecific_Func(col, , ) >= 1 + -- Power_GreaterThanSpecific_Func(col, , ) > 0 + -- can be transformed to + -- col[] > + ELSIF (fname LIKE upper('Power_GreaterThan%') AND + (strt = 1 OR + (strt = 0 AND + bitand(pred.Flags, ODCIConst.PredIncludeStart) = 0))) THEN + relop := '>'; + + ELSE + RETURN ODCIConst.Error; + + END IF; + + sel := get_selectivity(relop, value, lo, hi, nrows); + RETURN ODCIConst.Success; + END; + + STATIC FUNCTION ODCIStatsSelectivity(pred sys.ODCIPredInfo, + sel OUT NUMBER, args sys.ODCIArgDescList, strt NUMBER, stop NUMBER, + object PowerDemand_Typ, value NUMBER, env sys.ODCIEnv) + RETURN NUMBER IS + cellsel NUMBER; + i NUMBER; + specsel NUMBER; + newargs sys.ODCIArgDescList + := sys.ODCIArgDescList(NULL, NULL, NULL, + NULL, NULL); + BEGIN + -- To compute selectivity for the ANY functions, call the + -- selectivity function for the SPECIFIC functions. For example, + -- the selectivity of the ANY predicate + -- + -- Power_EqualsAnyFunc(object, value) = 1 + -- + -- is computed as + -- + -- 1 - (1-s[1])(1-s[2])...(1-s[100]) + -- + -- where s[i] is the selectivity of the SPECIFIC predicate + -- + -- Power_EqualsSpecific_Func(object, i, value) = 1 + -- + + sel := 1; + newargs(1) := args(1); + newargs(2) := args(2); + newargs(3) := args(3); + newargs(4) := sys.ODCIArgDesc(ODCIConst.ArgLit, NULL, NULL, NULL, + NULL, NULL, NULL); + newargs(5) := args(4); + FOR i in 1..100 LOOP + cellsel := NULL; + specsel := power_statistics.ODCIStatsSelectivity(pred, cellsel, + newargs, strt, stop, object, i, value, env); + IF specsel = ODCIConst.Success THEN + sel := sel * (1 - cellsel/100); + END IF; + END LOOP; + + sel := (1 - sel)*100; + RETURN ODCIConst.Success; + END; + + STATIC FUNCTION ODCIStatsIndexCost(ia sys.ODCIIndexInfo, + sel NUMBER, cost OUT sys.ODCICost, qi sys.ODCIQueryInfo, + pred sys.ODCIPredInfo, args sys.ODCIArgDescList, + strt NUMBER, stop NUMBER, cmppos NUMBER, cmpval NUMBER, env sys.ODCIEnv) + RETURN NUMBER IS + BEGIN + -- This is the cost for queries on a specific cell; simply + -- use the cost for queries on any cell. + RETURN ODCIStatsIndexCost(ia, sel, cost, qi, pred, args, + strt, stop, cmpval, env); + END; + + STATIC FUNCTION ODCIStatsIndexCost(ia sys.ODCIIndexInfo, + sel NUMBER, cost OUT sys.ODCICost, qi sys.ODCIQueryInfo, + pred sys.ODCIPredInfo, args sys.ODCIArgDescList, + strt NUMBER, stop NUMBER, cmpval NUMBER, env sys.ODCIEnv) + RETURN NUMBER IS + ixtable VARCHAR2(40); + numblocks NUMBER := NULL; + get_table user_tables%ROWTYPE; + CURSOR c1(tab VARCHAR2) IS + SELECT * FROM user_tables WHERE table_name = tab; + BEGIN + -- This is the cost for queries on any cell. + + -- To compute the cost of a domain index, multiply the + -- number of blocks in the table implementing the index + -- with the selectivity + + -- Return if we don't have predicate selectivity + IF sel IS NULL THEN + RETURN ODCIConst.Error; + END IF; + + cost := sys.ODCICost(NULL, NULL, NULL, NULL); + + -- Get name of table implementing the domain index + ixtable := ia.IndexName || '_pidx'; + + -- Get number of blocks in domain index + FOR get_table IN c1(upper(ixtable)) LOOP + numblocks := get_table.blocks; + EXIT; + END LOOP; + + IF numblocks IS NULL THEN + -- Exit if there are no user-defined statistics for the index + RETURN ODCIConst.Error; + END IF; + + cost.CPUCost := ceil(400*(sel/100)*numblocks); + cost.IOCost := ceil(1.5*(sel/100)*numblocks); + RETURN ODCIConst.Success; + END; + + STATIC FUNCTION ODCIStatsFunctionCost(func sys.ODCIFuncInfo, + cost OUT sys.ODCICost, args sys.ODCIArgDescList, + object PowerDemand_Typ, cell NUMBER, value NUMBER, env sys.ODCIEnv) + RETURN NUMBER IS + BEGIN + -- This is the cost for functions on a specific cell; simply + -- use the cost for functions on any cell. + RETURN ODCIStatsFunctionCost(func, cost, args, object, value, env); + END; + + STATIC FUNCTION ODCIStatsFunctionCost(func sys.ODCIFuncInfo, + cost OUT sys.ODCICost, args sys.ODCIArgDescList, + object PowerDemand_Typ, value NUMBER, env sys.ODCIEnv) + RETURN NUMBER IS + fname VARCHAR2(30); + BEGIN + cost := sys.ODCICost(NULL, NULL, NULL, NULL); + + -- Get function name + IF bitand(func.Flags, ODCIConst.ObjectFunc) > 0 THEN + fname := func.ObjectName; + ELSE + fname := func.MethodName; + END IF; + + IF fname LIKE upper('Power_LessThan%') THEN + cost.CPUCost := 5000; + cost.IOCost := 0; + RETURN ODCIConst.Success; + ELSIF fname LIKE upper('Power_Equals%') THEN + cost.CPUCost := 7000; + cost.IOCost := 0; + RETURN ODCIConst.Success; + ELSIF fname LIKE upper('Power_GreaterThan%') THEN + cost.CPUCost := 5000; + cost.IOCost := 0; + RETURN ODCIConst.Success; + ELSE + RETURN ODCIConst.Error; + END IF; + END; + +END; +/ +show errors; + +-- Associate statistics type with types, indextypes, and functions +ASSOCIATE STATISTICS WITH TYPES PowerDemand_Typ USING power_statistics; +ASSOCIATE STATISTICS WITH INDEXTYPES power_idxtype USING power_statistics; +ASSOCIATE STATISTICS WITH FUNCTIONS + Power_EqualsSpecific_Func, + Power_GreaterThanSpecific_Func, + Power_LessThanSpecific_Func, + Power_EqualsAny_Func, + Power_GreaterThanAny_Func, + Power_LessThanAny_Func + USING power_statistics; + +-- Analyze the table +ANALYZE TABLE PowerDemand_Tab COMPUTE STATISTICS; + +-- Verify that user-defined statistics were collected +SELECT tab tablename, col colname, cpos, lo, hi, nrows +FROM PowerCartUserStats +WHERE nrows IS NOT NULL +ORDER BY cpos; + +-- Delete the statistics +ANALYZE TABLE PowerDemand_Tab DELETE STATISTICS; + +-- Verify that user-defined statistics were deleted +SELECT tab tablename, col colname, cpos, lo, hi, nrows +FROM PowerCartUserStats +WHERE nrows IS NOT NULL +ORDER BY cpos; + +-- Re-analyze the table +ANALYZE TABLE PowerDemand_Tab COMPUTE STATISTICS; + +-- Verify that user-defined statistics were re-collected +SELECT tab tablename, col colname, cpos, lo, hi, nrows +FROM PowerCartUserStats +WHERE nrows IS NOT NULL +ORDER BY cpos; + +-- Examine the values. +SELECT region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + ORDER BY 1,4,3; + + +------------------------------------------------------------------- +-- Query, referencing the functions. +------------------------------------------------------------------- + +SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_EqualsSpecific_Func(P.Sample,2,10) = 1; + +SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_EqualsSpecific_Func(P.Sample,2,8) = 1 + ORDER BY 1,2; + +SET SERVEROUTPUT ON SIZE 999999 + +------------------------------------------------------------------- +-- Query, referencing the operators (without index) +------------------------------------------------------------------- + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,211) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,211) = 1; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,1,10) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,1,10) = 1; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,9) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,9) = 1; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,8) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,8) = 1 + ORDER BY 1,2; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_EqualsAny(P.Sample,9) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_EqualsAny(P.Sample,9) = 1 + ORDER BY 1,2; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_GreaterThanAny(P.Sample,10) = 0; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_GreaterThanAny(P.Sample,10) = 0 + ORDER BY 1,2; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_LessThanAny(P.Sample,10) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_LessThanAny(P.Sample,10) = 1 + ORDER BY 1,2; + +------------------------------------------------------------------- +-- CREATE INDEX +------------------------------------------------------------------- +CREATE INDEX PowerIndex ON PowerDemand_Tab(Sample) + INDEXTYPE IS power_idxtype parameters('test'); + +-- Analyze the index +ANALYZE INDEX PowerIndex COMPUTE STATISTICS; + +------------------------------------------------------------------- +-- Query, referencing the operators (with index) +------------------------------------------------------------------- +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,211) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,211) = 1; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,1,10) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,1,10) = 1; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_EqualsAny(P.Sample,9) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_EqualsAny(P.Sample,9) = 1 + ORDER BY 1,2; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_GreaterThanAny(P.Sample,4) = 0; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_GreaterThanAny(P.Sample,4) = 0; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_LessThanAny(P.Sample,5) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_LessThanAny(P.Sample,5) = 1; + +---------------------------------------------------------------- +-- Test incremental inserts. -- +---------------------------------------------------------------- +INSERT INTO PowerDemand_Tab VALUES( + 3, + PowerDemand_Typ(NULL, NULL, NULL, PowerGrid_Typ(9,8,10,6,5), + to_date('02-01-1998 01','MM-DD-YYYY HH')) +); + +SET ECHO ON +SET SERVEROUTPUT ON SIZE 999999 + +declare +CURSOR c1 IS SELECT Sample FROM PowerDemand_Tab WHERE Region=3 + FOR UPDATE; +s PowerDemand_Typ; +BEGIN + OPEN c1; + LOOP + FETCH c1 INTO s; + EXIT WHEN c1%NOTFOUND; + s.SetTotalDemand; + s.SetMaxDemand; + s.SetMinDemand; + dbms_output.put_line(s.TotGridDemand); + dbms_output.put_line(s.MaxCellDemand); + dbms_output.put_line(s.MinCellDemand); + UPDATE PowerDemand_Tab SET Sample = s WHERE CURRENT OF c1; + END LOOP; + CLOSE c1; +END; +/ + +-- This should return one more row. +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,8) = 1 + ORDER BY 1,2; + +---------------------------------------------------------------- +-- Test incremental deletes. -- +---------------------------------------------------------------- +DELETE FROM PowerDemand_Tab WHERE Region=3; + +-- This should return one less row than the preceding SELECT. +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,8) = 1 + ORDER BY 1,2; + +---------------------------------------------------------------- +-- Test incremental updates. -- +---------------------------------------------------------------- +INSERT INTO PowerDemand_Tab VALUES(4, + PowerDemand_Typ(NULL, NULL, NULL, PowerGrid_Typ(61,8,12,9,3), + to_date('02-01-1998 01','MM-DD-YYYY HH')) +); + +declare +CURSOR c1 IS SELECT Sample FROM PowerDemand_Tab WHERE Region=4 + FOR UPDATE; +s PowerDemand_Typ; +BEGIN + OPEN c1; + LOOP + FETCH c1 INTO s; + EXIT WHEN c1%NOTFOUND; + s.SetTotalDemand; + s.SetMaxDemand; + s.SetMinDemand; + dbms_output.put_line(s.TotGridDemand); + dbms_output.put_line(s.MaxCellDemand); + dbms_output.put_line(s.MinCellDemand); + UPDATE PowerDemand_Tab SET Sample = s WHERE CURRENT OF c1; + END LOOP; + CLOSE c1; +END; +/ + +-- This SELECT should return one more row than the next SELECT. +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,8) = 1 + ORDER BY 1,2; + +-- Now change cell 2's value to 7 (was 8) for the row that was +-- just inserted (region 4, 1:00 AM on 02-Feb-1998). + +UPDATE PowerDemand_Tab t +SET + t.Sample = PowerDemand_Typ(NULL, NULL, NULL, + PowerGrid_Typ(54,7,12,9,3), + to_date('02-01-1998 01','MM-DD-YYYY HH')) +WHERE + t.Region=4 and + t.sample.sampletime = to_date('02-01-1998 01','MM-DD-YYYY HH'); + +declare +CURSOR c1 IS SELECT Sample FROM PowerDemand_Tab WHERE Region=4 + FOR UPDATE; +s PowerDemand_Typ; +BEGIN + OPEN c1; + LOOP + FETCH c1 INTO s; + EXIT WHEN c1%NOTFOUND; + s.SetTotalDemand; + s.SetMaxDemand; + s.SetMinDemand; + dbms_output.put_line(s.TotGridDemand); + dbms_output.put_line(s.MaxCellDemand); + dbms_output.put_line(s.MinCellDemand); + UPDATE PowerDemand_Tab SET Sample = s WHERE CURRENT OF c1; + END LOOP; + CLOSE c1; +END; +/ + +-- This SELECT should return one less row than the preceding SELECT. +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,8) = 1 + ORDER BY 1,2; + +-- Delete the row that was added for region 4. +DELETE FROM PowerDemand_Tab WHERE Region=4; + +-- Cleanup +CONNECT sys/knl_test7 AS sysdba; +DROP USER PowerCartUser CASCADE; + diff --git a/extdemo2.c b/extdemo2.c new file mode 100644 index 0000000..c62b983 --- /dev/null +++ b/extdemo2.c @@ -0,0 +1,730 @@ +#ifdef RCSID +static char *RCSid = + "$Header: extdemo2.c 05-apr-2005.06:32:23 yhu Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 2005, Oracle. All rights reserved. +*/ + +/* + + NAME + extdemo2.c - Extensible Indexing example implemented as C routines + + DESCRIPTION + This file contains the definitions of the DML and Query routines + for the extensible indexing example that implements a simple btree + (sbtree). See extdemo2.sql for the SQL script that defines the + indextype. + + PUBLIC FUNCTION(S) + qxiqtbs - QXIQT Btree Start routine + qxiqtbf - QXIQT Btree Fetch routine + qxiqtbc - QXIQT Btree Close routine + qxiqtbi - QXIQT Btree Insert routine + qxiqtbd - QXIQT Btree Delete routine + qxiqtbu - QXIQT Btree Update routine + + PRIVATE FUNCTION(S) + qxiqtbe - QXIQT error reporting routine + + NOTES + + + MODIFIED (MM/DD/YY) + yhu 04/04/05 - #4184410: fix porting exceptions in HP VMS + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + spsundar 10/21/98 - fix ODCIIndexInsert routine + rmurthy 06/16/98 - Creation + +*/ + +#ifndef EXTDEMO2_ORACLE +# include "extdemo2.h" +#endif +#include +#include + +/*--------------------------------------------------------------------------- + TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ + +/* ODCIIndexInsert function */ +OCINumber *qxiqtbi(ctx, ix, ix_ind, rid, rid_ind, + newval, newval_ind) +OCIExtProcContext *ctx; +ODCIIndexInfo *ix; +ODCIIndexInfo_ind *ix_ind; +char *rid; +short rid_ind; +char *newval; +short newval_ind; +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + OCIBind *bndp1 = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + ub4 key; /* key value set in "self" */ + + char insstmt[2000]; /* sql insert statement */ + + /* allocate memory for OCINumber first */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct insert Statement * + ******************************/ + + sprintf(insstmt, + "INSERT into %s.%s_sbtree values (:newval, :mrid)", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + + /**************************************** + * Parse and Execute Create Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, (text *)insstmt, + (ub4)strlen(insstmt), OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + + + /* Set up bind for newval */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)1, + (dvoid *)newval, + (sb4)(strlen(newval)+1), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)2, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + return(rval); +} + +/* ODCIIndexDelete function */ +OCINumber *qxiqtbd(ctx, ix, ix_ind, rid, rid_ind, + oldval, oldval_ind) +OCIExtProcContext *ctx; +ODCIIndexInfo *ix; +ODCIIndexInfo_ind *ix_ind; +char *rid; +short rid_ind; +char *oldval; +short oldval_ind; +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + OCIBind *bndp1 = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + ub4 key; /* key value set in "self" */ + + char delstmt[2000]; /* sql insert statement */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct delete Statement * + ******************************/ + + sprintf(delstmt, + "DELETE FROM %s.%s_sbtree WHERE f2 = :rr", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + + /**************************************** + * Parse and Execute delete Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, (text *)delstmt, + (ub4)strlen(delstmt), OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)1, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + return(rval); +} + +/* ODCIIndexUpdate function */ +OCINumber *qxiqtbu(ctx, ix, ix_ind, rid, rid_ind, + oldval, oldval_ind, newval, newval_ind) +OCIExtProcContext *ctx; +ODCIIndexInfo *ix; +ODCIIndexInfo_ind *ix_ind; +char *rid; +short rid_ind; +char *oldval; +short oldval_ind; +char *newval; +short newval_ind; +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + OCIBind *bndp1 = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + ub4 key; /* key value set in "self" */ + + char updstmt[2000]; /* sql insert statement */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct update Statement * + ******************************/ + + sprintf(updstmt, + "UPDATE %s.%s_sbtree SET f1 = :newval, f2 = :rr WHERE f1 = :oldval", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + + /**************************************** + * Parse and Execute Create Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, (text *)updstmt, + (ub4)strlen(updstmt), OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + + /* Set up bind for newval */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)1, + (dvoid *)newval, + (sb4)(strlen(newval)+1), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)2, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up bind for oldval */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)3, + (dvoid *)oldval, + (sb4)(strlen(oldval)+1), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + return(rval); +} + +/* ODCIIndexStart function */ +OCINumber *qxiqtbs(ctx, sctx, sctx_ind, ix, ix_ind, pr, pr_ind, qy, qy_ind, + strt, strt_ind, stop, stop_ind, cmpval, cmpval_ind) +OCIExtProcContext *ctx; +qxiqtim *sctx; +qxiqtin *sctx_ind; +ODCIIndexInfo *ix; +dvoid *ix_ind; +ODCIPredInfo *pr; +dvoid *pr_ind; +ODCIQueryInfo *qy; +dvoid *qy_ind; +OCINumber *strt; +short strt_ind; +OCINumber *stop; +short stop_ind; +char *cmpval; +short cmpval_ind; +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int strtval; /* start bound */ + int stopval; /* stop bound */ + + int errnum = 29400; /* choose some oracle error number */ + char errmsg[512]; /* error message buffer */ + size_t errmsglen; /* Length of error message */ + + char relop[3]; /* relational operator used in sql stmt */ + char selstmt[2000]; /* sql select statement */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + ub4 key; /* key value set in "sctx" */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, + errhp))) + return(rval); + + + /**********************************************/ + /* Allocate memory to hold index scan context */ + /**********************************************/ + if (qxiqtce(ctx, errhp, OCIMemoryAlloc((dvoid *)usrhp, errhp, + (dvoid **)&icx, + OCI_DURATION_STATEMENT, + (ub4)(sizeof(qxiqtcx)), + OCI_MEMORY_CLEARED))) + return(rval); + + icx->stmthp = (OCIStmt *)0; + icx->defnp = (OCIDefine *)0; + icx->bndp = (OCIBind *)0; + + /***********************************/ + /* Check that the bounds are valid */ + /***********************************/ + /* convert from oci numbers to native numbers */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, strt, + sizeof(strtval), OCI_NUMBER_SIGNED, + (dvoid *)&strtval))) + return(rval); + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, stop, + sizeof(stopval), + OCI_NUMBER_SIGNED, (dvoid *)&stopval))) + return(rval); + + /* verify that strtval/stopval are both either 0 or 1 */ + if (!(((strtval == 0) && (stopval == 0)) || + ((strtval == 1) && (stopval == 1)))) + { + strcpy(errmsg, (char *)"Incorrect predicate for sbtree operator"); + errmsglen = (size_t)strlen(errmsg); + if (OCIExtProcRaiseExcpWithMsg(ctx, errnum, (text *)errmsg, errmsglen) + != OCIEXTPROC_SUCCESS) + /* Use cartridge error services here */; + return(rval); + } + + /*********************************************/ + /* Generate the SQL statement to be executed */ + /*********************************************/ + if (memcmp((dvoid *)OCIStringPtr(envhp, pr->ObjectName), (dvoid *)"EQ", 2) + == 0) + if (strtval == 1) + strcpy(relop, (char *)"="); + else + strcpy(relop, (char *)"!="); + else if (memcmp((dvoid *)OCIStringPtr(envhp, pr->ObjectName), (dvoid *)"LT", + 2) == 0) + if (strtval == 1) + strcpy(relop, (char *)"<"); + else + strcpy(relop, (char *)">="); + else + if (strtval == 1) + strcpy(relop, (char *)">"); + else + strcpy(relop, (char *)"<="); + + sprintf(selstmt, "select f2 from %s.%s_sbtree where f1 %s :val", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), relop); + + /***********************************/ + /* Parse, bind, define and execute */ + /***********************************/ + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&(icx->stmthp), + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(icx->stmthp, errhp, (text *)selstmt, + (ub4)strlen(selstmt), OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + /* Set up bind */ + if (qxiqtce(ctx, errhp, + OCIBindByPos(icx->stmthp, &(icx->bndp), errhp, (ub4)1, + (dvoid *)cmpval, + (sb4)(strlen(cmpval)+1), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up define */ + if (qxiqtce(ctx, errhp, OCIDefineByPos(icx->stmthp, &(icx->defnp), errhp, + (ub4)1, (dvoid *)(icx->ridp), + (sb4) sizeof(icx->ridp), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)OCI_DEFAULT))) + return(rval); + + /* execute */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, icx->stmthp, errhp, (ub4)0, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /************************************/ + /* Set index context to be returned */ + /************************************/ + /* generate a key */ + if (qxiqtce(ctx, errhp, OCIContextGenerateKey((dvoid *)usrhp, errhp, &key))) + return(rval); + /* set the memory address of the struct to be saved in the context */ + if (qxiqtce(ctx, errhp, OCIContextSetValue((dvoid *)usrhp, errhp, + OCI_DURATION_STATEMENT, + (ub1 *)&key, (ub1)sizeof(key), + (dvoid *)icx))) + return(rval); + /* set the key as the member of "sctx" */ + if (qxiqtce(ctx, errhp, OCIRawAssignBytes(envhp, errhp, (ub1 *)&key, + (ub4)sizeof(key), + &(sctx->sctx_qxiqtim)))) + return(rval); + + sctx_ind->atomic_qxiqtin = OCI_IND_NOTNULL; + sctx_ind->scind_qxiqtin = OCI_IND_NOTNULL; + + return(rval); +} + + +/* ODCIIndexFetch function */ +OCINumber *qxiqtbf(ctx, self, self_ind, nrows, nrows_ind, rids, rids_ind) +OCIExtProcContext *ctx; +qxiqtim *self; +qxiqtin *self_ind; +OCINumber *nrows; +short nrows_ind; +OCIArray **rids; +short *rids_ind; +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int idx = 1; + int nrowsval; + + OCIArray *ridarrp = *rids; /* rowid collection */ + OCIString *ridstr = (OCIString *)0; + + int done = 0; + int retval = (int)ODCI_SUCCESS; + OCINumber *rval = (OCINumber *)0; + + ub1 *key; /* key to retrieve context */ + ub4 keylen; /* length of key */ + + /*******************/ + /* Get OCI handles */ + /*******************/ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, + OCINumberFromInt(errhp, (dvoid *)&retval, sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, errhp))) + return(rval); + + /********************************/ + /* Retrieve context from key */ + /********************************/ + key = OCIRawPtr(envhp, self->sctx_qxiqtim); + keylen = OCIRawSize(envhp, self->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + key, (ub1)keylen, + (dvoid **)&(icx)))) + return(rval); + + /* get value of nrows */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, nrows, sizeof(nrowsval), + OCI_NUMBER_SIGNED, (dvoid *)&nrowsval))) + return(rval); + + /****************/ + /* Fetch rowids */ + /****************/ + while (!done) + { + if (idx > nrowsval) + done = 1; + else + { + status = OCIStmtFetch(icx->stmthp, errhp, (ub4)1, (ub2) 0, + (ub4)OCI_DEFAULT); + if (status == OCI_NO_DATA) + { + short col_ind = OCI_IND_NULL; + /* have to create dummy oci string */ + OCIStringAssignText(envhp, errhp, (text *)"dummy", + (ub2)5, &ridstr); + /* append null element to collection */ + if (qxiqtce(ctx, errhp, OCICollAppend(envhp, errhp,(dvoid *)ridstr, + (dvoid *)&col_ind, + (OCIColl *)ridarrp))) + return(rval); + done = 1; + } + else if (status == OCI_SUCCESS) + { + OCIStringAssignText(envhp, errhp, (text *)icx->ridp, + (ub2)18, (OCIString **)&ridstr); + /* append rowid to collection */ + if (qxiqtce(ctx, errhp, OCICollAppend(envhp, errhp, (dvoid *)ridstr, + (dvoid *)0, (OCIColl *)ridarrp))) + return(rval); + idx++; + } + else if (qxiqtce(ctx, errhp, status)) + return(rval); + } + } + + /* free ridstr finally */ + if (ridstr && + (qxiqtce(ctx, errhp, OCIStringResize(envhp, errhp, (ub4)0, + &ridstr)))) + return(rval); + + *rids_ind = OCI_IND_NOTNULL; + + return(rval); +} + + +/* ODCIIndexClose function */ +OCINumber *qxiqtbc(ctx, self, self_ind) +OCIExtProcContext *ctx; +qxiqtim *self; +qxiqtin *self_ind; +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int retval = (int) ODCI_SUCCESS; + OCINumber *rval = (OCINumber *)0; + + ub1 *key; /* key to retrieve context */ + ub4 keylen; /* length of key */ + + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, errhp))) + return(rval); + + /********************************/ + /* Retrieve context using key */ + /********************************/ + key = OCIRawPtr(envhp, self->sctx_qxiqtim); + keylen = OCIRawSize(envhp, self->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + key, (ub1)keylen, + (dvoid **)&(icx)))) + return(rval); + + /* Free handles and memory */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)icx->stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + if (qxiqtce(ctx, errhp, OCIMemoryFree((dvoid *)usrhp, errhp, (dvoid *)icx))) + return(rval); + + return(rval); +} + + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ +static int qxiqtce(ctx, errhp, status) +OCIExtProcContext *ctx; +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + int errnum = 29400; /* choose some oracle error number */ + int rc = 0; + + switch (status) + { + case OCI_SUCCESS: + rc = 0; + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4)1, (text *)NULL, &errcode, + errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR); + OCIExtProcRaiseExcpWithMsg(ctx, errnum, errbuf, strlen((char *)errbuf)); + rc = 1; + break; + default: + (void) sprintf((char *)errbuf, "Warning - some error\n"); + OCIExtProcRaiseExcpWithMsg(ctx, errnum, errbuf, strlen((char *)errbuf)); + rc = 1; + break; + } + return (rc); +} + +/* end of file extdemo2.c */ + diff --git a/extdemo2.h b/extdemo2.h new file mode 100644 index 0000000..cc22b0d --- /dev/null +++ b/extdemo2.h @@ -0,0 +1,167 @@ +/* + * $Header: extdemo2.h 14-jul-99.12:48:29 mjaeger Exp $ + */ + +/* Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + NAME + extdemo2.h - Extensible Indexing example implemented as C routines + + DESCRIPTION + This file contains the definitions of the DML and Query routines + for the extensible indexing example that implements a simple btree + (sbtree). See extdemo2.sql for the SQL script that defines the + indextype. + + RELATED DOCUMENTS + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + qxiqtbs - QXIQT Btree Start routine + qxiqtbf - QXIQT Btree Fetch routine + qxiqtbc - QXIQT Btree Close routine + qxiqtbi - QXIQT Btree Insert routine + qxiqtbd - QXIQT Btree Delete routine + qxiqtbu - QXIQT Btree Update routine + + PRIVATE FUNCTION(S) + qxiqtbe - QXIQT error reporting routine + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + hdnguyen 04/02/99 - merged khackel fix in + khackel 02/03/99 - WIN32COMMON: added dllexport for public functions + rmurthy 06/16/98 - Creation + +*/ + + +#ifndef EXTDEMO2_ORACLE +# define EXTDEMO2_ORACLE + +#ifndef OCI_ORACLE +# include +#endif +#ifndef ODCI_ORACLE +# include +#endif + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +#ifdef WIN32COMMON +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + +/* index scan context - should be stored in "statement" duration memory + * and used by start, fetch and close routines. + */ +struct qxiqtcx +{ + OCIStmt *stmthp; + OCIDefine *defnp; + OCIBind *bndp; + char ridp[19]; +}; +typedef struct qxiqtcx qxiqtcx; + +/* The index implementation type is an ADT with a single RAW attribute + * which will be used to store the context key value. + * C mapping of the implementation type : + */ +struct qxiqtim +{ + OCIRaw *sctx_qxiqtim; +}; +typedef struct qxiqtim qxiqtim; + +struct qxiqtin +{ + short atomic_qxiqtin; + short scind_qxiqtin; +}; +typedef struct qxiqtin qxiqtin; + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ +/* ODCIIndexStart */ +OCINumber DLLEXPORT *qxiqtbs(/*_ OCIExtProcContext *ctx, + struct qxiqtim *sctx, struct qxiqtin *sctx_ind, + ODCIIndexInfo *ix, dvoid *ix_ind, + ODCIPredInfo *pr, dvoid *pr_ind, + ODCIQueryInfo *qy, dvoid *qy_ind, + OCINumber *strt, short strt_ind, + OCINumber *stop, short stop_ind, + char *cmpval, short cmpval_ind _*/); + +/* ODCIIndexFetch */ +OCINumber DLLEXPORT *qxiqtbf(/*_ OCIExtProcContext *ctx, + struct qxiqtim *self, struct qxiqtin *self_ind, + OCINumber *nrows, short nrows_ind, + OCIArray **rids, short *rids_ind _*/); + +/* ODCIIndexClose */ +OCINumber DLLEXPORT *qxiqtbc(/*_ OCIExtProcContext *ctx, + struct qxiqtim *self, struct qxiqtin *self_ind _*/); + +/* ODCIIndexInsert */ +OCINumber DLLEXPORT *qxiqtbi(/*_ OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *newval, + short newval_ind _*/); + +/* ODCIIndexDelete */ +OCINumber DLLEXPORT *qxiqtbd(/*_ OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *oldval, + short oldval_ind _*/); + +/* ODCIIndexUpdate */ +OCINumber DLLEXPORT *qxiqtbu(/*_ OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *oldval, + short oldval_ind, + char *newval, + short newval_ind _*/); + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ +static int qxiqtce(/*_ OCIExtProcContext *ctx, OCIError *errhp, + sword status _*/); + +#endif /* EXTDEMO2_ORACLE */ diff --git a/extdemo2.sql b/extdemo2.sql new file mode 100644 index 0000000..332ee11 --- /dev/null +++ b/extdemo2.sql @@ -0,0 +1,421 @@ +rem +rem $Header: extdemo2.sql 09-mar-2001.14:56:24 rmurthy Exp $ +rem +rem extdemo2.sql +rem +rem Copyright (c) 1998, 1999,, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem extdemo2.sql - An extensible indexing example +rem implemented as C routines +rem +rem DESCRIPTION +rem This file demonstrates the definition and usage of a simple +rem btree indextype whose routines are implemented as C callouts. +rem The C routines are in the file extdemo2.c +rem The header file is extdemo2.h +rem +rem The foll. steps should have been done before running +rem this script. +rem 1. Compile the C file (i.e make -f demo_rdbms.mk demos) +rem 2. Create a user named extdemo2 with password extdemo2 +rem 3. Create a library in extdemo2 schema called extdemo2l +rem which points to the compiled extdemo2.c +rem +rem The design of the indextype is as follows : +rem +rem The sbtree indextype implemented here will support the evaluation +rem of three user-defined operators : gt(Greater Than), lt(Less Than) +rem and eq(EQuals). These operators can operate on the operands of +rem VARCHAR2 datatype. +rem To simplify the implementation of the indextype, we will store +rem the index data in a regular table. +rem Thus, our code merely translates operations on the SB-tree into +rem operations on the table storing the index data. +rem When a user creates a SB-tree index, we will create a table +rem consisting of the indexed column and a rowid column. Inserts into +rem the base table will cause appropriate insertions into the index table. +rem Deletes and updates are handled similarly. +rem When the SB-tree is queried based on a user-defined operator (one +rem of gt, lt and eq), we will fire off an appropriate query against +rem the index table to retrieve all the satisfying rows and return them. +rem +rem MODIFIED (MM/DD/YY) +rem rmurthy 03/09/01 - bug 1676437 - change call to extdemo0 +rem rmurthy 01/13/00 - add path name while calling utlxplan +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem hdnguyen 07/26/99 - sqlplus conversion +rem hdnguyen 06/15/99 - modified step 1 to add compile instruction +rem rmurthy 09/25/98 - Created + +--------------------------------------------------------------------- +-- SIMPLE B-TREE Index Method Implemented as C Callouts -- +--------------------------------------------------------------------- + +connect extdemo2/extdemo2 +set echo off +@'?/rdbms/admin/utlxplan.sql' +set echo on + +-- CREATE FUNCTIONAL IMPLEMENTATIONS for operators + +create function bt_eq(a varchar2, b varchar2) return number as +begin + if a = b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_lt(a varchar2, b varchar2) return number as +begin + if a < b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_gt(a varchar2, b varchar2) return number as +begin + if a > b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +-- CREATE BTREE OPERATORS + +create operator eq binding (varchar2, varchar2) return number using bt_eq; + +create operator lt binding (varchar2, varchar2) return number using bt_lt; + +create operator gt binding (varchar2, varchar2) return number using bt_gt; + + +-- CREATE INDEXTYPE IMPLEMENTATION TYPE +create type sbtree_im as object +( + scanctx RAW(4), + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return NUMBER, + static function ODCIIndexCreate (ia sys.odciindexinfo, parms varchar2) + return number, + static function ODCIIndexDrop(ia sys.odciindexinfo) return number, + STATIC FUNCTION odciindexinsert(ia sys.odciindexinfo, rid VARCHAR2, + newval VARCHAR2) + RETURN NUMBER, + STATIC FUNCTION odciindexdelete(ia sys.odciindexinfo, rid VARCHAR2, + oldval VARCHAR2) + RETURN NUMBER, + STATIC FUNCTION odciindexupdate(ia sys.odciindexinfo, rid VARCHAR2, + oldval VARCHAR2, newval VARCHAR2) + RETURN NUMBER, + static function ODCIIndexStart(sctx IN OUT sbtree_im, ia sys.odciindexinfo, + op sys.odciPredInfo, qi sys.ODCIQueryInfo, + strt number, stop number, + cmpval varchar2) return number, + member function ODCIIndexFetch(nrows number, rids OUT sys.odciridlist) + return number, + member function ODCIIndexClose return number +); +/ +show errors + + +--------------------------------- +-- CREATE IMPLEMENTATION UNIT -- +--------------------------------- + +-- CREATE TYPE BODY +create or replace type body sbtree_im +is + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return number is + begin + ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCIINDEX1')); + return ODCIConst.Success; + end ODCIGetInterfaces; + + static function ODCIIndexCreate (ia sys.odciindexinfo, parms varchar2) + return number + is + i integer; + stmt varchar2(1000); + cnum integer; + junk integer; + begin + -- construct the sql statement + stmt := 'create table ' || ia.IndexSchema || '.' || + ia.IndexName || '_sbtree' || + '( f1 , f2 ) as select ' || + ia.IndexCols(1).ColName || ', ROWID from ' || + ia.IndexCols(1).TableSchema || '.' || ia.IndexCols(1).TableName; + + dbms_output.put_line('CREATE'); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + return ODCIConst.Success; + end; + + static function ODCIIndexDrop(ia sys.odciindexinfo) return number is + stmt varchar2(1000); + cnum integer; + junk integer; + begin + -- construct the sql statement + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || '_sbtree'; + + dbms_output.put_line('DROP'); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + return ODCIConst.Success; + end; + + STATIC FUNCTION odciindexinsert(ia sys.odciindexinfo, rid VARCHAR2, + newval VARCHAR2) + RETURN NUMBER AS external + name "qxiqtbi" + library extdemo2l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + newval, + newval indicator, + RETURN ocinumber + ); + + STATIC FUNCTION odciindexdelete(ia sys.odciindexinfo, rid VARCHAR2, + oldval VARCHAR2) + RETURN NUMBER AS external + name "qxiqtbd" + library extdemo2l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + oldval, + oldval indicator, + RETURN ocinumber + ); + + STATIC FUNCTION odciindexupdate(ia sys.odciindexinfo, rid VARCHAR2, + oldval VARCHAR2, newval VARCHAR2) + RETURN NUMBER AS external + name "qxiqtbu" + library extdemo2l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + oldval, + oldval indicator, + newval, + newval indicator, + RETURN ocinumber + ); + + static function ODCIIndexStart(sctx in out sbtree_im, ia sys.odciindexinfo, + op sys.odciPredInfo, + qi sys.ODCIQueryInfo, + strt number, + stop number, + cmpval varchar2) + return number as external + name "qxiqtbs" + library extdemo2l + with context + parameters ( + context, + sctx, + sctx INDICATOR STRUCT, + ia, + ia INDICATOR STRUCT, + op, + op INDICATOR STRUCT, + qi, + qi INDICATOR STRUCT, + strt, + strt INDICATOR, + stop, + stop INDICATOR, + cmpval, + cmpval INDICATOR, + return OCINumber + ); + + member function ODCIIndexFetch(nrows number, rids OUT sys.odciridlist) + return number as external + name "qxiqtbf" + library extdemo2l + with context + parameters ( + context, + self, + self INDICATOR STRUCT, + nrows, + nrows INDICATOR, + rids, + rids INDICATOR, + return OCINumber + ); + + member function ODCIIndexClose return number as external + name "qxiqtbc" + library extdemo2l + with context + parameters ( + context, + self, + self INDICATOR STRUCT, + return OCINumber + ); + +end; +/ +show errors + +--------------------- +-- CREATE INDEXTYPE +--------------------- + +create indextype sbtree +for +eq(varchar2, varchar2), +lt(varchar2, varchar2), +gt(varchar2, varchar2) +using sbtree_im; + +-------------------------- +-- USAGE EXAMPLES -- +-------------------------- +set serveroutput on size 20000 + +---------------- +-- CREATE TABLE +---------------- + +create table t1 (f1 number, f2 varchar2(200)); +insert into t1 values (1, 'ravi'); +insert into t1 values (3, 'murthy'); +commit; + +----------------- +-- CREATE INDEX +----------------- + +create index it1 on t1(f2) indextype is sbtree parameters('test'); + +------------ +-- QUERIES +------------ + +explain plan for +select * from t1 where eq(f2, 'ravi') = 1; +set echo off +@@extdemo0 +set echo on +select * from t1 where eq(f2, 'ravi') = 1; + +explain plan for +select * from t1 where gt(f2, 'aaa') = 1; +set echo off +@@extdemo0 +set echo on +select * from t1 where gt(f2, 'aaa') = 1; + +explain plan for +select * from t1 where lt(f2, 'aaa') = 1; +set echo off +@@extdemo0 +set echo on +select * from t1 where lt(f2, 'aaa') = 1; + +explain plan for +select * from t1 where lt(f2, 'aaa') = 0; +set echo off +@@extdemo0 +set echo on +select * from t1 where lt(f2, 'aaa') = 0; + +----------- +-- INSERTS +----------- + +INSERT INTO t1 VALUES (6, 'cheuk'); +INSERT INTO t1 VALUES (7, 'chau'); +explain plan for +select * from t1 where eq(f2, 'cheuk') = 1; +set echo off +@@extdemo0 +set echo on +select * from t1 where eq(f2, 'cheuk') = 1; + +----------- +-- DELETES +----------- + +DELETE FROM t1 WHERE f2 = 'ravi'; +explain plan for +select * from t1 where eq(f2, 'ravi') = 1; +set echo off +@@extdemo0 +set echo on +select * from t1 where eq(f2, 'ravi') = 1; + +----------- +-- UPDATES +----------- + +UPDATE t1 SET f2 = 'Nipun' WHERE f1 = 3; +explain plan for +select * from t1 where eq(f2, 'Nipun') = 1; +set echo off +@@extdemo0 +set echo on +select * from t1 where eq(f2, 'Nipun') = 1; + +------------ +-- CLEANUPS +------------ + +drop index it1; +drop table t1; +drop indextype sbtree; +drop type sbtree_im; +drop operator eq; +drop operator lt; +drop operator gt; +drop function bt_eq; +drop function bt_lt; +drop function bt_gt; diff --git a/extdemo3.java b/extdemo3.java new file mode 100644 index 0000000..0a1dc8b --- /dev/null +++ b/extdemo3.java @@ -0,0 +1,408 @@ +/* $Header: extdemo3.java 30-mar-2006.18:37:53 yhu Exp $ */ + +/* Copyright (c) 1999, 2006, Oracle. All rights reserved. */ + +/* + DESCRIPTION + extdemo3.java - class that implements the ODCIIndex methods. + This class was originally generated using JPUB based + on the type that extensible index is based on. The + methods were implemented after the class was generated. + + PRIVATE CLASSES + + NOTES + + MODIFIED (MM/DD/YY) + yhu 03/30/06 - remove dependencies on classes12 + hdnguyen 08/10/01 - case sensitive fixes due to 9.0.2 regen of ODCIs + rshaikh 06/23/99 - create + rshaikh 06/23/99 - Creation + */ + +/** + * @version $Header: extdemo3.java 30-mar-2006.18:37:53 yhu Exp $ + * @author rshaikh + * @since release specific 8.1.6 + */ +import java.sql.SQLException; +import java.sql.Connection; +import oracle.jdbc.OracleTypes; +import oracle.sql.ORAData; +import oracle.sql.ORADataFactory; +import oracle.sql.Datum; +import oracle.sql.STRUCT; +import oracle.jpub.runtime.MutableStruct; + +import java.lang.*; +import java.sql.*; +import oracle.*; +import oracle.sql.*; +import oracle.jdbc.*; +import sqlj.runtime.ref.DefaultContext; +import sqlj.runtime.ConnectionContext; +import oracle.ODCI.*; +import oracle.CartridgeServices.*; + +public class extdemo3 implements ORAData, ORADataFactory +{ + public static final String _SQL_NAME = "EXTDEMO.EXTDEMO3"; + public static final int _SQL_TYPECODE = OracleTypes.STRUCT; + + final static java.math.BigDecimal SUCCESS = new java.math.BigDecimal("0"); + final static java.math.BigDecimal ERROR = new java.math.BigDecimal("1"); + final static int TRUE = 1; + final static int FALSE = 0; + + /* connection management */ + protected DefaultContext __tx = null; + protected Connection __onn = null; + public void setConnectionContext(DefaultContext ctx) throws SQLException + { release(); __tx = ctx; } + public DefaultContext getConnectionContext() throws SQLException + { if (__tx==null) + { __tx = (__onn==null) ? DefaultContext.getDefaultContext() : new DefaultContext(__onn); } + return __tx; + }; + public Connection getConnection() throws SQLException + { return (__onn==null) ? ((__tx==null) ? null : __tx.getConnection()) : __onn ; } + public void release() throws SQLException + { if (__tx!=null && __onn!=null) __tx.close(ConnectionContext.KEEP_CONNECTION ); + __onn = null; __tx = null; + } + + protected MutableStruct _struct; + + private static int[] _sqlType = { 4 }; + private static ORADataFactory[] _factory = new ORADataFactory[1]; + protected static final extdemo3 _extdemo3Factory = new extdemo3(false); + + public static ORADataFactory getORADataFactory() + { return _extdemo3Factory; } + + /* constructor */ + protected extdemo3(boolean init) + { if (init) _struct = new MutableStruct(new Object[1], _sqlType, _factory); } + public extdemo3() + { this(true); __tx = DefaultContext.getDefaultContext(); } + public extdemo3(DefaultContext c) throws SQLException + { this(true); __tx = c; } + public extdemo3(Connection c) throws SQLException + { this(true); __onn = c; } + + /* ORAData interface */ + public Datum toDatum(Connection c) throws SQLException + { + if (__tx!=null && __onn!=c) release(); + __onn = c; + return _struct.toDatum(c, _SQL_NAME); + } + + /* ORADataFactory interface */ + public ORAData create(Datum d, int sqlType) throws SQLException + { return create(null, d, sqlType); } + public void setFrom(extdemo3 o) throws SQLException + { release(); _struct = o._struct; __tx = o.__tx; __onn = o.__onn; } + protected void setValueFrom(extdemo3 o) { _struct = o._struct; } + protected ORAData create(extdemo3 o, Datum d, int sqlType) throws SQLException + { + if (d == null) { if (o!=null) { o.release(); }; return null; } + if (o == null) o = new extdemo3(false); + o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory); + o.__onn = ((STRUCT) d).getJavaSqlConnection(); + return o; + } + + /* accessor methods */ + public Integer getScanctx() throws SQLException + { return (Integer) _struct.getAttribute(0); } + + public void setScanctx(Integer scanctx) throws SQLException + { _struct.setAttribute(0, scanctx); } + + // ODCIIndexStart + public static java.math.BigDecimal ODCIStart(extdemo3 sctx[], + ODCIIndexInfo ia, ODCIPredInfo op, + ODCIQueryInfo qi, + java.math.BigDecimal strt, java.math.BigDecimal stop, + String cmpval) + throws java.sql.SQLException + { + String relop; + String selstmt; + int key; + extdemo3a sbtctx; // cntxt obj that holds the ResultSet and Statement + PreparedStatement ps; + OracleResultSet rset; + + Connection conn = + sqlj.runtime.RuntimeContext.getRuntime().getDefaultConnection(); + + + CallableStatement cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(\'Start \')}"); + cstmt.executeUpdate(); + + //*********************************** + //* Check that the bounds are valid * + //*********************************** + // verify that strtval/stopval are both either 0 or 1 + if (!(((strt.intValue() == 0) && (stop.intValue() == 0)) || + ((strt.intValue() == 1) && (stop.intValue() == 1)))) + { + // throw Application_Error + System.out.println("incorrect predicate for btree operator"); + return ERROR; + } + + String s = new String("start key: "+ strt.intValue() + " stop key: " + + stop.intValue() + " compare value: " + cmpval); + cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(?)}"); + cstmt.setString(1, s); + cstmt.executeUpdate(); + + //********************************************* + //* Generate the SQL statement to be executed * + //********************************************* + if ((op.getObjectName()).equals("EQ")){ + if (strt.intValue() == 1) + relop = new String("="); + else + relop = new String("!="); + }else if ((op.getObjectName()).equals("LT")){ + if (strt.intValue() == 1) + relop = new String("<"); + else + relop = new String(">="); + }else{ + if (strt.intValue() == 1) + relop = new String(">"); + else + relop = new String("<="); + } + + selstmt = new String("select ROWIDTOCHAR(f2) from " + + ia.getIndexSchema() + + "." + + ia.getIndexName() + + "_sbtree where f1 " + + relop + " '" + cmpval + "'"); + cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(?)}"); + cstmt.setString(1, selstmt); + cstmt.executeUpdate(); + + + ps = conn.prepareStatement(selstmt); + rset = (OracleResultSet) ps.executeQuery(); + + // set result set in ContextManager. This stores away the + // ResultSet and the Statement handle so that they can + // be used to fetch the rowids and cleanup at a later time. + sbtctx = new extdemo3a(rset, ps); + sctx[0] = new extdemo3(); + + try{ + key = ContextManager.setContext((Object)sbtctx); + }catch (CountException ce) { + System.out.println("ContextManager CountException error"); + return ERROR; + } + + System.out.println("ContextManager key=" + key); + + // set the key into the self argument so that we can retrieve the + // context with this key later. + sctx[0].setScanctx(new Integer(key)); + + return SUCCESS; + } + + // ODCIIndexFetch + public java.math.BigDecimal ODCIFetch( + java.math.BigDecimal nrows, + ODCIRidList rids[]) + throws java.sql.SQLException + { + extdemo3a sbtctx; // cntxt obj that holds the ResultSet and Statement + OracleResultSet rset; + String rid; + int idx = 1; + int done = FALSE; + String[] rlist = new String[nrows.intValue()]; + int key = getScanctx().intValue(); + + Connection conn = + sqlj.runtime.RuntimeContext.getRuntime().getDefaultConnection(); + CallableStatement cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(\'Fetch \')}"); + cstmt.executeUpdate(); + + String s = new String("nrows : " + nrows); + cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(?)}"); + cstmt.setString(1, s); + cstmt.executeUpdate(); + + System.out.println("ContextManager key=" + key); + + // Get the resultSet back from the ContextManager using the key + try{ + sbtctx= (extdemo3a)ContextManager.getContext(key); + }catch(InvalidKeyException ike){ + System.out.println("ContextManager InvalidKeyException"); + return ERROR; + } + rset = (OracleResultSet)(sbtctx.getRs()); + + //*************** + // Fetch rowids * + //*************** + for(int i=0; done != TRUE; i++) + { + if (idx > nrows.intValue()){ + done = TRUE; + }else { + if (rset.next()){ + // append rowid to collection + rid = rset.getString(1); + rlist[i] = new String(rid); + idx++; + }else{ + // append null rowid to collection + rlist[i] = null; + done = TRUE; + } + } + } + + // Since rids is an out parameter we need to set the ODCIRidList + // object into the first position to be passed out. + rids[0] = new ODCIRidList(rlist); + + return SUCCESS; + } + + // ODCIIndexClose + public java.math.BigDecimal ODCIClose() + throws java.sql.SQLException + { + extdemo3a sbtctx; // contxt obj that holds the ResultSet and Statement + OracleResultSet rset; + PreparedStatement ps; + System.out.println("in odciclose"); + + int key = getScanctx().intValue(); + System.out.println("in odciclose2"); + + Connection conn = + sqlj.runtime.RuntimeContext.getRuntime().getDefaultConnection(); + CallableStatement cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(\'Close\')}"); + cstmt.executeUpdate(); + + System.out.println("key=" + key); + + // Get the resultSet and statement back from the ContextManager + // so that we can close them. + try{ + sbtctx = (extdemo3a)ContextManager.clearContext(key); + }catch(InvalidKeyException ike){ + System.out.println("ContextManager InvalidKeyException"); + return ERROR; + } + + rset = (OracleResultSet)sbtctx.getRs(); + ps = (PreparedStatement)sbtctx.getStmt(); + rset.close(); + ps.close(); + + return SUCCESS; + } + + // ODCIIndexInsert + public static java.math.BigDecimal ODCIInsert( + ODCIIndexInfo ia, String rid, String newval) + throws java.sql.SQLException + { + String insstmt; + + Connection conn = + sqlj.runtime.RuntimeContext.getRuntime().getDefaultConnection(); + CallableStatement cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(\'Insert\')}"); + cstmt.executeUpdate(); + + /****************************** + * Construct insert Statement * + ******************************/ + insstmt = new String("INSERT into " + + ia.getIndexSchema() + "." + ia.getIndexName() + +"_sbtree values ('" + newval + "','" + rid + "')" ); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate(insstmt); + stmt.close(); + + return SUCCESS; + } + + // ODCIIndexDelete + public static java.math.BigDecimal ODCIDelete( + ODCIIndexInfo ia, String rid, String oldval) + throws java.sql.SQLException + { + + String delstmt; + + Connection conn = + sqlj.runtime.RuntimeContext.getRuntime().getDefaultConnection(); + CallableStatement cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(\'Delete\')}"); + cstmt.executeUpdate(); + + /****************************** + * Construct delete Statement * + ******************************/ + delstmt = new String("DELETE from " + + ia.getIndexSchema() + "." + ia.getIndexName() + +"_sbtree where f1= '" + oldval +"'" ); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate(delstmt); + stmt.close(); + + return SUCCESS; + } + + // ODCIIndexUpdate + public static java.math.BigDecimal ODCIUpdate( + ODCIIndexInfo ia, String rid, String oldval, + String newval) + throws java.sql.SQLException + { + String updstmt; + + Connection conn = + sqlj.runtime.RuntimeContext.getRuntime().getDefaultConnection(); + CallableStatement cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(\'Update\')}"); + cstmt.executeUpdate(); + + /****************************** + * Construct update Statement * + ******************************/ + updstmt = new String("UPDATE " + + ia.getIndexSchema() + "." + ia.getIndexName() + +"_sbtree SET f1= '" + newval + "' WHERE f1 = '" + + oldval +"'"); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate(updstmt); + stmt.close(); + + return SUCCESS; + } + +} diff --git a/extdemo3.sql b/extdemo3.sql new file mode 100644 index 0000000..149717b --- /dev/null +++ b/extdemo3.sql @@ -0,0 +1,313 @@ +Rem +Rem $Header: extdemo3.sql 09-mar-2001.14:56:30 rmurthy Exp $ +Rem +Rem extdemo3.sql +Rem +Rem Copyright (c) Oracle Corporation 1999, 2000. All Rights Reserved. +Rem +rem NAME +rem extdemo3.sql - An extensible indexing example +rem implemented as Java callouts. +rem +rem DESCRIPTION +rem This file demonstrates the definition and usage of a simple +rem btree indextype whose routines are implemented as Java callouts. +rem +rem The Java methods are in the file extdemo3.java +rem The associated context class is in extdemo3a.java +rem +rem The foll. steps should have been done before running +rem this script. +rem 1. Compile the Java files +rem (i.e javac extdemo3a.java, javac extdemo3.java . Make +rem sure that the ORACLE_HOME/rdbms/jlib/ODCI.jar and +rem ORACLE_HOME/rdbms/jlib/CartridgeServices.jar files are in +rem your classpath and that these files have been loaded into the +rem database in SYS schema) +rem 2. Create a user named extdemo with password extdemo +rem 3. Grant create any directory privilege to extdemo +rem 3. Create a directory in extdemo schema called vmtestdir +rem which points to the directory containing the compiled +rem extdemo3.class and extdemo3a.class +rem +rem The design of the indextype is as follows : +rem +rem The sbtree indextype implemented here will support the evaluation +rem of three user-defined operators : gt(Greater Than), lt(Less Than) +rem and eq(EQuals). These operators can operate on the operands of +rem VARCHAR2 datatype. +rem To simplify the implementation of the indextype, we will store +rem the index data in a regular table. +rem Thus, our code merely translates operations on the SB-tree into +rem operations on the table storing the index data. +rem When a user creates a SB-tree index, we will create a table +rem consisting of the indexed column and a rowid column. Inserts into +rem the base table will cause appropriate insertions into the index table. +rem Deletes and updates are handled similarly. +rem When the SB-tree is queried based on a user-defined operator (one +rem of gt, lt and eq), we will fire off an appropriate query against +rem the index table to retrieve all the satisfying rows and return them. +Rem +Rem MODIFIED (MM/DD/YY) +Rem rmurthy 03/09/01 - bug 1676437 - change call to extdemo0 +Rem hdnguyen 11/14/00 - fixed connect internal +Rem rmurthy 01/12/00 - add path name while calling utlxplan +Rem hdnguyen 09/16/99 - Use extdemo0 +Rem rshaikh 09/13/99 - Created +Rem + +--------------------------------------------------------------------- +-- SIMPLE B-TREE Index Method Implemented as Trusted Callouts -- +--------------------------------------------------------------------- +connect extdemo/extdemo +set echo off +@'?/rdbms/admin/utlxplan.sql' +set echo on + +-- CREATE FUNCTIONAL IMPLEMENTATIONS for operators + +create function bt_eq(a varchar2, b varchar2) return number as +begin + if a = b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_lt(a varchar2, b varchar2) return number as +begin + if a < b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_gt(a varchar2, b varchar2) return number as +begin + if a > b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +-- CREATE BTREE OPERATORS + +create operator eq binding (varchar2, varchar2) return number using bt_eq; + +create operator lt binding (varchar2, varchar2) return number using bt_lt; + +create operator gt binding (varchar2, varchar2) return number using bt_gt; + + +-- CREATE INDEXTYPE IMPLEMENTATION TYPE +create or replace type extdemo3 as object +( + scanctx integer, + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) return NUMBER, + static function ODCIIndexCreate (ia sys.odciindexinfo, parms varchar2) return number, + static function ODCIIndexDrop(ia sys.odciindexinfo) return number, + + STATIC FUNCTION odciindexinsert(ia sys.odciindexinfo, rid VARCHAR2, + newval VARCHAR2) + RETURN NUMBER AS LANGUAGE JAVA NAME + 'extdemo3.ODCIInsert(oracle.ODCI.ODCIIndexInfo, java.lang.String, + java.lang.String) return java.math.BigDecimal', + + STATIC FUNCTION odciindexdelete(ia sys.odciindexinfo, rid VARCHAR2, + oldval VARCHAR2) + RETURN NUMBER AS LANGUAGE JAVA NAME + 'extdemo3.ODCIDelete(oracle.ODCI.ODCIIndexInfo, java.lang.String, + java.lang.String) return java.math.BigDecimal', + + STATIC FUNCTION odciindexupdate(ia sys.odciindexinfo, rid VARCHAR2, + oldval VARCHAR2, newval VARCHAR2) + RETURN NUMBER AS LANGUAGE JAVA NAME + 'extdemo3.ODCIUpdate(oracle.ODCI.ODCIIndexInfo, java.lang.String, + java.lang.String, java.lang.String) return + java.math.BigDecimal', + + static function ODCIIndexStart(sctx in out extdemo3, ia sys.odciindexinfo, + op sys.odciPredInfo, + qi sys.ODCIQueryInfo, + strt number, + stop number, + cmpval varchar2) + RETURN NUMBER AS LANGUAGE JAVA NAME + 'extdemo3.ODCIStart(extdemo3[], oracle.ODCI.ODCIIndexInfo, + oracle.ODCI.ODCIPredInfo, + oracle.ODCI.ODCIQueryInfo, java.math.BigDecimal, + java.math.BigDecimal, + java.lang.String) return java.math.BigDecimal', + + member function ODCIIndexFetch(nrows number, rids OUT sys.odciridlist) + return number as LANGUAGE JAVA NAME + 'extdemo3.ODCIFetch(java.math.BigDecimal, + oracle.ODCI.ODCIRidList[]) return java.math.BigDecimal', + + member function ODCIIndexClose return number as LANGUAGE JAVA NAME + 'extdemo3.ODCIClose() return java.math.BigDecimal' + +); +/ +show errors + + +CREATE OR REPLACE JAVA CLASS USING BFILE (vmtestdir, 'extdemo3a.class') +/ +CREATE OR REPLACE JAVA CLASS USING BFILE (vmtestdir, 'extdemo3.class') +/ + +ALTER JAVA CLASS "extdemo3a" RESOLVE; +ALTER JAVA CLASS "extdemo3" RESOLVE; + + + + +--------------------------------- +-- CREATE IMPLEMENTATION UNIT -- +--------------------------------- + +-- CREATE TYPE BODY +create or replace type body extdemo3 +is + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return number is + begin + ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCIINDEX1')); + return ODCIConst.Success; + end ODCIGetInterfaces; + + static function ODCIIndexCreate (ia sys.odciindexinfo, parms varchar2) return number + is + i integer; + stmt varchar2(1000); + cnum integer; + junk integer; + begin + -- construct the sql statement + stmt := 'create table ' || ia.IndexSchema || '.' || + ia.IndexName || '_sbtree' || + '( f1 , f2 ) as select ' || + ia.IndexCols(1).ColName || ', ROWID from ' || + ia.IndexCols(1).TableSchema || '.' || ia.IndexCols(1).TableName; + + dbms_output.put_line('CREATE'); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + return ODCIConst.Success; + end; + + static function ODCIIndexDrop(ia sys.odciindexinfo) return number is + stmt varchar2(1000); + cnum integer; + junk integer; + begin + -- construct the sql statement + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || '_sbtree'; + + dbms_output.put_line('DROP'); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + return ODCIConst.Success; + end; + +end; +/ +show errors + +-------------------------- +-- USAGE EXAMPLES -- +-------------------------- + +-- CREATE INDEXTYPE +connect / as sysdba +grant create library to EXTDEMO; +grant create any directory to EXTDEMO; +grant create any operator, create indextype, create table to EXTDEMO; +connect extdemo/extdemo +set serveroutput on + +create indextype sbtree +for +eq(varchar2, varchar2), +lt(varchar2, varchar2), +gt(varchar2, varchar2) +using extdemo3; + +create table t1 (f1 number, f2 varchar2(200)); +insert into t1 values (1, 'ravi'); +insert into t1 values (3, 'murthy'); +commit; + +create index it1 on t1(f2) indextype is sbtree parameters('test'); + +-- query +explain plan for +select * from t1 where eq(f2, 'ravi') = 1; +set echo off +@@extdemo0 +set echo on + +select * from t1 where eq(f2, 'ravi') = 1; + +explain plan for +select * from t1 where gt(f2, 'aaa') = 1; +set echo off +@@extdemo0 +set echo on + +select * from t1 where gt(f2, 'aaa') = 1; + +-- INSERT TESTS +-- BUG 687446 +INSERT INTO t1 VALUES (6, 'cheuk'); +INSERT INTO t1 VALUES (7, 'chau'); + +-- query from index table +SELECT f1 FROM it1_sbtree; + +-- DELETE TEST +DELETE FROM t1 WHERE f2 = 'ravi'; + +-- query from index table +SELECT f1 FROM it1_sbtree; + +-- UPDATE TEST +UPDATE t1 SET f2 = 'Nipun' WHERE f1 = 3; + +-- query from index table +SELECT f1 FROM it1_sbtree; + +-- DROP TEST +drop table t1; + +describe t1; +describe it1; +describe it1_sbtree; + +drop index it1; +describe it1; +describe it1_sbtree; + + diff --git a/extdemo3a.java b/extdemo3a.java new file mode 100644 index 0000000..a57d393 --- /dev/null +++ b/extdemo3a.java @@ -0,0 +1,56 @@ +/* $Header: extdemo3a.java 30-mar-2006.18:38:05 yhu Exp $ */ + +/* Copyright (c) 1999, 2006, Oracle. All rights reserved. */ + +/* + DESCRIPTION + extdemo3a.java - class that holds the ResultSet and PreparedStatment + to be stored in CartridgeServices context + + MODIFIED (MM/DD/YY) + yhu 03/30/06 - remove dependencies on classes12 + rshaikh 06/24/99 - + rshaikh 06/23/99 - create + rshaikh 06/23/99 - Creation + */ + +/** + * @version $Header: extdemo3a.java 30-mar-2006.18:38:05 yhu Exp $ + * @author rshaikh + * @since release specific (what release of product did this appear in) + */ +import java.sql.SQLException; +import java.sql.Connection; +import oracle.jdbc.OracleTypes; +import oracle.sql.ORAData; +import oracle.sql.ORADataFactory; +import oracle.sql.Datum; +import oracle.sql.STRUCT; +import oracle.jpub.runtime.MutableStruct; + +import java.lang.*; +import java.sql.*; +import oracle.*; +import oracle.sql.*; +import oracle.jdbc.*; +import sqlj.runtime.ref.DefaultContext; +import sqlj.runtime.ConnectionContext; + +public class extdemo3a +{ + OracleResultSet rs; + PreparedStatement stmt; + + public extdemo3a(OracleResultSet r, PreparedStatement s) + { + rs=r; + stmt=s; + } + + public OracleResultSet getRs(){ return rs;} + public PreparedStatement getStmt() {return stmt;} + public void setRs(OracleResultSet r) {rs=r;} + public void setStmt(PreparedStatement s) {stmt=s;} + +} + diff --git a/extdemo4.c b/extdemo4.c new file mode 100644 index 0000000..ae58be3 --- /dev/null +++ b/extdemo4.c @@ -0,0 +1,788 @@ +#ifdef RCSID +static char *RCSid = + "$Header: extdemo4.c 08-feb-2001.18:14:54 ayoaz Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) Oracle Corporation 1998, 2000. All Rights Reserved. */ + +/* + + NAME + extdemo4.c - User Defined Aggregates using C safe callouts + using external context + + DESCRIPTION + See extdemo4.sql for the definition of the implementation type. + + NOTES + The implementation type contains two attributes, key and aggCtx. + Normally, the key will contains a value which identifes the + memory in extproc, where the aggregation context is stored, and + the aggCtx attribute will be NULL. + In certain situations, such as parallel aggregation, it is neccessary + to send the aggregation context from one slave to another, so + the external aggregation context will be "wrapped" into the + aggCtx attribute of the implementation type instance, and the key + will be set to NULL. So when the implementation type instance ("self") + is returned to the server, it will contain the actual aggregation + context in it. + Therefore, each of the ODCIAggregate routines has to check if the + aggregation context is in-line or out-of-line by checking the + "key" attribute. If it not NULL, than the key value is used to + access the externally stored context. If it is NULL, than external + memory is allocated and the context is copied from the aggCtx + attribute to the external memory, and the key identifying the external + memory is stored in the implementation type instance. This is done by + the GetExtAggCtx function. + + After retrieving the context, each of ODCIAggregate functions + calls the equivalent do_xxx function with the aggregation context + as the first argument (e.g. ODCIAggregateIterate calls do_iterate). + Therefore, the do_xxx functions only deal with actually implementing + the aggregation logic, using the aggregation context as a C struct, + without having to deal with the logic of retrieving the aggregation + context. + + The do_wrap and do_unwrap functions translate the aggregation context + from its OCI representation to a user-defined C representation. + In this example, the OCI representation of the aggregation context + is AggCtx_t, which represents the context as a x-y coordinate + stored as Oracle numbers (OCINumber). The C representation is + ExtAggCtx_t, which represents the context as x-y coordinate stored + as C doubles. If the context doesn't have to be transferred between + slaves, the context will always be stored externally as a user-defined C + struct (in extproc's memory), so these functions will not be called. + + All the other do_xxx (do_init, do_iterate, do_terminate, do_merge + and do_delete) only deal with context in its external format + (ExtAggCtx_t) which makes it simpler and faster to do the aggregation. + + MODIFIED (MM/DD/YY) + ayoaz 02/08/01 - Merged ayoaz_udag_demo + ayoaz 02/06/01 - Creation + +*/ + +#include "extdemo4.h" +#include + +/*------------------------------------------------------------------------ + PRIVATE TYPES AND CONSTANTS + ----------------------------------------------------------------------*/ + +/* The external context (stored in extproc's process memory) */ + +struct ExtAggCtx_t +{ + double x; + double y; +}; +typedef struct ExtAggCtx_t ExtAggCtx_t; + +/*-----------------------------------------------------------------------*/ + +/* OCI Handles */ + +struct Handles_t +{ + OCIExtProcContext* extProcCtx; + OCIEnv* envhp; + OCISvcCtx* svchp; + OCIError* errhp; + OCISession* usrhp; +}; +typedef struct Handles_t Handles_t; + +/*------------------------------------------------------------------------- + PRIVATE FUNCTIONS PROTOTYPES + -----------------------------------------------------------------------*/ + +static int GetHandles(OCIExtProcContext* extProcCtx, Handles_t* handles); + +/* + NAME: + GetHandles - get the various OCI handles + PARAMETERS: + extProcCtx (IN) - external procedure context + handles (OUT) - struct which contains the OCI handles + DESCRIPTION: + This function retrieves the OCI environment, service, error and + user handles using the external procedure context, and returns + then via the handles parameter. + RETURN: + Zero on success, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static ExtAggCtx_t* GetExtAggCtx(Handles_t* handles, + Imp_t* self, Imp_Ind_t* self_ind); + +/* + NAME: + GetExtAggCtx - retrieve the external context + PARAMETERS: + handles (IN) - OCI handles + self (IN) - pointer to the self (implementation type instance) + self_ind (IN) - indicator struct for self + DESCRIPTION: + This function returns a pointer to the external representation + of the context, by retrieving it using the key attribute in self, + or allocating the external context and "unwrapping" the aggCtx within + the self into the external context. + RETURN: + Pointer to external context, or NULL in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int ChkErr(Handles_t* handles, sword status); + +/* + NAME: + ChkErr - check the error code, and register exception if neccessary + PARAMETERS: + handles (IN) - OCI handles + sword (IN) - error code + DESCRIPTION: + This function checks the input error code, and if it indicates + an OCI error, it registers an exception with the appropriate message. + RETURN: + Zero if there was no error, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int do_init(Handles_t* handles, ExtAggCtx_t* extAggCtx); +/* + NAME: + do_init - initialize the aggregation context + PARAMETERS: + handles (IN) - OCI handles + extAggCtx (OUT) - aggregation context + DESCRIPTION: + This function initializes the contents of the aggregation context, + to the (0,0) coordinates. + RETURN: + Zero on success, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int do_iterate(Handles_t* handles, ExtAggCtx_t* extAggCtx, + Vector_t* arg, Vector_Ind_t* arg_ind); +/* + NAME: + do_iterate - update the aggregation context with a new value + PARAMETERS: + handles (IN) - OCI handles + extAggCtx (IN/OUT) - aggregation context + arg (IN) - the vector to add + arg_ind (IN) - the vector's indicator struct + DESCRIPTION: + This function updates the aggregation context according by adding + the vector to the current coordinates in the aggregation context. + RETURN: + Zero on success, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int do_terminate(Handles_t* handles, ExtAggCtx_t* extAggCtx, + Vector_t* result, Vector_Ind_t* result_ind); +/* + NAME: + do_terminate - calculate aggregation result + PARAMETERS: + handles (IN) - OCI handles + extAggCtx (IN) - aggregation context + result (OUT) - the result vector + result_ind (OUT) - the result vector indicator struct + DESCRIPTION: + This function returns the sum as a vector, by translating the + current coordinates in the aggregation context into a vector. + RETURN: + Zero on success, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int do_merge(Handles_t* handles, ExtAggCtx_t* extAggCtx, + ExtAggCtx_t* extAggCtx2); +/* + NAME: + do_merge - merge two aggregation contexts + PARAMETERS: + handles (IN) - OCI handles + extAggCtx (IN/OUT) - aggregation context + extAggCtx2 (IN) - second aggregation context + DESCRIPTION: + Add the coordinates of the second context into the current context. + RETURN: + Zero on success, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int do_delete(Handles_t* handles, ExtAggCtx_t* extAggCtx, + Vector_t* arg, Vector_Ind_t* arg_ind); +/* + NAME: + do_delete - update the aggregation context by removing a value + PARAMETERS: + handles (IN) - OCI handles + extAggCtx (IN/OUT) - aggregation context + arg (IN) - the vector to subtract + arg_ind (IN) - the vector's indicator struct + DESCRIPTION: + This function updates the aggregation context according by subtracting + the vector from the coordinates in the aggregation context. + RETURN: + Zero on success, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int do_wrap(Handles_t* handles, ExtAggCtx_t* extAggCtx, + AggCtx_t* aggCtx, AggCtx_Ind_t* aggCtx_ind); +/* + NAME: + do_wrap - translate the external context into an OCI aggr. context. + PARAMETERS: + handles (IN) - OCI handles + extAggCtx (IN) - aggregation context (external) + aggCtx (OUT) - embedded OCI aggregation context + aggCtx_ind (OUT) - indicator of the embedded OCI aggregation context + DESCRIPTION: + This function translates the external context into the OCI aggregation + context (which is embedded in the implementation type instance). + RETURN: + Zero on success, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int do_unwrap(Handles_t* handles, ExtAggCtx_t* extAggCtx, + AggCtx_t* aggCtx, AggCtx_Ind_t* aggCtx_ind); +/* + NAME: + do_unwrap - translate the OCI aggregation context into external context + PARAMETERS: + handles (IN) - OCI handles + extAggCtx (OUT) - aggregation context (external) + aggCtx (IN) - embedded OCI aggregation context + aggCtx_ind (IN) - indicator of the embedded OCI aggregation context + DESCRIPTION: + This function translates the OCI aggregation context into the + an external context. + RETURN: + Zero on success, -1 in case of error. +*/ + +/*------------------------------------------------------------------------- + PUBLIC FUNCTIONS + -----------------------------------------------------------------------*/ + +/* ODCIAggregateInitialize function */ + +int Initialize(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind) +{ + Handles_t handles; + ExtAggCtx_t* extAggCtx; + ub4 key; + + /* Get OCI handles */ + if (GetHandles(extProcCtx, &handles)) + return ODCI_ERROR; + + /* Set up self */ + if (self_ind->_atomic==OCI_IND_NULL) + { + self_ind->_atomic = OCI_IND_NOTNULL; + self_ind->key = OCI_IND_NULL; + self_ind->aggCtx._atomic = OCI_IND_NULL; + } + + /* Get context */ + extAggCtx=GetExtAggCtx(&handles,self,self_ind); + if (!extAggCtx) return ODCI_ERROR; + + /* Initialize context */ + if (do_init(&handles, extAggCtx)) + return ODCI_ERROR; + + return ODCI_SUCCESS; +} + +/*-----------------------------------------------------------------------*/ + +/* ODCIAggregateIterate function */ + +int Iterate(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Vector_t* arg, Vector_Ind_t* arg_ind) +{ + Handles_t handles; + ExtAggCtx_t* extAggCtx; + + /* Get OCI handles */ + if (GetHandles(extProcCtx, &handles)) + return ODCI_ERROR; + + /* Get context */ + extAggCtx=GetExtAggCtx(&handles,self,self_ind); + if (!extAggCtx) return ODCI_ERROR; + + if (do_iterate(&handles,extAggCtx,arg,arg_ind)) + return ODCI_ERROR; + + return ODCI_SUCCESS; +} + +/*-----------------------------------------------------------------------*/ + +/* ODCIAgregateTerminate */ + +int Terminate(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Vector_t* result, Vector_Ind_t* result_ind, + OCINumber* flags, OCIInd flags_ind) +{ + Handles_t handles; + ExtAggCtx_t* extAggCtx; + int flags_val=0; + + /* Get OCI handles */ + if (GetHandles(extProcCtx, &handles)) + return ODCI_ERROR; + + /* Get context */ + extAggCtx=GetExtAggCtx(&handles,self,self_ind); + if (!extAggCtx) return ODCI_ERROR; + + if (do_terminate(&handles,extAggCtx,result,result_ind)) + return ODCI_ERROR; + + /* get the flags parameter velue */ + if (flags_ind==OCI_IND_NOTNULL) + { + if (ChkErr(&handles, OCINumberToInt(handles.errhp, flags, + sizeof(flags_val), OCI_NUMBER_SIGNED, + &flags_val))) + return ODCI_ERROR; + } + + /* Free external context memory (unless ODCI_AGGREGATE_REUSE_CTX is set) */ + if ((flags_val && ODCI_AGGREGATE_REUSE_CTX)==0) + { + if (ChkErr(&handles, OCIMemoryFree((dvoid*)handles.usrhp, + handles.errhp, (dvoid*) extAggCtx))) + return ODCI_ERROR; + + self_ind->key=OCI_IND_NULL; + } + + return ODCI_SUCCESS; +} + +/*-----------------------------------------------------------------------*/ + +/* ODCIAggregateMerge */ + +int Merge(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Imp_t* sctx2, Imp_Ind_t* sctx2_ind) +{ + Handles_t handles; + ExtAggCtx_t* extAggCtx; + ExtAggCtx_t* extAggCtx2; + + /* Get OCI handles */ + if (GetHandles(extProcCtx, &handles)) + return ODCI_ERROR; + + /* Get 1st external context */ + extAggCtx=GetExtAggCtx(&handles,self,self_ind); + if (!extAggCtx) return ODCI_ERROR; + + /* Get 2nd external context */ + extAggCtx2=GetExtAggCtx(&handles,sctx2,sctx2_ind); + if (!extAggCtx2) return ODCI_ERROR; + + if (do_merge(&handles,extAggCtx,extAggCtx2)) + return ODCI_ERROR; + + /* Free the 2nd external context memory */ + if (sctx2_ind->key == OCI_IND_NOTNULL) + { + if (ChkErr(&handles, OCIMemoryFree((dvoid *)handles.usrhp, + handles.errhp, (dvoid *)extAggCtx2))) + return ODCI_ERROR; + } + + return ODCI_SUCCESS; +} + +/*-----------------------------------------------------------------------*/ + +/* ODCIAggregateDelete function */ + +int Delete(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Vector_t* arg, Vector_Ind_t* arg_ind) +{ + Handles_t handles; + ExtAggCtx_t* extAggCtx; + + /* Get OCI handles */ + if (GetHandles(extProcCtx, &handles)) + return ODCI_ERROR; + + /* Get context */ + extAggCtx=GetExtAggCtx(&handles,self,self_ind); + if (!extAggCtx) return ODCI_ERROR; + + if (do_delete(&handles,extAggCtx,arg,arg_ind)) + return ODCI_ERROR; + + return ODCI_SUCCESS; +} + +/*-----------------------------------------------------------------------*/ + +/* ODCIAgregateWrapContext */ + +int WrapContext(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind) +{ + Handles_t handles; + ExtAggCtx_t* extAggCtx; + + /* Get OCI handles */ + if (GetHandles(extProcCtx, &handles)) + return ODCI_ERROR; + + /* nothing to do if no external context */ + if (self_ind->key==OCI_IND_NULL) + return ODCI_SUCCESS; + + /* Get context */ + extAggCtx=GetExtAggCtx(&handles,self,self_ind); + if (!extAggCtx) return ODCI_ERROR; + + if (do_wrap(&handles,extAggCtx,&self->aggCtx,&self_ind->aggCtx)) + return ODCI_ERROR; + + /* Free external context memory */ + if (ChkErr(&handles, OCIMemoryFree((dvoid*)handles.usrhp, + handles.errhp, (dvoid*) extAggCtx))) + return ODCI_ERROR; + + self_ind->key=OCI_IND_NULL; + + return ODCI_SUCCESS; +} + +/*------------------------------------------------------------------------- + PRIVATE FUNCTIONS + -----------------------------------------------------------------------*/ + +static int do_init(Handles_t* handles, ExtAggCtx_t* extAggCtx) +{ + /* Initialize context */ + extAggCtx->x=0.0; + extAggCtx->y=0.0; + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static int do_iterate(Handles_t* handles, ExtAggCtx_t* extAggCtx, + Vector_t* arg, Vector_Ind_t* arg_ind) +{ + double length=0.0; + double angle=0.0; + + /* get the input value */ + if (arg_ind->length==OCI_IND_NOTNULL) + { + if (ChkErr(handles, OCINumberToReal(handles->errhp, &arg->length, + sizeof(length), (dvoid*) &length))) + return(-1); + + } + + if (arg_ind->angle==OCI_IND_NOTNULL) + { + if (ChkErr(handles, OCINumberToReal(handles->errhp, &arg->angle, + sizeof(angle), (dvoid*) &angle))) + return(-1); + + } + + /* update the context by adding the equivalent vector coordinates */ + extAggCtx->x+=length*cos(angle); + extAggCtx->y+=length*sin(angle); + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static int do_terminate(Handles_t* handles, ExtAggCtx_t* extAggCtx, + Vector_t* result, Vector_Ind_t* result_ind) +{ + double length=0.0; + double angle=0.0; + + /* calculate the length and angle using the coordinates in context */ + + if (extAggCtx->x!=0 || extAggCtx->y!=0) + length=sqrt(extAggCtx->x*extAggCtx->x+extAggCtx->y*extAggCtx->y); + + if (extAggCtx->x!=0) + angle=atan(extAggCtx->y/extAggCtx->x); + + /* assign the length and angle to the result vector */ + if (ChkErr(handles, OCINumberFromReal(handles->errhp, &length, + sizeof(length), &result->length))) + return -1; + + result_ind->length=OCI_IND_NOTNULL; + + if (ChkErr(handles, OCINumberFromReal(handles->errhp, &angle, + sizeof(angle), &result->angle))) + return -1; + + result_ind->angle=OCI_IND_NOTNULL; + + result_ind->_atomic=OCI_IND_NOTNULL; + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static int do_merge(Handles_t* handles, ExtAggCtx_t* extAggCtx, + ExtAggCtx_t* extAggCtx2) +{ + /* add the other context coordiantes to the current coordinates */ + extAggCtx->x+=extAggCtx2->x; + extAggCtx->y+=extAggCtx2->y; + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static int do_delete(Handles_t* handles, ExtAggCtx_t* extAggCtx, + Vector_t* arg, Vector_Ind_t* arg_ind) +{ + double length=0.0; + double angle=0.0; + + /* get the input value */ + if (arg_ind->length==OCI_IND_NOTNULL) + { + if (ChkErr(handles, OCINumberToReal(handles->errhp, &arg->length, + sizeof(length), (dvoid*) &length))) + return(-1); + + } + + if (arg_ind->angle==OCI_IND_NOTNULL) + { + if (ChkErr(handles, OCINumberToReal(handles->errhp, &arg->angle, + sizeof(angle), (dvoid*) &angle))) + return(-1); + + } + + /* update the context by subtracting the equivalent vector coordinates */ + extAggCtx->x-=length*cos(angle); + extAggCtx->y-=length*sin(angle); + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static int do_wrap(Handles_t* handles, ExtAggCtx_t* extAggCtx, + AggCtx_t* aggCtx, AggCtx_Ind_t* aggCtx_ind) +{ + /* transfer the external context's coordinates to the embedded context */ + + if (ChkErr(handles, OCINumberFromReal(handles->errhp, &extAggCtx->x, + sizeof(extAggCtx->x), &aggCtx->x))) + return -1; + + aggCtx_ind->x = OCI_IND_NOTNULL; + + if (ChkErr(handles, OCINumberFromReal(handles->errhp, &extAggCtx->y, + sizeof(extAggCtx->y), &aggCtx->y))) + return -1; + + aggCtx_ind->y = OCI_IND_NOTNULL; + + aggCtx_ind->_atomic = OCI_IND_NOTNULL; + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static int do_unwrap(Handles_t* handles, ExtAggCtx_t* extAggCtx, + AggCtx_t* aggCtx, AggCtx_Ind_t* aggCtx_ind) +{ + extAggCtx->x=0.0; + extAggCtx->y=0.0; + + /* get the coordinates from the embedded context and store them + in the external context */ + + if (aggCtx_ind->x==OCI_IND_NOTNULL) + { + if (ChkErr(handles, OCINumberToReal(handles->errhp, &aggCtx->x, + sizeof(extAggCtx->x), &extAggCtx->x))) + return -1; + } + + if (aggCtx_ind->x==OCI_IND_NOTNULL) + { + if (ChkErr(handles, OCINumberToReal(handles->errhp, &aggCtx->y, + sizeof(extAggCtx->y), &extAggCtx->y))) + return -1; + } + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static ExtAggCtx_t* GetExtAggCtx(Handles_t* handles, Imp_t* self, + Imp_Ind_t* self_ind) +{ + ExtAggCtx_t* extCtx; /* The real context */ + + if (self_ind->key==OCI_IND_NOTNULL) + { + /* the key is not null, so we'll use it to get + the address of external context */ + + ub1* key; /* key to retrieve context */ + ub4 keylen; /* length of key */ + + /* Get the key */ + key = OCIRawPtr(handles->envhp, self->key); + keylen = OCIRawSize(handles->envhp, self->key); + + /* Retrieve context from key */ + if (ChkErr(handles, OCIContextGetValue((dvoid *)handles->usrhp, + handles->errhp, key, (ub1)keylen, + (dvoid**) &extCtx))) + return NULL; + } + else + { + /* the key attribute was NULL, so we will allocate memory for + the external context */ + + ub4 key; + + /* Allocate memory to hold external scan context */ + if (ChkErr(handles, OCIMemoryAlloc((dvoid *)handles->usrhp, + handles->errhp, (dvoid **)&extCtx, + OCI_DURATION_STATEMENT, + (ub4)(sizeof(ExtAggCtx_t)), OCI_MEMORY_CLEARED))) + return NULL; + + /* generate a key */ + if (ChkErr(handles, OCIContextGenerateKey((dvoid *)handles->usrhp, + handles->errhp, &key))) + return NULL; + + /* set the memory address of the struct to be saved in the context */ + if (ChkErr(handles, OCIContextSetValue((dvoid *)handles->usrhp, + handles->errhp, OCI_DURATION_STATEMENT, + (ub1 *)&key, (ub1)sizeof(key), (dvoid*) extCtx))) + return NULL; + + /* store the key in self */ + if (ChkErr(handles, OCIRawAssignBytes(handles->envhp, handles->errhp, + (ub1 *)&key, (ub4)sizeof(key), &(self->key)))) + return NULL; + + self_ind->key = OCI_IND_NOTNULL; + + /* if the embedded context is not null, use it to initialize the + external context (unwrap) */ + + if (self_ind->aggCtx._atomic==OCI_IND_NOTNULL) + { + /* unwrap - create external context from embedded context */ + if (do_unwrap(handles,extCtx,&self->aggCtx,&self_ind->aggCtx)) + return NULL; + + /* set the embedded context to NULL */ + self_ind->aggCtx._atomic = OCI_IND_NULL; + + } + + } + + return extCtx; +} + +/*-----------------------------------------------------------------------*/ + +static int GetHandles(OCIExtProcContext* extProcCtx, Handles_t* handles) +{ + handles->extProcCtx=extProcCtx; + + /* Get OCI env, error and service handles */ + if (ChkErr(handles, OCIExtProcGetEnv(extProcCtx, &handles->envhp, + &handles->svchp, &handles->errhp))) + return -1; + + /* get the user handle */ + if (ChkErr(handles, OCIAttrGet((dvoid *)handles->svchp, + (ub4)OCI_HTYPE_SVCCTX, (dvoid *)&handles->usrhp, + (ub4 *)0, (ub4)OCI_ATTR_SESSION, handles->errhp))) + return -1; + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static int ChkErr(Handles_t* handles, sword status) +{ + text errbuf[512]; + sb4 errcode; + + /* check the error code */ + switch (status) + { + case OCI_SUCCESS: + case OCI_SUCCESS_WITH_INFO: + return 0; + case OCI_ERROR: + OCIErrorGet ((dvoid *) handles->errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + sprintf((char*)errbuf, "OCI ERROR code %d",errcode); + break; + default: + sprintf((char*)errbuf, "Warning - error status %d",status); + break; + } + + /* register exception */ + OCIExtProcRaiseExcpWithMsg(handles->extProcCtx, 29400, errbuf, + strlen((char*)errbuf)); + return 1; +} + +/* end of file extdemo4.c */ + diff --git a/extdemo4.h b/extdemo4.h new file mode 100644 index 0000000..316bfe6 --- /dev/null +++ b/extdemo4.h @@ -0,0 +1,127 @@ +/* + * $Header: extdemo4.h 08-feb-2001.18:14:55 ayoaz Exp $ + */ + +/* Copyright (c) Oracle Corporation 1998, 2000. All Rights Reserved. */ + +/* + NAME + extdemo4.h - user defined aggregates using C safe callouts + with external aggregation context + + DESCRIPTION + This file contains the OCI declarations of the SQL types used + by the SumVector aggregate function. + + MODIFIED (MM/DD/YY) + ayoaz 02/08/01 - Merged ayoaz_udag_demo + ayoaz 02/06/01 - Creation + +*/ + +#ifndef EXTDEMO4_ORACLE +#define EXTDEMO4_ORACLE + +#ifndef OCI_ORACLE +# include +#endif +#ifndef ODCI_ORACLE +# include +#endif + +/*------------------------------------------------------------------------- + OCI REPRESENTATION OF SQL TYPES + -----------------------------------------------------------------------*/ + +/* Vector_t - this is the OCI representation of the Vector_t SQL type */ + +struct Vector_t +{ + OCINumber length; + OCINumber angle; +}; +typedef struct Vector_t Vector_t; + +/* Indicator struct for Vector_t type */ + +struct Vector_Ind_t +{ + OCIInd _atomic; + OCIInd length; + OCIInd angle; +}; +typedef struct Vector_Ind_t Vector_Ind_t; + +/* AggCtx_t - OCI representation of the AggCtx_t SQL type */ + +struct AggCtx_t +{ + OCINumber x; + OCINumber y; +}; +typedef struct AggCtx_t AggCtx_t; + +/* Indicator struct for AggCtx_t */ + +struct AggCtx_Ind_t +{ + OCIInd _atomic; + OCIInd x; + OCIInd y; +}; +typedef struct AggCtx_Ind_t AggCtx_Ind_t; + +/* Imp_t - OCI representation of the Imp_t SQL type */ + +struct Imp_t +{ + OCIRaw* key; /* a key identifying the external context (null if none) */ + AggCtx_t aggCtx; /* the aggregation context (null if context is external */ +}; +typedef struct Imp_t Imp_t; + +/* Indicator struct for Imp_t */ + +struct Imp_Ind_t +{ + OCIInd _atomic; + OCIInd key; + AggCtx_Ind_t aggCtx; +}; +typedef struct Imp_Ind_t Imp_Ind_t; + +/*------------------------------------------------------------------------ + PUBLIC FUNCTIONS + ----------------------------------------------------------------------*/ + +/* C implementation of ODCIAgregateInitialize */ +int Initialize(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind); + +/* C implementation of ODCIAgregateIterate */ +int Iterate(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Vector_t* arg, Vector_Ind_t* arg_ind); + +/* C implementation of ODCIAgregateTerminate */ +int Terminate(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Vector_t* result, Vector_Ind_t* result_ind, + OCINumber* flags, OCIInd flags_ind); + +/* C implementation of ODCIAggregateMerge */ +int Merge(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Imp_t* sctx2, Imp_Ind_t* sctx2_ind); + +/* C implementation of ODCIAgregateDelete */ +int Delete(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Vector_t* arg, Vector_Ind_t* arg_ind); + +/* C implementation of ODCIAgregateWrapContext */ +int WrapContext(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind); + +#endif + diff --git a/extdemo4.sql b/extdemo4.sql new file mode 100644 index 0000000..460704a --- /dev/null +++ b/extdemo4.sql @@ -0,0 +1,206 @@ +Rem +Rem $Header: extdemo4.sql 08-feb-2001.18:14:55 ayoaz Exp $ +Rem +Rem extdemo4.sql +Rem +Rem Copyright (c) Oracle Corporation 1998, 2000. All Rights Reserved. +Rem +Rem NAME +Rem extdemo4.sql - user defined aggregate implemented using C functions. +Rem +Rem DESCRIPTION +Rem This file demonstrates the creation and use of a simple user +Rem defined aggregate function called SumVector, which calculates +Rem the sum of a set of vectors. +Rem +Rem The following steps should be taken before running this script: +Rem +Rem 1. Create the shared library extdemo4.so: +Rem +Rem make extproc_with_context SHARED_LIBNAME=extdemo4.so OBJS="extdemo4.o" +Rem +Rem 2. Change the CREATE LIBRARY command in this script to reflect +Rem the path of the shared library created in step 1. +Rem For example: +Rem +Rem CREATE LIBRARY VectorLib is '/oracle_home/rdbms/demo/extdemo4.so'; +Rem / +Rem +Rem MODIFIED (MM/DD/YY) +Rem ayoaz 02/08/01 - Merged ayoaz_udag_demo +Rem ayoaz 02/06/01 - Created +Rem + +SET FEEDBACK 1 +SET ECHO ON + +CONNECT system/manager +DROP USER extdemo4 CASCADE; +GRANT RESOURCE, CONNECT TO extdemo4 IDENTIFIED BY extdemo4; +GRANT CREATE TYPE TO extdemo4; +GRANT CREATE PROCEDURE TO extdemo4; +GRANT CREATE TABLE TO extdemo4; +GRANT CREATE LIBRARY TO extdemo4; + +CONNECT extdemo4/extdemo4 + +CREATE LIBRARY VectorLib is '/ade/ayoaz_ade0/oracle/rdbms/demo/extdemo4.so'; +/ + +-- Vector type + +CREATE TYPE Vector_t AS OBJECT ( + length NUMBER, + angle NUMBER, + MAP MEMBER FUNCTION GetLength RETURN NUMBER +); +/ + +CREATE TYPE BODY Vector_t IS + MAP MEMBER FUNCTION GetLength RETURN NUMBER IS + BEGIN + RETURN length; + END; +END; +/ + +-- Create the context type + +CREATE TYPE AggCtx_t AS OBJECT ( + x NUMBER, + y NUMBER +); +/ + +-- Create the implementation type + +CREATE TYPE Imp_t AS OBJECT +( + key RAW(4), + aggCtx aggCtx_t, + + STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT Imp_t) + RETURN PLS_INTEGER + AS LANGUAGE C + LIBRARY VectorLib + NAME "Initialize" + WITH CONTEXT + PARAMETERS ( + CONTEXT, + sctx, + sctx INDICATOR STRUCT, + RETURN INT + ), + + MEMBER FUNCTION ODCIAggregateIterate(self IN OUT Imp_t, arg IN Vector_t) + RETURN PLS_INTEGER + AS LANGUAGE C + LIBRARY VectorLib + NAME "Iterate" + WITH CONTEXT + PARAMETERS ( + CONTEXT, + self, + self INDICATOR STRUCT, + arg, + arg INDICATOR STRUCT, + RETURN INT + ), + + MEMBER FUNCTION ODCIAggregateTerminate(self IN Imp_t, result OUT Vector_t, + flags IN NUMBER) RETURN PLS_INTEGER + AS LANGUAGE C + LIBRARY VectorLib + NAME "Terminate" + WITH CONTEXT + PARAMETERS ( + CONTEXT, + self, + self INDICATOR STRUCT, + result, + result INDICATOR STRUCT, + flags, + flags INDICATOR, + RETURN INT + ), + + MEMBER FUNCTION ODCIAggregateMerge(self IN OUT Imp_t, sctx2 IN Imp_t) + RETURN PLS_INTEGER + AS LANGUAGE C + LIBRARY VectorLib + NAME "Merge" + WITH CONTEXT + PARAMETERS ( + CONTEXT, + self, + self INDICATOR STRUCT, + sctx2, + sctx2 INDICATOR STRUCT, + RETURN INT + ), + + member function ODCIAggregateDelete(self IN OUT Imp_t, arg IN Vector_t) + RETURN PLS_INTEGER + AS LANGUAGE C + LIBRARY VectorLib + NAME "Delete" + WITH CONTEXT + PARAMETERS ( + CONTEXT, + self, + self INDICATOR STRUCT, + arg, + arg INDICATOR STRUCT, + RETURN INT + ), + + MEMBER FUNCTION ODCIAggregateWrapContext(self IN OUT Imp_t) + RETURN PLS_INTEGER + AS LANGUAGE C + LIBRARY VectorLib + NAME "WrapContext" + WITH CONTEXT + PARAMETERS ( + CONTEXT, + self, + self INDICATOR STRUCT, + RETURN INT + ) + +); +/ + +-- Create user aggregate function + +CREATE FUNCTION SumVector(arg Vector_t) RETURN Vector_t +PARALLEL_ENABLE AGGREGATE USING Imp_t; +/ + +-- Create sample data + +CREATE TABLE t1 (c1 NUMBER, c2 Vector_t); +INSERT INTO T1 VALUES(1, Vector_t(5,0)); +INSERT INTO T1 VALUES(1, Vector_t(3,0)); +INSERT INTO T1 VALUES(2, Vector_t(1,2)); +INSERT INTO T1 VALUES(2, Vector_t(2,1)); +INSERT INTO T1 VALUES(2, Vector_t(3,0.5)); +INSERT INTO T1 VALUES(2, Vector_t(3,2.5)); + +CREATE TABLE t2 PARALLEL 2 AS SELECT * FROM t1; + +COMMIT; + +-- Sample queries + +-- serial cases +SELECT SumVector(c2) sum FROM t1; +SELECT SumVector(DISTINCT c2) sum FROM t1; +SELECT c1, SumVector(c2) sum FROM t1 GROUP BY c1 ORDER BY c1; +SELECT c1, SumVector(distinct c2) sum FROM t1 GROUP BY c1 ORDER BY c1; + +-- parallel cases +SELECT SumVector(c2) sum FROM t2; +SELECT SumVector(DISTINCT c2) sum FROM t2; +SELECT c1, SumVector(c2) sum FROM t2 GROUP BY c1 ORDER BY c1; +SELECT c1, SumVector(distinct c2) sum FROM t2 GROUP BY c1 ORDER BY c1; + diff --git a/extdemo5.c b/extdemo5.c new file mode 100644 index 0000000..c9a0d84 --- /dev/null +++ b/extdemo5.c @@ -0,0 +1,824 @@ +#ifdef RCSID +static char *RCSid = + "$Header: extdemo5.c 05-apr-2005.06:32:29 yhu Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 2001, 2005, Oracle. All rights reserved. +*/ + +/* + + NAME + extdemo5.c - Extensible Indexing example implemented as C routines + for local domain index on varchar2 column of + a range partitioned table. + + DESCRIPTION + This file contains the definitions of the DML and Query routines + for the extensible indexing example that implements a simple btree + (sbtree). See extdemo5.sql for the SQL script that defines the + indextype. + + PUBLIC FUNCTION(S) + qxiqtbps - QXIQT Btree Start routine + qxiqtbpf - QXIQT Btree Fetch routine + qxiqtbpc - QXIQT Btree Close routine + qxiqtbpi - QXIQT Btree Insert routine + qxiqtbpd - QXIQT Btree Delete routine + qxiqtbpu - QXIQT Btree Update routine + + PRIVATE FUNCTION(S) + qxiqtbe - QXIQT error reporting routine + + NOTES + + + MODIFIED (MM/DD/YY) + yhu 04/04/05 - #4184410: fix porting exceptions in HP VMS + hdnguyen 04/27/01 - misc. modification + spsundar 04/25/01 - Creation + +*/ + +#ifndef EXTDEMO5_ORACLE +# include "extdemo5.h" +#endif +#include +#include + +/*--------------------------------------------------------------------------- + TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ + +/* ODCIIndexInsert function */ +OCINumber *qxiqtbpi(ctx, ix, ix_ind, rid, rid_ind, + newval, newval_ind, env, env_ind) +OCIExtProcContext *ctx; +ODCIIndexInfo *ix; +ODCIIndexInfo_ind *ix_ind; +char *rid; +short rid_ind; +char *newval; +short newval_ind; +ODCIEnv *env; +ODCIEnv_ind *env_ind; +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + + char insstmt[2000]; /* sql insert statement */ + + /* allocate memory for OCINumber first */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct insert Statement * + ******************************/ + if (ix_ind->IndexPartition == OCI_IND_NULL) + (void)sprintf(insstmt, + "INSERT into %s.%s_sbtree values (:newval, :mrid)", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + else + (void)sprintf(insstmt, + "INSERT into %s.%s_%s_sbtree values (:newval, :mrid)", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, ix->IndexPartition)); + + + /**************************************** + * Parse and Execute Create Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, + (text *)insstmt, + (ub4)strlen(insstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + /* Set up bind for newval */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)1, + (dvoid *)newval, + (sb4)(strlen(newval)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)2, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /* free stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + return(rval); +} + +/* ODCIIndexDelete function */ +OCINumber *qxiqtbpd(ctx, ix, ix_ind, rid, rid_ind, + oldval, oldval_ind, env, env_ind) +OCIExtProcContext *ctx; +ODCIIndexInfo *ix; +ODCIIndexInfo_ind *ix_ind; +char *rid; +short rid_ind; +char *oldval; +short oldval_ind; +ODCIEnv *env; +ODCIEnv_ind *env_ind; +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + + char delstmt[2000]; /* sql delete statement */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct delete Statement * + ******************************/ + if (ix_ind->IndexPartition == OCI_IND_NULL) + (void)sprintf(delstmt, + "DELETE FROM %s.%s_sbtree WHERE f2 = :rr", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + else + (void)sprintf(delstmt, + "DELETE FROM %s.%s_%s_sbtree WHERE f2 = :rr", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, ix->IndexPartition)); + + /**************************************** + * Parse and Execute delete Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, + (text *)delstmt, + (ub4)strlen(delstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)1, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /* free stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + return(rval); +} + +/* ODCIIndexUpdate function */ +OCINumber *qxiqtbpu(ctx, ix, ix_ind, rid, rid_ind, oldval, oldval_ind, + newval, newval_ind, env, env_ind) +OCIExtProcContext *ctx; +ODCIIndexInfo *ix; +ODCIIndexInfo_ind *ix_ind; +char *rid; +short rid_ind; +char *oldval; +short oldval_ind; +char *newval; +short newval_ind; +ODCIEnv *env; +ODCIEnv_ind *env_ind; +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + + char updstmt[2000]; /* sql upate statement */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct update Statement * + ******************************/ + if (ix_ind->IndexPartition == OCI_IND_NULL) + (void)sprintf(updstmt, + "UPDATE %s.%s_sbtree SET f1 = :newval WHERE f1 = :oldval", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + else + (void)sprintf(updstmt, + "UPDATE %s.%s_%s_sbtree SET f1 = :newval WHERE f1 = :oldval", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, ix->IndexPartition)); + + + /**************************************** + * Parse and Execute Create Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, + (text *)updstmt, + (ub4)strlen(updstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + /* Set up bind for newval */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)1, + (dvoid *)newval, + (sb4)(strlen(newval)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up bind for oldval */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)2, + (dvoid *)oldval, + (sb4)(strlen(oldval)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /* free stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + return(rval); +} + +/* ODCIIndexStart function */ +OCINumber *qxiqtbps(ctx, sctx, sctx_ind, ix, ix_ind, pr, pr_ind, + qy, qy_ind, strt, strt_ind, stop, stop_ind, + cmpval, cmpval_ind, env, env_ind) +OCIExtProcContext *ctx; +qxiqtim *sctx; +qxiqtin *sctx_ind; +ODCIIndexInfo *ix; +ODCIIndexInfo_ind *ix_ind; +ODCIPredInfo *pr; +ODCIPredInfo_ind *pr_ind; +ODCIQueryInfo *qy; +ODCIQueryInfo_ind *qy_ind; +OCINumber *strt; +short strt_ind; +OCINumber *stop; +short stop_ind; +char *cmpval; +short cmpval_ind; +ODCIEnv *env; +ODCIEnv_ind *env_ind; +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int strtval; /* start bound */ + int stopval; /* stop bound */ + + int errnum = 29400; /* choose some oracle error number */ + char errmsg[512]; /* error message buffer */ + size_t errmsglen; /* Length of error message */ + + char relop[3]; /* relational operator used in sql stmt */ + char selstmt[2000]; /* sql select statement */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + ub4 key; /* key value set in "sctx" */ + + ub1 *rkey; /* key to retrieve context */ + ub4 rkeylen; /* length of key */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, + errhp))) + return(rval); + + /**********************************************/ + /* Allocate memory to hold index scan context */ + /**********************************************/ + if (sctx_ind ->atomic_qxiqtin == OCI_IND_NULL || + sctx_ind ->scind_qxiqtin == OCI_IND_NULL) + { + if (qxiqtce(ctx, errhp, OCIMemoryAlloc((dvoid *)usrhp, errhp, + (dvoid **)&icx, + OCI_DURATION_STATEMENT, + (ub4)(sizeof(qxiqtcx)), + OCI_MEMORY_CLEARED))) + return(rval); + + icx->stmthp = (OCIStmt *)0; + icx->defnp = (OCIDefine *)0; + icx->bndp = (OCIBind *)0; + } + else + { + /*************************/ + /* Retrieve scan context */ + /*************************/ + rkey = OCIRawPtr(envhp, sctx->sctx_qxiqtim); + rkeylen = OCIRawSize(envhp, sctx->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + rkey, (ub1)rkeylen, + (dvoid **)&(icx)))) + return(rval); + } + + /***********************************/ + /* Check that the bounds are valid */ + /***********************************/ + /* convert from oci numbers to native numbers */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, strt, + sizeof(strtval), + OCI_NUMBER_SIGNED, + (dvoid *)&strtval))) + return(rval); + + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, stop, + sizeof(stopval), + OCI_NUMBER_SIGNED, + (dvoid *)&stopval))) + return(rval); + + /* verify that strtval/stopval are both either 0 or 1 */ + if (!(((strtval == 0) && (stopval == 0)) || + ((strtval == 1) && (stopval == 1)))) + { + strcpy(errmsg, (char *)"Incorrect predicate for sbtree operator"); + errmsglen = (size_t)strlen(errmsg); + if (OCIExtProcRaiseExcpWithMsg(ctx, errnum, (text *)errmsg, errmsglen) + != OCIEXTPROC_SUCCESS) + /* Use cartridge error services here */; + return(rval); + } + + /*********************************************/ + /* Generate the SQL statement to be executed */ + /*********************************************/ + if (memcmp((dvoid *)OCIStringPtr(envhp, pr->ObjectName), (dvoid *)"EQ", 2) + == 0) + if (strtval == 1) + strcpy(relop, (char *)"="); + else + strcpy(relop, (char *)"!="); + else if (memcmp((dvoid *)OCIStringPtr(envhp, pr->ObjectName), (dvoid *)"LT", + 2) == 0) + if (strtval == 1) + strcpy(relop, (char *)"<"); + else + strcpy(relop, (char *)">="); + else + if (strtval == 1) + strcpy(relop, (char *)">"); + else + strcpy(relop, (char *)"<="); + + if (ix_ind->IndexPartition == OCI_IND_NULL) + (void)sprintf(selstmt, "select f2 from %s.%s_sbtree where f1 %s :val", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), relop); + else + (void)sprintf(selstmt, "select f2 from %s.%s_%s_sbtree where f1 %s :val", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, ix->IndexPartition), relop); + + + /***********************************/ + /* Parse, bind, define and execute */ + /***********************************/ + if (sctx_ind ->atomic_qxiqtin == OCI_IND_NULL || + sctx_ind ->scind_qxiqtin == OCI_IND_NULL) + { + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&(icx->stmthp), + (ub4)OCI_HTYPE_STMT, + (size_t)0, (dvoid **)0))) + return(rval); + } + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(icx->stmthp, errhp, + (text *)selstmt, + (ub4)strlen(selstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + /* Set up bind */ + if (qxiqtce(ctx, errhp, OCIBindByPos(icx->stmthp, &(icx->bndp), + errhp, (ub4)1, + (dvoid *)cmpval, + (sb4)(strlen(cmpval)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up define */ + if (qxiqtce(ctx, errhp, OCIDefineByPos(icx->stmthp, &(icx->defnp), + errhp, (ub4)1, + (dvoid *)(icx->ridp), + (sb4) sizeof(icx->ridp), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)OCI_DEFAULT))) + return(rval); + + /* execute */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, icx->stmthp, + errhp, (ub4)0, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /************************************/ + /* Set index context to be returned */ + /************************************/ + if (sctx_ind ->atomic_qxiqtin == OCI_IND_NULL || + sctx_ind ->scind_qxiqtin == OCI_IND_NULL) + { + /* generate a key */ + if (qxiqtce(ctx, errhp, OCIContextGenerateKey((dvoid *)usrhp, + errhp, &key))) + return(rval); + + /* set the memory address of the struct to be saved in the context */ + if (qxiqtce(ctx, errhp, OCIContextSetValue((dvoid *)usrhp, errhp, + OCI_DURATION_STATEMENT, + (ub1 *)&key, + (ub1)sizeof(key), + (dvoid *)icx))) + return(rval); + + /* set the key as the member of "sctx" */ + if (qxiqtce(ctx, errhp, OCIRawAssignBytes(envhp, errhp, + (ub1 *)&key, + (ub4)sizeof(key), + &(sctx->sctx_qxiqtim)))) + return(rval); + + sctx_ind->atomic_qxiqtin = OCI_IND_NOTNULL; + sctx_ind->scind_qxiqtin = OCI_IND_NOTNULL; + + return(rval); + } + + return(rval); +} + +/* ODCIIndexFetch function */ +OCINumber *qxiqtbpf(ctx, self, self_ind, nrows, nrows_ind, + rids, rids_ind, env, env_ind) +OCIExtProcContext *ctx; +qxiqtim *self; +qxiqtin *self_ind; +OCINumber *nrows; +short nrows_ind; +OCIArray **rids; +short *rids_ind; +ODCIEnv *env; +ODCIEnv_ind *env_ind; +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int idx = 1; + int nrowsval; + + OCIArray *ridarrp = *rids; /* rowid collection */ + OCIString *ridstr = (OCIString *)0; + + int done = 0; + int retval = (int)ODCI_SUCCESS; + OCINumber *rval = (OCINumber *)0; + + ub1 *key; /* key to retrieve context */ + ub4 keylen; /* length of key */ + + /*******************/ + /* Get OCI handles */ + /*******************/ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, + OCINumberFromInt(errhp, (dvoid *)&retval, sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, errhp))) + return(rval); + + /********************************/ + /* Retrieve context from key */ + /********************************/ + key = OCIRawPtr(envhp, self->sctx_qxiqtim); + keylen = OCIRawSize(envhp, self->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + key, (ub1)keylen, + (dvoid **)&(icx)))) + return(rval); + + /* get value of nrows */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, nrows, + sizeof(nrowsval), + OCI_NUMBER_SIGNED, + (dvoid *)&nrowsval))) + return(rval); + + /****************/ + /* Fetch rowids */ + /****************/ + while (!done) + { + if (idx > nrowsval) + done = 1; + else + { + status = OCIStmtFetch(icx->stmthp, errhp, (ub4)1, (ub2) 0, + (ub4)OCI_DEFAULT); + if (status == OCI_NO_DATA) + { + short col_ind = OCI_IND_NULL; + /* have to create dummy oci string */ + OCIStringAssignText(envhp, errhp, (text *)"dummy", + (ub2)5, &ridstr); + /* append null element to collection */ + if (qxiqtce(ctx, errhp, OCICollAppend(envhp, errhp, + (dvoid *)ridstr, + (dvoid *)&col_ind, + (OCIColl *)ridarrp))) + return(rval); + done = 1; + } + else if (status == OCI_SUCCESS) + { + OCIStringAssignText(envhp, errhp, (text *)icx->ridp, + (ub2)18, (OCIString **)&ridstr); + /* append rowid to collection */ + if (qxiqtce(ctx, errhp, OCICollAppend(envhp, errhp, + (dvoid *)ridstr, + (dvoid *)0, + (OCIColl *)ridarrp))) + return(rval); + idx++; + } + else if (qxiqtce(ctx, errhp, status)) + return(rval); + } + } + + /* free ridstr finally */ + if (ridstr && + (qxiqtce(ctx, errhp, OCIStringResize(envhp, errhp, (ub4)0, + &ridstr)))) + return(rval); + + *rids_ind = OCI_IND_NOTNULL; + + return(rval); +} + + +/* ODCIIndexClose function */ +OCINumber *qxiqtbpc(ctx, self, self_ind, env, env_ind) +OCIExtProcContext *ctx; +qxiqtim *self; +qxiqtin *self_ind; +ODCIEnv *env; +ODCIEnv_ind *env_ind; +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int retval = (int) ODCI_SUCCESS; + OCINumber *rval = (OCINumber *)0; + + ub1 *key; /* key to retrieve context */ + ub4 keylen; /* length of key */ + + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, errhp))) + return(rval); + + /********************************/ + /* Retrieve context using key */ + /********************************/ + key = OCIRawPtr(envhp, self->sctx_qxiqtim); + keylen = OCIRawSize(envhp, self->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + key, (ub1)keylen, + (dvoid **)&(icx)))) + return(rval); + + /* Free handles and memory */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)icx->stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + if (qxiqtce(ctx, errhp, OCIMemoryFree((dvoid *)usrhp, errhp, (dvoid *)icx))) + return(rval); + + return(rval); +} + + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ +static int qxiqtce(ctx, errhp, status) +OCIExtProcContext *ctx; +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + int errnum = 29400; /* choose some oracle error number */ + int rc = 0; + + switch (status) + { + case OCI_SUCCESS: + rc = 0; + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4)1, (text *)NULL, &errcode, + errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR); + OCIExtProcRaiseExcpWithMsg(ctx, errnum, errbuf, strlen((char *)errbuf)); + rc = 1; + break; + default: + (void) sprintf((char *)errbuf, "Warning - some error\n"); + OCIExtProcRaiseExcpWithMsg(ctx, errnum, errbuf, strlen((char *)errbuf)); + rc = 1; + break; + } + return (rc); +} + +/* end of file extdemo5.c */ + diff --git a/extdemo5.h b/extdemo5.h new file mode 100644 index 0000000..e8fb980 --- /dev/null +++ b/extdemo5.h @@ -0,0 +1,173 @@ +/* + * $Header: extdemo5.h 30-apr-2001.16:05:04 hdnguyen Exp $ + */ + +/* Copyright (c) 2001, Oracle Corporation. All rights reserved. +*/ + +/* + NAME + extdemo5.h - Extensible Indexing example implemented as C routines + for local domain index on varchar2 column of a + range partitioned table. + + DESCRIPTION + This file contains the definitions of the DML and Query routines + for the extensible indexing example that implements a simple btree + (sbtree). See extdemo5.sql for the SQL script that defines the + indextype. + + RELATED DOCUMENTS + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + qxiqtbps - QXIQT Btree Start routine + qxiqtbpf - QXIQT Btree Fetch routine + qxiqtbpc - QXIQT Btree Close routine + qxiqtbpi - QXIQT Btree Insert routine + qxiqtbpd - QXIQT Btree Delete routine + qxiqtbpu - QXIQT Btree Update routine + + PRIVATE FUNCTION(S) + qxiqtbe - QXIQT error reporting routine + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + hdnguyen 04/27/99 - misc. modification + spsundar 04/25/01 - Creation + +*/ + + +#ifndef EXTDEMO5_ORACLE +# define EXTDEMO5_ORACLE + +#ifndef OCI_ORACLE +# include +#endif +#ifndef ODCI_ORACLE +# include +#endif + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +#ifdef WIN32COMMON +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + +/* index scan context - should be stored in "statement" duration memory + * and used by start, fetch and close routines. + */ +struct qxiqtcx +{ + OCIStmt *stmthp; + OCIDefine *defnp; + OCIBind *bndp; + char ridp[19]; +}; +typedef struct qxiqtcx qxiqtcx; + +/* The index implementation type is an ADT with a single RAW attribute + * which will be used to store the context key value. + * C mapping of the implementation type : + */ +struct qxiqtim +{ + OCIRaw *sctx_qxiqtim; +}; +typedef struct qxiqtim qxiqtim; + +struct qxiqtin +{ + short atomic_qxiqtin; + short scind_qxiqtin; +}; +typedef struct qxiqtin qxiqtin; + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ +/* ODCIIndexStart */ +OCINumber DLLEXPORT *qxiqtbps(/*_ OCIExtProcContext *ctx, + struct qxiqtim *sctx, struct qxiqtin *sctx_ind, + ODCIIndexInfo *ix, ODCIIndexInfo_ind *ix_ind, + ODCIPredInfo *pr, ODCIPredInfo_ind *pr_ind, + ODCIQueryInfo *qy, ODCIQueryInfo_ind *qy_ind, + OCINumber *strt, short strt_ind, + OCINumber *stop, short stop_ind, + char *cmpval, short cmpval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind _*/); + +/* ODCIIndexFetch */ +OCINumber DLLEXPORT *qxiqtbpf(/*_ OCIExtProcContext *ctx, + struct qxiqtim *self, struct qxiqtin *self_ind, + OCINumber *nrows, short nrows_ind, + OCIArray **rids, short *rids_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind _*/); + +/* ODCIIndexClose */ +OCINumber DLLEXPORT *qxiqtbpc(/*_ OCIExtProcContext *ctx, + struct qxiqtim *self, struct qxiqtin *self_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind _*/); + +/* ODCIIndexInsert */ +OCINumber DLLEXPORT *qxiqtbpi(/*_ OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *newval, + short newval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind _*/); + +/* ODCIIndexDelete */ +OCINumber DLLEXPORT *qxiqtbpd(/*_ OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *oldval, + short oldval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind _*/); + +/* ODCIIndexUpdate */ +OCINumber DLLEXPORT *qxiqtbpu(/*_ OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *oldval, + short oldval_ind, + char *newval, + short newval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind _*/); + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ +static int qxiqtce(/*_ OCIExtProcContext *ctx, OCIError *errhp, + sword status _*/); + +#endif /* EXTDEMO5_ORACLE */ diff --git a/extdemo5.sql b/extdemo5.sql new file mode 100644 index 0000000..7c38ab1 --- /dev/null +++ b/extdemo5.sql @@ -0,0 +1,768 @@ +rem +rem $Header: extdemo5.sql 30-apr-2001.16:05:05 hdnguyen Exp $ +rem +rem extdemo5.sql +rem +rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +rem +rem NAME +rem extdemo5.sql - An extensible indexing example implemented +rem as C routines for local domain index on +rem varchar2 column of a range partitioned table. +rem +rem DESCRIPTION +rem This file demonstrates the definition and usage of a simple +rem btree indextype whose routines are implemented as C callouts. +rem The C routines are in the file extdemo5.c +rem The header file is extdemo5.h +rem +rem The following steps should have been done before running +rem this script. +rem 1. Compile the C file (i.e make -f demo_rdbms.mk demos) +rem 2. Create a user named extdemo5 with password extdemo5 +rem with all the necessary privileges. +rem 3. Create a library in extdemo5 schema called extdemo5l +rem which points to the compiled extdemo5.c +rem +rem The design of the indextype is as follows : +rem +rem The sbtree indextype implemented here will support the evaluation +rem of three user-defined operators : gt(Greater Than), lt(Less Than) +rem and eq(EQuals). These operators can operate on the operands of +rem VARCHAR2 datatype. +rem To simplify the implementation of the indextype, we will store +rem the index data in a regular table. +rem Thus, our code merely translates operations on the SB-tree into +rem operations on the table storing the index data. +rem When a user creates a SB-tree index, we will create a table +rem consisting of the indexed column and a rowid column. Inserts into +rem the base table will cause appropriate insertions into the index table. +rem Deletes and updates are handled similarly. +rem When the SB-tree is queried based on a user-defined operator (one +rem of gt, lt and eq), we will fire off an appropriate query against +rem the index table to retrieve all the satisfying rows and return them. +rem +rem NOTE: +rem The database has to be at compatible = 9.0.0 or above +rem +rem MODIFIED (MM/DD/YY) +rem hdnguyen 04/30/01 - modified MergePartition. +rem hdnguyen 04/27/01 - misc. modification +rem spsundar 04/25/01 - Created + +--------------------------------------------------------------------- +-- SIMPLE B-TREE Index Method Implemented as C Callouts -- +--------------------------------------------------------------------- + +connect extdemo5/extdemo5 +set echo off +@'?/rdbms/admin/utlxplan.sql' +set echo on + +-- CREATE FUNCTIONAL IMPLEMENTATIONS for operators + +create function bt_eq(a varchar2, b varchar2) return number as +begin + if a = b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_lt(a varchar2, b varchar2) return number as +begin + if a < b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_gt(a varchar2, b varchar2) return number as +begin + if a > b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +-- CREATE BTREE OPERATORS + +create operator eq binding (varchar2, varchar2) + return number using bt_eq; + +create operator lt binding (varchar2, varchar2) + return number using bt_lt; + +create operator gt binding (varchar2, varchar2) + return number using bt_gt; + + +-- CREATE INDEXTYPE IMPLEMENTATION TYPE +create type psbtree_im as object +( + scanctx RAW(4), + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return NUMBER, + + static function ODCIIndexCreate (ia sys.ODCIIndexInfo, + parms varchar2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexDrop(ia sys.ODCIIndexInfo, + env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexInsert(ia sys.ODCIIndexInfo, rid VARCHAR2, + newval VARCHAR2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexDelete(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexUpdate(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, newval VARCHAR2, env sys.ODCIEnv) + return NUMBER, + + static function ODCIIndexTruncate(ia sys.ODCIIndexInfo, + env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexExchangePartition (ia sys.ODCIIndexInfo, + ia1 sys.ODCIIndexInfo, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexMergePartition (ia sys.ODCIIndexInfo, + part_name1 sys.ODCIPartInfo, part_name2 sys.ODCIPartInfo, + parms varchar2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexSplitPartition (ia sys.ODCIIndexInfo, + part_name1 sys.ODCIPartInfo, part_name2 sys.ODCIPartInfo, + parms varchar2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexStart(sctx IN OUT psbtree_im, + ia sys.ODCIIndexInfo, op sys.ODCIPredInfo, + qi sys.ODCIQueryInfo, strt number, stop number, + cmpval varchar2, env sys.ODCIEnv) + return NUMBER, + + member function ODCIIndexFetch(nrows number, + rids OUT sys.ODCIRidList, env sys.ODCIEnv) + return NUMBER, + + member function ODCIIndexClose(env sys.ODCIEnv) return NUMBER +); +/ +show errors + +--------------------------------- +-- CREATE IMPLEMENTATION UNIT -- +--------------------------------- + +-- CREATE TYPE BODY +create or replace type body psbtree_im +is + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return number is + begin + ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCIINDEX2')); + return ODCIConst.Success; + end ODCIGetInterfaces; + + static function ODCIIndexCreate (ia sys.ODCIIndexInfo, + parms varchar2, env sys.ODCIEnv) return number + is + i integer; + stmt varchar2(1000); + cnum integer; + junk integer; + begin + stmt := ''; + + if ((env.CallProperty is null) and (ia.IndexPartition is null )) then + stmt := 'create table ' ||ia.IndexSchema || '.' || ia.IndexName || + '_sbtree(f1, f2) as select ' || + ia.IndexCols(1).Colname || ', ROWID from ' || + ia.IndexCols(1).TableSchema || '.' || + ia.IndexCols(1).TableName; + end if; + + if ((env.CallProperty is not null) and (ia.IndexPartition is not null)) then + stmt := 'create table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || ia.IndexPartition || '_sbtree' || + '(f1, f2) as select ' || + ia.IndexCols(1).Colname || ', ROWID from ' || + ia.IndexCols(1).TableSchema || '.' || + ia.IndexCols(1).TableName || ' partition (' || + ia.IndexCols(1).tablepartition || ')'; + end if; + + if ((env.CallProperty is null) and (ia.IndexPartition is not null)) then + stmt := 'create table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || ia.IndexPartition || '_sbtree' || + '(f1, f2) as select ' || + ia.IndexCols(1).Colname || ', ROWID from ' || + ia.IndexCols(1).TableSchema || '.' || + ia.IndexCols(1).TableName || ' partition (' || + ia.IndexCols(1).TablePartition || ')'; + end if; + + dbms_output.put_line('Create'); + dbms_output.put_line(stmt); + + -- execute the statement + if ( (env.CallProperty is null) or + (env.CallProperty = sys.ODCIConst.IntermediateCall) ) then + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + return ODCIConst.Success; + end; + + static function ODCIIndexDrop(ia sys.ODCIIndexInfo, env sys.ODCIEnv) + return number is + stmt varchar2(1000); + cnum integer; + junk integer; + begin + -- construct the sql statement + stmt := ''; + if ((env.CallProperty is null) and (ia.IndexPartition is null) ) then + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || + '_sbtree'; + else + if (ia.IndexPartition is not null) then + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || ia.IndexPartition || '_sbtree'; + end if; + end if; + + dbms_output.put_line('Drop'); + dbms_output.put_line(stmt); + + -- execute the statement + if ( (env.CallProperty is null) or + (env.CallProperty = sys.ODCIConst.IntermediateCall) ) then + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + return ODCIConst.Success; + end; + + static function ODCIIndexTruncate(ia sys.ODCIIndexInfo, env sys.ODCIEnv) + return number is + stmt varchar2(2000); + cnum integer; + junk integer; + begin + -- construct the sql statement + stmt := ''; + if ((env.CallProperty is null) and (ia.IndexPartition is null) ) then + stmt := 'truncate table ' || ia.IndexSchema || '.' || ia.IndexName || + '_sbtree'; + else + if (ia.IndexPartition is not null) then + stmt := 'truncate table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || ia.IndexPartition || '_sbtree'; + end if; + end if; + + dbms_output.put_line('Truncate'); + dbms_output.put_line(stmt); + + -- execute the statement + if ( (env.CallProperty is null) or + (env.CallProperty = sys.ODCIConst.IntermediateCall) ) then + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + return ODCIConst.Success; + end; + + static function ODCIIndexExchangePartition(ia sys.ODCIIndexInfo, + ia1 sys.ODCIIndexInfo, env sys.ODCIEnv) + return number + is + stmt varchar2(2000); + cnum integer; + junk integer; + begin + stmt := ''; + dbms_output.put_line('Exchange Partitions'); + + -- construct the sql statement + stmt := 'alter table temp exchange partition p1 with table ' || + ia1.IndexSchema || '.' || ia1.IndexName || '_sbtree'; + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + stmt := 'alter table temp exchange partition p1 with table ' || + ia.IndexSchema || '.' || ia.IndexName || + '_' || ia.IndexPartition || '_sbtree'; + + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + stmt := 'alter table temp exchange partition p1 with table ' || + ia1.IndexSchema || '.' || ia1.IndexName || '_sbtree'; + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + return ODCIConst.Success; + end; + + static function ODCIIndexMergePartition(ia sys.ODCIIndexInfo, + part_name1 sys.ODCIPartInfo, part_name2 sys.ODCIPartInfo, + parms varchar2, env sys.ODCIEnv) + return number + is + stmt varchar2(2000); + cnum integer; + junk integer; + begin + dbms_output.put_line('Merge Partitions'); + stmt := ''; + + if ( part_name2 is not null) then + stmt := 'create table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || part_name2.IndexPartition || '_sbtree' || + '(f1 ' || ia.IndexCols(1).ColTypeName || + '(30), f2 ROWID)'; + + dbms_output.put_line('create'); + dbms_output.put_line('Parameter string : ' || parms); + + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + if ( part_name1 is not null) then + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || part_name1.IndexPartition || '_sbtree'; + + dbms_output.put_line('drop'); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + if (ia.IndexPartition is not null) then + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || ia.IndexPartition || '_sbtree'; + + dbms_output.put_line('drop'); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + return ODCIConst.Success; + end; + + static function ODCIIndexSplitPartition(ia sys.ODCIIndexInfo, + part_name1 sys.ODCIPartInfo, part_name2 sys.ODCIPartInfo, + parms varchar2, env sys.ODCIEnv) + return number + is + stmt varchar2(2000); + cnum integer; + junk integer; + begin + dbms_output.put_line('Split Partition'); + stmt := ''; + + if (ia.IndexPartition is not null) then + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || ia.IndexPartition || '_sbtree'; + + dbms_output.put_line('drop'); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + if ( part_name1 is not null) then + stmt := 'create table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || part_name1.IndexPartition || '_sbtree' || + '( f1 ' || ia.IndexCols(1).ColTypeName || + '(30), f2 ROWID)'; + + dbms_output.put_line('create'); + dbms_output.put_line('Parameter string : ' || parms); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + if ( part_name2 is not null) then + stmt := 'create table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || part_name2.IndexPartition || '_sbtree' || + '( f1 ' || ia.IndexCols(1).ColTypeName || + '(30), f2 ROWID)'; + + dbms_output.put_line('create'); + dbms_output.put_line('Parameter string : ' || parms); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + return ODCIConst.Success; + end; + + static function ODCIIndexInsert(ia sys.ODCIIndexInfo, rid VARCHAR2, + newval VARCHAR2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbpi" + library extdemo5l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + newval, + newval indicator, + env, + env indicator struct, + return ocinumber + ); + + static function ODCIIndexDelete(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbpd" + library extdemo5l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + oldval, + oldval indicator, + env, + env indicator struct, + return ocinumber + ); + + static function ODCIIndexUpdate(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, newval VARCHAR2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbpu" + library extdemo5l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + oldval, + oldval indicator, + newval, + newval indicator, + env, + env indicator struct, + return ocinumber + ); + + static function ODCIIndexStart(sctx in out psbtree_im, + ia sys.ODCIIndexInfo, op sys.ODCIPredInfo, + qi sys.ODCIQueryInfo, strt number, stop number, + cmpval varchar2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbps" + library extdemo5l + WITH context + parameters ( + context, + sctx, + sctx indicator struct, + ia, + ia indicator struct, + op, + op indicator struct, + qi, + qi indicator struct, + strt, + strt indicator, + stop, + stop indicator, + cmpval, + cmpval indicator, + env, + env indicator struct, + return OCINumber + ); + + member function ODCIIndexFetch(nrows number, + rids OUT sys.ODCIRidList, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbpf" + library extdemo5l + WITH context + parameters ( + context, + self, + self indicator struct, + nrows, + nrows indicator, + rids, + rids indicator, + env, + env indicator struct, + return OCINumber + ); + + member function ODCIIndexClose (env sys.ODCIEnv) + ReTURN NUMBEr AS external + name "qxiqtbpc" + library extdemo5l + WITH context + parameters ( + context, + self, + self indicator struct, + env, + env indicator struct, + return OCINumber + ); + +end; +/ +show errors + +--------------------- +-- CREATE INDEXTYPE +--------------------- + +create indextype psbtree +for +eq(varchar2, varchar2), +lt(varchar2, varchar2), +gt(varchar2, varchar2) +using psbtree_im with local range partition; + +-------------------------- +-- USAGE EXAMPLES -- +-------------------------- +set serveroutput on size 20000 + +---------------- +-- CREATE TABLE +---------------- + +create table t1 (f1 number, f2 varchar2(200)) +partition by range(f1) +( + partition p1 values less than (101), + partition p2 values less than (201), + partition p3 values less than (301), + partition p4 values less than (401) + ); +insert into t1 values (10, 'aaaa'); +insert into t1 values (200, 'bbbb'); +insert into t1 values (100, 'cccc'); +insert into t1 values (300, 'dddd'); +insert into t1 values (400, 'eeee'); +commit; + +----------------------------- +-- CREATE LOCAL DOMAIN INDEX +----------------------------- + +create index it1 on t1(f2) indextype is psbtree local +(partition pe1 parameters('test1'), partition pe2, + partition pe3, partition pe4 parameters('test4')) +parameters('test'); + +----------- +-- INSERTS +----------- + +insert into t1 values (11, 'gggg'); +insert into t1 values (325, 'hhhh'); +insert into t1 values (327, 'iiii'); +select * from t1 order by f1; + +commit; + +----------- +-- DELETES +----------- + +delete from t1 where f1 = 325; +select * from t1 order by f1; + +rollback; + +select * from t1 where eq(f2, 'hhhh') = 1; + +delete from t1 where eq(f2, 'hhhh') = 1; +select * from t1 order by f1; + +select * from t1 where eq(f2, 'hhhh') = 1; + +commit; + +----------- +-- UPDATES +----------- +update t1 set f2 = '####' where f1=327; +select * from t1 order by f1; + +commit; + +update t1 set f1 = 328 where eq(f2, '####') = 1; + +select * from t1 where eq(f2, '####') = 1; + +----------- +-- QUERIES +----------- +-- partition extended table_name +explain plan for + select * from t1 partition(p1) where eq(f2, 'gggg') = 1; +set echo off +@@extdemo0 +set echo on + +select * from t1 partition(p1) where eq(f2, 'gggg') = 1; + +-- entire table +explain plan for + select * from t1 where eq(f2, 'gggg') = 1; +set echo off +@@extdemo0 +set echo on + +select * from t1 where eq(f2, 'gggg') = 1; + +-- subset of table +explain plan for + select * from t1 where eq(f2, 'dddd') = 1 and f1>101 ; +set echo off +@@extdemo0 +set echo on + +select * from t1 where eq(f2, 'dddd') = 1 and f1>101 ; + +-- single partition +explain plan for + select * from t1 where eq(f2, 'dddd') = 1 and f1 =300 ; +set echo off +@@extdemo0 +set echo on + +select * from t1 where eq(f2, 'dddd') = 1 and f1 = 300; + +select * from t1 where lt(f2, 'zzzz') = 1 order by f1; + +select * from t1 where gt(f2, 'aaaa') = 1 order by f1; + +-------------------------- +-- ALTER TABLE OPERATIONS +-------------------------- +--Alter Table Add Partition +alter table t1 add partition pp2 values less than (501); +insert into t1 values (500, 'ffff'); + +--Alter Table Drop Partition +alter table t1 drop partition pp2; + +--Alter Table Split Partition +alter table t1 split partition p2 at (150) into +(partition p21, partition p22); + +--Alter Table Merge Partition +alter table t1 merge partitions p22, p3 into partition pp2; + +--Create A Non-Partitioned Table +create table ext (f1 number, f2 varchar2(200)); + +insert into ext values (310, 'aaaa'); +insert into ext values (320, 'bbbb'); +insert into ext values (330, 'dddd'); + +-- NOW, CREATE DOMAIN INDEXES +create index it2 on ext(f2) indextype is psbtree; + +create table temp ( f1 varchar2(200) , f2 ROWID) +partition by range (f1) +( partition p1 values less than (maxvalue)); + +--Alter Table Exchange Partition + +alter table t1 exchange partition p4 with table ext including indexes; + +--Alter Table Modify Unusable +alter table t1 modify partition p4 unusable local indexes; + +--Alter Table Truncate Partition +alter table t1 truncate partition p1; + +------------ +-- CLEANUPS +------------ + +drop index it1; +drop index it2; +drop table t1; +drop table temp; +drop table ext; +drop indextype psbtree; +drop type psbtree_im; +drop operator eq; +drop operator lt; +drop operator gt; +drop function bt_eq; +drop function bt_lt; +drop function bt_gt; + + diff --git a/extdemo6.c b/extdemo6.c new file mode 100644 index 0000000..199df07 --- /dev/null +++ b/extdemo6.c @@ -0,0 +1,960 @@ +/* Copyright (c) 2008, Oracle. All rights reserved. */ + +/* + + NAME + extdemo6.c - Extensible Indexing example implemented as C routines + for system-managed local domain index on varchar2 column of + a range partitioned table. + + DESCRIPTION + This file contains the definitions of the DML and Query routines + for the extensible indexing example that implements a simple btree + (sbtree) using a system-managed approach. See extdemo6.sql for the + SQL script that defines the indextype. + + PUBLIC FUNCTION(S) + qxiqtbsps - QXIQT Btree Start routine + qxiqtbspf - QXIQT Btree Fetch routine + qxiqtbspc - QXIQT Btree Close routine + qxiqtbspi - QXIQT Btree Insert routine + qxiqtbspd - QXIQT Btree Delete routine + qxiqtbspu - QXIQT Btree Update routine + + PRIVATE FUNCTION(S) + qxiqtce - QXIQT error reporting routine + + NOTES + + + MODIFIED (MM/DD/YY) + yhu 06/06/08 - Creation + +*/ + +#ifndef EXTDEMO6_ORACLE +# include "extdemo6.h" +#endif +#include +#include + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ + +/* ODCIIndexInsert function */ +OCINumber *qxiqtbspi( +OCIExtProcContext *ctx, +ODCIIndexInfo *ix, +ODCIIndexInfo_ind *ix_ind, +char *rid, +short rid_ind, +char *newval, +short newval_ind, +ODCIEnv *env, +ODCIEnv_ind *env_ind) +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + + char insstmt[2000]; /* sql insert statement */ + ODCIColInfo *colinfo; /* column info */ + ODCIColInfo_ind *colinfo_ind; + boolean exists = TRUE; + int partiden; /* table partition iden */ + + + /* allocate memory for OCINumber first */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct insert Statement * + ******************************/ + if ( ix_ind->IndexPartitionIden == OCI_IND_NULL ) + (void)sprintf(insstmt, + "INSERT into %s.%s_sbtree values (:newval, :mrid)", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + else + { + if (qxiqtce(ctx, errhp, OCICollGetElem(envhp, errhp, + (OCIColl *)ix->IndexCols, (sb4)0, &exists, + (void **) &colinfo, (void **) &colinfo_ind))) + return(rval); + + (void)sprintf(insstmt, + "INSERT into %s.%s_sbtree partition (DATAOBJ_TO_PARTITION(%s, :partiden)) values (:newval, :mrid)", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, colinfo->TableName)); + } + + /**************************************** + * Parse and Execute Create Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, + (text *)insstmt, + (ub4)strlen(insstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + if (ix_ind->IndexPartitionIden != OCI_IND_NULL) + { + /* Convert partiden to integer from OCINumber */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, + &(colinfo->TablePartitionIden), + sizeof(partiden), + OCI_NUMBER_SIGNED, + ( void *)&partiden))) + return(rval); + + /* Set up bind for partiden */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":partiden", + sizeof(":partiden")-1, + (dvoid *)&partiden, + (sb4)(sizeof(partiden)), + (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + } + + /* Set up bind for newval */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":newval", + sizeof(":newval")-1, + (dvoid *)newval, + (sb4)(strlen(newval)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":mrid", + sizeof(":mrid")-1, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /* free stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + return(rval); +} + +/* ODCIIndexDelete function */ +OCINumber *qxiqtbspd( +OCIExtProcContext *ctx, +ODCIIndexInfo *ix, +ODCIIndexInfo_ind *ix_ind, +char *rid, +short rid_ind, +char *oldval, +short oldval_ind, +ODCIEnv *env, +ODCIEnv_ind *env_ind) +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + + char delstmt[2000]; /* sql delete statement */ + ODCIColInfo *colinfo; /* column info */ + ODCIColInfo_ind *colinfo_ind; + boolean exists = TRUE; + int partiden; /* table partition iden */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct delete Statement * + ******************************/ + if (ix_ind->IndexPartitionIden == OCI_IND_NULL ) + (void)sprintf(delstmt, + "DELETE FROM %s.%s_sbtree WHERE f2 = :rr", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + else + { + if (qxiqtce(ctx, errhp, OCICollGetElem(envhp, errhp, + (OCIColl *)ix->IndexCols, (sb4)0, &exists, + (void **) &colinfo, (void **) &colinfo_ind))) + return(rval); + + (void)sprintf(delstmt, + "DELETE FROM %s.%s_sbtree partition (DATAOBJ_TO_PARTITION(%s, :partiden)) WHERE f2 = :rr", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, colinfo->TableName)); + } + + /**************************************** + * Parse and Execute delete Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, + (text *)delstmt, + (ub4)strlen(delstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + if (ix_ind->IndexPartitionIden != OCI_IND_NULL) + { + /* Convert partiden to integer from OCINumber */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, + &(colinfo->TablePartitionIden), + sizeof(partiden), + OCI_NUMBER_SIGNED, + ( void *)&partiden))) + return(rval); + + /* Set up bind for partiden */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":partiden", + sizeof(":partiden")-1, + (dvoid *)&partiden, + (sb4)(sizeof(partiden)), + (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + } + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":rr", + sizeof(":rr")-1, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /* free stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + return(rval); +} + +/* ODCIIndexUpdate function */ +OCINumber *qxiqtbspu( +OCIExtProcContext *ctx, +ODCIIndexInfo *ix, +ODCIIndexInfo_ind *ix_ind, +char *rid, +short rid_ind, +char *oldval, +short oldval_ind, +char *newval, +short newval_ind, +ODCIEnv *env, +ODCIEnv_ind *env_ind) +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + + char updstmt[2000]; /* sql upate statement */ + ODCIColInfo *colinfo; /* column info */ + ODCIColInfo_ind *colinfo_ind; + boolean exists = TRUE; + int partiden; /* table partition iden */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct update Statement * + ******************************/ + if (ix_ind->IndexPartitionIden == OCI_IND_NULL) + (void)sprintf(updstmt, + "UPDATE %s.%s_sbtree SET f1 = :newval WHERE f2 = :rr", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + else + { + if (qxiqtce(ctx, errhp, OCICollGetElem(envhp, errhp, + (OCIColl *)ix->IndexCols, (sb4)0, &exists, + (void **) &colinfo, (void **) &colinfo_ind))) + return(rval); + + (void)sprintf(updstmt, + "UPDATE %s.%s_sbtree partition (DATAOBJ_TO_PARTITION(%s, :partiden)) SET f1 = :newval WHERE f2 = :rr", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, colinfo->TableName)); + } + + /**************************************** + * Parse and Execute Create Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, + (text *)updstmt, + (ub4)strlen(updstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + if (ix_ind->IndexPartitionIden != OCI_IND_NULL) + { + /* Convert partiden to integer from OCINumber */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, + &(colinfo->TablePartitionIden), + sizeof(partiden), + OCI_NUMBER_SIGNED, + ( void *)&partiden))) + return(rval); + + /* Set up bind for partiden */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":partiden", + sizeof(":partiden")-1, + (dvoid *)&partiden, + (sb4)(sizeof(partiden)), + (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + } + + /* Set up bind for newval */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":newval", + sizeof(":newval")-1, + (dvoid *)newval, + (sb4)(strlen(newval)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":rr", + sizeof(":rr")-1, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /* free stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + return(rval); +} + +/* ODCIIndexStart function */ +OCINumber *qxiqtbsps( +OCIExtProcContext *ctx, +qxiqtim *sctx, +qxiqtin *sctx_ind, +ODCIIndexInfo *ix, +ODCIIndexInfo_ind *ix_ind, +ODCIPredInfo *pr, +ODCIPredInfo_ind *pr_ind, +ODCIQueryInfo *qy, +ODCIQueryInfo_ind *qy_ind, +OCINumber *strt, +short strt_ind, +OCINumber *stop, +short stop_ind, +char *cmpval, +short cmpval_ind, +ODCIEnv *env, +ODCIEnv_ind *env_ind) +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int strtval; /* start bound */ + int stopval; /* stop bound */ + + int errnum = 29400; /* choose some oracle error number */ + char errmsg[512]; /* error message buffer */ + size_t errmsglen; /* Length of error message */ + + char relop[3]; /* relational operator used in sql stmt */ + char selstmt[2000]; /* sql select statement */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + ub4 key; /* key value set in "sctx" */ + + ub1 *rkey; /* key to retrieve context */ + ub4 rkeylen; /* length of key */ + ODCIColInfo *colinfo; /* column info */ + ODCIColInfo_ind *colinfo_ind; + boolean exists = TRUE; + int partiden; /* table partition iden */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, + errhp))) + return(rval); + + /**********************************************/ + /* Allocate memory to hold index scan context */ + /**********************************************/ + if (sctx_ind ->atomic_qxiqtin == OCI_IND_NULL || + sctx_ind ->scind_qxiqtin == OCI_IND_NULL) + { + if (qxiqtce(ctx, errhp, OCIMemoryAlloc((dvoid *)usrhp, errhp, + (dvoid **)&icx, + OCI_DURATION_STATEMENT, + (ub4)(sizeof(qxiqtcx)), + OCI_MEMORY_CLEARED))) + return(rval); + + icx->stmthp = (OCIStmt *)0; + icx->defnp = (OCIDefine *)0; + icx->bndp = (OCIBind *)0; + } + else + { + /*************************/ + /* Retrieve scan context */ + /*************************/ + rkey = OCIRawPtr(envhp, sctx->sctx_qxiqtim); + rkeylen = OCIRawSize(envhp, sctx->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + rkey, (ub1)rkeylen, + (dvoid **)&(icx)))) + return(rval); + } + + /***********************************/ + /* Check that the bounds are valid */ + /***********************************/ + /* convert from oci numbers to native numbers */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, strt, + sizeof(strtval), + OCI_NUMBER_SIGNED, + (dvoid *)&strtval))) + return(rval); + + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, stop, + sizeof(stopval), + OCI_NUMBER_SIGNED, + (dvoid *)&stopval))) + return(rval); + + /* verify that strtval/stopval are both either 0 or 1 */ + if (!(((strtval == 0) && (stopval == 0)) || + ((strtval == 1) && (stopval == 1)))) + { + strcpy(errmsg, (char *)"Incorrect predicate for sbtree operator"); + errmsglen = (size_t)strlen(errmsg); + if (OCIExtProcRaiseExcpWithMsg(ctx, errnum, (text *)errmsg, errmsglen) + != OCIEXTPROC_SUCCESS) + /* Use cartridge error services here */; + return(rval); + } + + /*********************************************/ + /* Generate the SQL statement to be executed */ + /*********************************************/ + if (memcmp((dvoid *)OCIStringPtr(envhp, pr->ObjectName), (dvoid *)"EQ", 2) + == 0) + if (strtval == 1) + strcpy(relop, (char *)"="); + else + strcpy(relop, (char *)"!="); + else if (memcmp((dvoid *)OCIStringPtr(envhp, pr->ObjectName), (dvoid *)"LT", + 2) == 0) + if (strtval == 1) + strcpy(relop, (char *)"<"); + else + strcpy(relop, (char *)">="); + else + if (strtval == 1) + strcpy(relop, (char *)">"); + else + strcpy(relop, (char *)"<="); + + if (ix_ind->IndexPartitionIden == OCI_IND_NULL) + (void)sprintf(selstmt, "select f2 from %s.%s_sbtree where f1 %s :val", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), relop); + else + { + + if (qxiqtce(ctx, errhp, OCICollGetElem(envhp, errhp, + (OCIColl *)ix->IndexCols, (sb4)0, &exists, + (void **) &colinfo, (void **) &colinfo_ind))) + return(rval); + (void)sprintf(selstmt, "select f2 from %s.%s_sbtree partition (DATAOBJ_TO_PARTITION(%s, :partiden)) where f1 %s :val", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, colinfo->TableName), relop); + } + + /***********************************/ + /* Parse, bind, define and execute */ + /***********************************/ + if (sctx_ind ->atomic_qxiqtin == OCI_IND_NULL || + sctx_ind ->scind_qxiqtin == OCI_IND_NULL) + { + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&(icx->stmthp), + (ub4)OCI_HTYPE_STMT, + (size_t)0, (dvoid **)0))) + return(rval); + } + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(icx->stmthp, errhp, + (text *)selstmt, + (ub4)strlen(selstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + + if (ix_ind->IndexPartitionIden != OCI_IND_NULL) + { + /* Convert partiden to integer from OCINumber */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, + &(colinfo->TablePartitionIden), + sizeof(partiden), + OCI_NUMBER_SIGNED, + ( void *)&partiden))) + return(rval); + + /* Set up bind for partiden */ + if (qxiqtce(ctx, errhp, OCIBindByName(icx->stmthp, &(icx->bndp), errhp, + (text *)":partiden", + sizeof(":partiden")-1, + (dvoid *)&partiden, + (sb4)(sizeof(partiden)), + (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + } + + /* Set up bind for compare value */ + if (qxiqtce(ctx, errhp, OCIBindByName(icx->stmthp, &(icx->bndp),errhp, + (text *)":val", + sizeof(":val")-1, + (dvoid *)cmpval, + (sb4)(strlen(cmpval)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up define */ + if (qxiqtce(ctx, errhp, OCIDefineByPos(icx->stmthp, &(icx->defnp), + errhp, (ub4)1, + (dvoid *)(icx->ridp), + (sb4) sizeof(icx->ridp), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)OCI_DEFAULT))) + return(rval); + + /* execute */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, icx->stmthp, + errhp, (ub4)0, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /************************************/ + /* Set index context to be returned */ + /************************************/ + if (sctx_ind ->atomic_qxiqtin == OCI_IND_NULL || + sctx_ind ->scind_qxiqtin == OCI_IND_NULL) + { + /* generate a key */ + if (qxiqtce(ctx, errhp, OCIContextGenerateKey((dvoid *)usrhp, + errhp, &key))) + return(rval); + + /* set the memory address of the struct to be saved in the context */ + if (qxiqtce(ctx, errhp, OCIContextSetValue((dvoid *)usrhp, errhp, + OCI_DURATION_STATEMENT, + (ub1 *)&key, + (ub1)sizeof(key), + (dvoid *)icx))) + return(rval); + + /* set the key as the member of "sctx" */ + if (qxiqtce(ctx, errhp, OCIRawAssignBytes(envhp, errhp, + (ub1 *)&key, + (ub4)sizeof(key), + &(sctx->sctx_qxiqtim)))) + return(rval); + + sctx_ind->atomic_qxiqtin = OCI_IND_NOTNULL; + sctx_ind->scind_qxiqtin = OCI_IND_NOTNULL; + + return(rval); + } + + return(rval); +} + +/* ODCIIndexFetch function */ +OCINumber *qxiqtbspf( +OCIExtProcContext *ctx, +qxiqtim *self, +qxiqtin *self_ind, +OCINumber *nrows, +short nrows_ind, +OCIArray **rids, +short *rids_ind, +ODCIEnv *env, +ODCIEnv_ind *env_ind) +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int idx = 1; + int nrowsval; + + OCIArray *ridarrp = *rids; /* rowid collection */ + OCIString *ridstr = (OCIString *)0; + + int done = 0; + int retval = (int)ODCI_SUCCESS; + OCINumber *rval = (OCINumber *)0; + + ub1 *key; /* key to retrieve context */ + ub4 keylen; /* length of key */ + + /*******************/ + /* Get OCI handles */ + /*******************/ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, + OCINumberFromInt(errhp, (dvoid *)&retval, sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, errhp))) + return(rval); + + /********************************/ + /* Retrieve context from key */ + /********************************/ + key = OCIRawPtr(envhp, self->sctx_qxiqtim); + keylen = OCIRawSize(envhp, self->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + key, (ub1)keylen, + (dvoid **)&(icx)))) + return(rval); + + /* get value of nrows */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, nrows, + sizeof(nrowsval), + OCI_NUMBER_SIGNED, + (dvoid *)&nrowsval))) + return(rval); + + /****************/ + /* Fetch rowids */ + /****************/ + while (!done) + { + if (idx > nrowsval) + done = 1; + else + { + status = OCIStmtFetch(icx->stmthp, errhp, (ub4)1, (ub2) 0, + (ub4)OCI_DEFAULT); + if (status == OCI_NO_DATA) + { + short col_ind = OCI_IND_NULL; + /* have to create dummy oci string */ + OCIStringAssignText(envhp, errhp, (text *)"dummy", + (ub2)5, &ridstr); + /* append null element to collection */ + if (qxiqtce(ctx, errhp, OCICollAppend(envhp, errhp, + (dvoid *)ridstr, + (dvoid *)&col_ind, + (OCIColl *)ridarrp))) + return(rval); + done = 1; + } + else if (status == OCI_SUCCESS) + { + OCIStringAssignText(envhp, errhp, (text *)icx->ridp, + (ub2)18, (OCIString **)&ridstr); + /* append rowid to collection */ + if (qxiqtce(ctx, errhp, OCICollAppend(envhp, errhp, + (dvoid *)ridstr, + (dvoid *)0, + (OCIColl *)ridarrp))) + return(rval); + idx++; + } + else if (qxiqtce(ctx, errhp, status)) + return(rval); + } + } + + /* free ridstr finally */ + if (ridstr && + (qxiqtce(ctx, errhp, OCIStringResize(envhp, errhp, (ub4)0, + &ridstr)))) + return(rval); + + *rids_ind = OCI_IND_NOTNULL; + + return(rval); +} + + +/* ODCIIndexClose function */ +OCINumber *qxiqtbspc( +OCIExtProcContext *ctx, +qxiqtim *self, +qxiqtin *self_ind, +ODCIEnv *env, +ODCIEnv_ind *env_ind) +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int retval = (int) ODCI_SUCCESS; + OCINumber *rval = (OCINumber *)0; + + ub1 *key; /* key to retrieve context */ + ub4 keylen; /* length of key */ + + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, errhp))) + return(rval); + + /********************************/ + /* Retrieve context using key */ + /********************************/ + key = OCIRawPtr(envhp, self->sctx_qxiqtim); + keylen = OCIRawSize(envhp, self->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + key, (ub1)keylen, + (dvoid **)&(icx)))) + return(rval); + + /* Free handles and memory */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)icx->stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + if (qxiqtce(ctx, errhp, OCIMemoryFree((dvoid *)usrhp, errhp, (dvoid *)icx))) + return(rval); + + return(rval); +} + + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ +static int qxiqtce( +OCIExtProcContext *ctx, +OCIError *errhp, +sword status) +{ + text errbuf[512]; + sb4 errcode = 0; + int errnum = 29400; /* choose some oracle error number */ + int rc = 0; + + switch (status) + { + case OCI_SUCCESS: + rc = 0; + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4)1, (text *)NULL, &errcode, + errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR); + OCIExtProcRaiseExcpWithMsg(ctx, errnum, errbuf, strlen((char *)errbuf)); + rc = 1; + break; + default: + (void) sprintf((char *)errbuf, "Warning - some error\n"); + OCIExtProcRaiseExcpWithMsg(ctx, errnum, errbuf, strlen((char *)errbuf)); + rc = 1; + break; + } + return (rc); +} + +/* end of file extdemo6.c */ + diff --git a/extdemo6.h b/extdemo6.h new file mode 100644 index 0000000..362743d --- /dev/null +++ b/extdemo6.h @@ -0,0 +1,158 @@ +/* Copyright (c) 2008, Oracle. All rights reserved. */ + +/* + NAME + extdemo6.h - Extensible Indexing example implemented as C routines + for system-managed local domain index on varchar2 column + of a range partitioned table. + + DESCRIPTION + This file contains the definitions of the DML and Query routines + for the extensible indexing example that implements a simple btree + (sbtree) using a system-managed approach. See extdemo6.sql for the + SQL script that defines the indextype. + + RELATED DOCUMENTS + + PUBLIC FUNCTION(S) + qxiqtbsps - QXIQT Btree Start routine + qxiqtbspf - QXIQT Btree Fetch routine + qxiqtbspc - QXIQT Btree Close routine + qxiqtbspi - QXIQT Btree Insert routine + qxiqtbspd - QXIQT Btree Delete routine + qxiqtbspu - QXIQT Btree Update routine + + PRIVATE FUNCTION(S) + qxiqtce - QXIQT error reporting routine + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + yhu 06/06/08 - Creation + +*/ + +#ifndef EXTDEMO6_ORACLE +# define EXTDEMO6_ORACLE + +#ifndef OCI_ORACLE +# include +#endif +#ifndef ODCI_ORACLE +# include +#endif + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +#ifdef WIN32COMMON +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + +/* index scan context - should be stored in "statement" duration memory + * and used by start, fetch and close routines. + */ +struct qxiqtcx +{ + OCIStmt *stmthp; + OCIDefine *defnp; + OCIBind *bndp; + char ridp[19]; +}; +typedef struct qxiqtcx qxiqtcx; + +/* The index implementation type is an ADT with a single RAW attribute + * which will be used to store the context key value. + * C mapping of the implementation type : + */ +struct qxiqtim +{ + OCIRaw *sctx_qxiqtim; +}; +typedef struct qxiqtim qxiqtim; + +struct qxiqtin +{ + short atomic_qxiqtin; + short scind_qxiqtin; +}; +typedef struct qxiqtin qxiqtin; + +/*--------------------------------------------------------------------------- + EXPORT FUNCTIONS + ---------------------------------------------------------------------------*/ +/* ODCIIndexStart */ +OCINumber DLLEXPORT *qxiqtbsps( OCIExtProcContext *ctx, + struct qxiqtim *sctx, struct qxiqtin *sctx_ind, + ODCIIndexInfo *ix, ODCIIndexInfo_ind *ix_ind, + ODCIPredInfo *pr, ODCIPredInfo_ind *pr_ind, + ODCIQueryInfo *qy, ODCIQueryInfo_ind *qy_ind, + OCINumber *strt, short strt_ind, + OCINumber *stop, short stop_ind, + char *cmpval, short cmpval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind ); + +/* ODCIIndexFetch */ +OCINumber DLLEXPORT *qxiqtbspf( OCIExtProcContext *ctx, + struct qxiqtim *self, struct qxiqtin *self_ind, + OCINumber *nrows, short nrows_ind, + OCIArray **rids, short *rids_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind ); + +/* ODCIIndexClose */ +OCINumber DLLEXPORT *qxiqtbspc( OCIExtProcContext *ctx, + struct qxiqtim *self, struct qxiqtin *self_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind ); + +/* ODCIIndexInsert */ +OCINumber DLLEXPORT *qxiqtbspi( OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *newval, + short newval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind ); + +/* ODCIIndexDelete */ +OCINumber DLLEXPORT *qxiqtbspd( OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *oldval, + short oldval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind ); + +/* ODCIIndexUpdate */ +OCINumber DLLEXPORT *qxiqtbspu( OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *oldval, + short oldval_ind, + char *newval, + short newval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind ); + + +/*--------------------------------------------------------------------------- + INTERNAL FUNCTIONS + ---------------------------------------------------------------------------*/ + +static int qxiqtce( OCIExtProcContext *ctx, OCIError *errhp, + sword status ); + +#endif /* EXTDEMO6_ORACLE */ diff --git a/extdemo6.sql b/extdemo6.sql new file mode 100644 index 0000000..4046a2b --- /dev/null +++ b/extdemo6.sql @@ -0,0 +1,722 @@ +Rem +Rem $Header: extdemo6.sql 06-jun-2008.09:31:29 yhu Exp $ +Rem +Rem extdemo6.sql +Rem +Rem Copyright (c) 2008, Oracle. All rights reserved. +Rem +Rem NAME +Rem extdemo6.sql - An extensible indexing example implemented +Rem as C routines for system-managed local domain index +Rem on varchar2 column of a range partitioned table. +Rem +Rem DESCRIPTION +Rem This file demonstrates the definition and usage of a simple +Rem btree indextype whose routines are implemented as C callouts. +Rem The C routines are in the file extdemo6.c +Rem The header file is extdemo6.h +Rem +Rem The following steps should have been done before running +Rem this script. +Rem 1. Compile the C file (i.e make -f demo_rdbms.mk demos) +Rem 2. Create a user named extdemo6 with password extdemo6 +Rem with all the necessary privileges. +Rem 3. Create a library in extdemo6 schema called extdemo6l +Rem which points to the compiled extdemo6.c +Rem +Rem The design of the indextype is as follows : +Rem +Rem The sbtree indextype implemented here will support the evaluation +Rem of three user-defined operators : gt(Greater Than), lt(Less Than) +Rem and eq(EQuals). These operators can operate on the operands of +Rem VARCHAR2 datatype. +Rem To simplify the implementation of the indextype, we will store +Rem the index data in a regular table. +Rem Thus, our code merely translates operations on the SB-tree into +Rem operations on the table storing the index data. +Rem When a user creates a SB-tree index, we will create a table +Rem consisting of the indexed column and a rowid column. Inserts into +Rem the base table will cause appropriate insertions into the index table. +Rem Deletes and updates are handled similarly. +Rem When the SB-tree is queried based on a user-defined operator (one +Rem of gt, lt and eq), we will fire off an appropriate query against +Rem the index table to retrieve all the satisfying rows and return them. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem yhu 06/06/08 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +--------------------------------------------------------------------- +-- SIMPLE B-TREE Index Method Implemented as C Callouts -- +--------------------------------------------------------------------- + +connect extdemo6/extdemo6 +set echo off +@'?/rdbms/admin/utlxplan.sql' +set echo on + +-- CREATE FUNCTIONAL IMPLEMENTATIONS for operators + +create function bt_eq(a varchar2, b varchar2) return number as +begin + if a = b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_lt(a varchar2, b varchar2) return number as +begin + if a < b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_gt(a varchar2, b varchar2) return number as +begin + if a > b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +-- CREATE BTREE OPERATORS + +create operator eq binding (varchar2, varchar2) + return number using bt_eq; + +create operator lt binding (varchar2, varchar2) + return number using bt_lt; + +create operator gt binding (varchar2, varchar2) + return number using bt_gt; + +create table md_table(iname varchar2(30), ipname varchar2(30), + params varchar2(1000), ipobj# number); + +create or replace package md authid definer as + procedure insertmd(iname varchar2, ipname varchar2, + ipobj# number, params varchar2); + procedure updateobjnum(iname varchar2, ipname varchar2, ipobj# number); + procedure updateidxnam(oldiname varchar2, newiname varchar2); + procedure updateidxpart(iname varchar2,oldpname varchar2, newpname varchar2); + procedure updateparams(iname varchar2, ipname varchar2, params varchar2); + procedure deletemd(iname varchar2, ipname varchar2); + procedure deleteindexmd(iname varchar2); +end md; +/ + +show errors + +create or replace package body md as + procedure insertmd (iname varchar2, ipname varchar2, + ipobj# number, params varchar2) + is + stmt1 varchar2(1000); + begin + stmt1 := 'insert into md_table values(:1, :2, :3, :4)'; + execute immediate stmt1 using iname, ipname, params, ipobj#; + + end; + + procedure updateobjnum(iname varchar2, ipname varchar2, ipobj# number) + is + stmt1 varchar2(1000); + begin + stmt1 := 'update md_table set ipobj# = :1 where iname = :2 and ipname= :3'; + execute immediate stmt1 using ipobj#, iname, ipname; + + end; + + procedure updateidxnam(oldiname varchar2, newiname varchar2) + is + stmt1 varchar2(1000); + begin + stmt1 := 'update md_table set iname = :1 where iname = :2'; + execute immediate stmt1 using newiname, oldiname; + end; + + procedure updateidxpart(iname varchar2,oldpname varchar2, newpname varchar2) + is + stmt1 varchar2(1000); + begin + stmt1 := 'update md_table set ipname =:1 where iname =:2 and ipname =:3'; + execute immediate stmt1 using newpname, iname, oldpname; + end; + + procedure updateparams(iname varchar2, ipname varchar2, params varchar2) + is + stmt1 varchar2(1000); + begin + stmt1 := 'update md_table set params = :1 where iname =:2 and ipname=:3'; + execute immediate stmt1 using params, iname, ipname; + end; + + procedure deletemd(iname varchar2, ipname varchar2) + is + stmt1 varchar2(1000); + begin + stmt1 := 'delete from md_table where iname = :1 and ipname = :2'; + execute immediate stmt1 using iname, ipname; + + end; + + procedure deleteindexmd(iname varchar2) + is + stmt1 varchar2(1000); + begin + stmt1 := 'delete from md_table where iname = :1'; + execute immediate stmt1 using iname; + + end; + end; +/ + +show errors; + +-- CREATE INDEXTYPE IMPLEMENTATION TYPE +create type psbtree_im as object +( + scanctx RAW(4), + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return NUMBER, + + static function ODCIIndexCreate (ia sys.ODCIIndexInfo, + parms varchar2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexAlter (ia sys.ODCIIndexInfo, + parms IN OUT varchar2, altopt number, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexDrop(ia sys.ODCIIndexInfo, + env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexInsert(ia sys.ODCIIndexInfo, rid VARCHAR2, + newval VARCHAR2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexDelete(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexUpdate(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, newval VARCHAR2, env sys.ODCIEnv) + return NUMBER, + + static function ODCIIndexUpdPartMetadata(ia sys.ODCIIndexInfo, + palist sys.ODCIPartInfoList, env sys.ODCIEnv) + return NUMBER, + + static function ODCIIndexExchangePartition (ia sys.ODCIIndexInfo, + ia1 sys.ODCIIndexInfo, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexStart(sctx IN OUT psbtree_im, + ia sys.ODCIIndexInfo, op sys.ODCIPredInfo, + qi sys.ODCIQueryInfo, strt number, stop number, + cmpval varchar2, env sys.ODCIEnv) + return NUMBER, + + member function ODCIIndexFetch(nrows number, + rids OUT sys.ODCIRidList, env sys.ODCIEnv) + return NUMBER, + + member function ODCIIndexClose(env sys.ODCIEnv) return NUMBER +); +/ +show errors + +--------------------------------- +-- CREATE IMPLEMENTATION UNIT -- +--------------------------------- + +-- CREATE TYPE BODY +create or replace type body psbtree_im +is + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return number is + begin + ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCIINDEX2')); + return ODCIConst.Success; + end ODCIGetInterfaces; + + static function ODCIIndexCreate (ia sys.ODCIIndexInfo, + parms varchar2, env sys.ODCIEnv) return number + is + i integer; + stmt varchar2(2000); + cursor cur1(ianame varchar2) is + select partition_name, parameters from user_ind_partitions + where index_name = ianame order by partition_name; + begin + stmt := ''; + + if (env.CallProperty is null) then + stmt := 'create table ' ||ia.IndexSchema || '.' || ia.IndexName || + '_sbtree(f1 varchar2(1000), f2 rowid)'; + elsif (env.callproperty = sys.ODCIConst.FirstCall) then + stmt := ''; + i := 1; + + for c1 in cur1(ia.indexname) loop + if (i >1) then + stmt := stmt || ','; + end if; + stmt := stmt || 'partition ' || c1.partition_name; + md.insertmd(ia.indexname, c1.partition_name, 0, c1.parameters); + i := i+1; + end loop; + stmt := 'create table ' || ia.indexschema || '.' || ia.indexname || + '_sbtree (f1 varchar2(1000), f2 rowid) partition by system ' || + '( ' || stmt || ')'; + end if; + + dbms_output.put_line('Create'); + dbms_output.put_line(stmt); + + -- execute the statement + if ( (env.CallProperty is null) or + (env.CallProperty = sys.ODCIConst.FirstCall) ) then + execute immediate stmt; + if (env.CallProperty is null) then + execute immediate 'insert into ' ||ia.IndexSchema || '.' + || ia.IndexName || '_sbtree select ' || + ia.IndexCols(1).Colname || ', ROWID from ' || + ia.IndexCols(1).TableSchema || '.' || + ia.IndexCols(1).TableName; + end if; + end if; + + return ODCIConst.Success; + end; + + static function ODCIIndexAlter (ia sys.ODCIIndexInfo, + parms IN OUT varchar2, altopt number, env sys.ODCIEnv) + return number is + stmt varchar2(2000); + + begin + stmt := ''; + if (altopt = ODCIConst.AlterIndexRebuild) then + if (env.callproperty = ODCIConst.IntermediateCall) then + md.updateobjnum(ia.IndexName, ia.IndexPartition, ia.IndexPartitionIden); + stmt := 'insert into ' || ia.indexschema || '.' || ia.indexname || + '_sbtree partition (' || ia.indexpartition || ') select ' || + ia.indexcols(1).colname || ', rowid from ' || + ia.indexcols(1).tableschema || '.' || ia.indexcols(1).tablename || + ' partition (' || ia.indexcols(1).tablepartition || ')'; + dbms_output.put_line(stmt); + execute immediate stmt; + end if; + elsif (altopt = ODCIConst.AlterIndexRename) then + if (ia.IndexPartition is not null) then + md.updateidxpart(ia.IndexName, ia.IndexPartition, parms); + stmt := 'alter table ' || ia.indexschema || '.' || + ia.indexname || '_sbtree rename partition ' || + ia.indexpartition || ' to ' || parms; + dbms_output.put_line(stmt); + execute immediate stmt; + else + md.updateidxnam(ia.IndexName, parms); + stmt := 'alter table ' || ia.indexschema || '.' || + ia.indexname || '_sbtree rename to ' || parms || '_sbtree'; + dbms_output.put_line(stmt); + execute immediate stmt; + end if; + end if; + + dbms_output.put_line('Alter'); + return ODCIConst.Success; + end ODCIIndexAlter; + + static function ODCIIndexDrop(ia sys.ODCIIndexInfo, env sys.ODCIEnv) + return number is + stmt varchar2(1000); + cnum integer; + junk integer; + begin + -- construct the sql statement + stmt := ''; + if (env.CallProperty is null) then + md.deleteindexmd(ia.indexname); + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || + '_sbtree'; + + dbms_output.put_line('Drop'); + dbms_output.put_line(stmt); + + execute immediate stmt; + end if; + + return ODCIConst.Success; + end; + + static function ODCIIndexExchangePartition(ia sys.ODCIIndexInfo, + ia1 sys.ODCIIndexInfo, env sys.ODCIEnv) + return number + is + stmt varchar2(2000); + cnum integer; + junk integer; + begin + stmt := ''; + dbms_output.put_line('Exchange Partitions'); + + -- construct the sql statement + stmt := 'alter table ' || ia.IndexSchema || '.' || ia.IndexName || + '_sbtree exchange partition ' || ia.IndexPartition || + ' with table ' || ia1.IndexSchema || '.' || ia1.IndexName || '_sbtree'; + + dbms_output.put_line(stmt); + execute immediate stmt; + + return ODCIConst.Success; + end; + + static function ODCIIndexUpdPartMetadata(ia sys.ODCIIndexInfo, + palist sys.ODCIPartInfoList, env sys.ODCIEnv) + return number is + col number; + begin + + dbms_output.put_line('ODCIUpdPartMetadata'); + SYS.ODCIINDEXINFODUMP(ia); + SYS.ODCIPARTINFOLISTDUMP(palist); + + FOR col IN palist.FIRST..palist.LAST LOOP + IF (palist(col).PartOp = ODCIConst.AddPartition) THEN + md.insertmd(ia.indexname, palist(col).indexpartition, + palist(col).indexpartitioniden, null); + ELSIF (palist(col).PartOp = ODCIConst.DropPartition) THEN + md.deletemd(ia.indexname, palist(col).indexpartition); + END IF; + END LOOP; + return ODCIConst.Success; + END; + + static function ODCIIndexInsert(ia sys.ODCIIndexInfo, rid VARCHAR2, + newval VARCHAR2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbspi" + library extdemo6l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + newval, + newval indicator, + env, + env indicator struct, + return ocinumber + ); + + static function ODCIIndexDelete(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbspd" + library extdemo6l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + oldval, + oldval indicator, + env, + env indicator struct, + return ocinumber + ); + + static function ODCIIndexUpdate(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, newval VARCHAR2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbspu" + library extdemo6l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + oldval, + oldval indicator, + newval, + newval indicator, + env, + env indicator struct, + return ocinumber + ); + + static function ODCIIndexStart(sctx in out psbtree_im, + ia sys.ODCIIndexInfo, op sys.ODCIPredInfo, + qi sys.ODCIQueryInfo, strt number, stop number, + cmpval varchar2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbsps" + library extdemo6l + WITH context + parameters ( + context, + sctx, + sctx indicator struct, + ia, + ia indicator struct, + op, + op indicator struct, + qi, + qi indicator struct, + strt, + strt indicator, + stop, + stop indicator, + cmpval, + cmpval indicator, + env, + env indicator struct, + return OCINumber + ); + + member function ODCIIndexFetch(nrows number, + rids OUT sys.ODCIRidList, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbspf" + library extdemo6l + WITH context + parameters ( + context, + self, + self indicator struct, + nrows, + nrows indicator, + rids, + rids indicator, + env, + env indicator struct, + return OCINumber + ); + + member function ODCIIndexClose (env sys.ODCIEnv) + ReTURN NUMBEr AS external + name "qxiqtbspc" + library extdemo6l + WITH context + parameters ( + context, + self, + self indicator struct, + env, + env indicator struct, + return OCINumber + ); + +end; +/ +show errors + +--------------------- +-- CREATE INDEXTYPE +--------------------- + +create indextype psbtree +for +eq(varchar2, varchar2), +lt(varchar2, varchar2), +gt(varchar2, varchar2) +using psbtree_im with local range partition +with system managed storage tables; + +-------------------------- +-- USAGE EXAMPLES -- +-------------------------- +set serveroutput on size 20000 + +---------------- +-- CREATE TABLE +---------------- + +create table t1 (f1 number, f2 varchar2(200)) +partition by range(f1) +( + partition p1 values less than (101), + partition p2 values less than (201), + partition p3 values less than (301), + partition p4 values less than (401) + ); +insert into t1 values (10, 'aaaa'); +insert into t1 values (200, 'bbbb'); +insert into t1 values (100, 'cccc'); +insert into t1 values (300, 'dddd'); +insert into t1 values (400, 'eeee'); +commit; + +----------------------------- +-- CREATE LOCAL DOMAIN INDEX +----------------------------- + +create index it1 on t1(f2) indextype is psbtree local +(partition pe1 parameters('test1'), partition pe2, + partition pe3, partition pe4 parameters('test4')) +parameters('test'); + +----------- +-- INSERTS +----------- + +insert into t1 values (11, 'gggg'); +insert into t1 values (325, 'hhhh'); +insert into t1 values (327, 'iiii'); +select * from t1 order by f1; + +commit; + +----------- +-- DELETES +----------- + +delete from t1 where f1 = 325; +select * from t1 order by f1; + +rollback; + +select * from t1 where eq(f2, 'hhhh') = 1; + +delete from t1 where eq(f2, 'hhhh') = 1; +select * from t1 order by f1; + +select * from t1 where eq(f2, 'hhhh') = 1; + +commit; + +----------- +-- UPDATES +----------- +update t1 set f2 = '####' where f1=327; +select * from t1 order by f1; + +commit; + +update t1 set f1 = 328 where eq(f2, '####') = 1; + +select * from t1 where eq(f2, '####') = 1; + +----------- +-- QUERIES +----------- +-- partition extended table_name +explain plan for + select * from t1 partition(p1) where eq(f2, 'gggg') = 1; +set echo off +@@extdemo0 +set echo on + +select * from t1 partition(p1) where eq(f2, 'gggg') = 1; + +-- entire table +explain plan for + select * from t1 where eq(f2, 'gggg') = 1; +set echo off +@@extdemo0 +set echo on + +select * from t1 where eq(f2, 'gggg') = 1; + +-- subset of table +explain plan for + select * from t1 where eq(f2, 'dddd') = 1 and f1>101 ; +set echo off +@@extdemo0 +set echo on + +select * from t1 where eq(f2, 'dddd') = 1 and f1>101 ; + +-- single partition +explain plan for + select * from t1 where eq(f2, 'dddd') = 1 and f1 =300 ; +set echo off +@@extdemo0 +set echo on + +select * from t1 where eq(f2, 'dddd') = 1 and f1 = 300; + +select * from t1 where lt(f2, 'zzzz') = 1 order by f1; + +select * from t1 where gt(f2, 'aaaa') = 1 order by f1; + +-------------------------- +-- ALTER TABLE OPERATIONS +-------------------------- +--Alter Table Add Partition +alter table t1 add partition pp2 values less than (501); +insert into t1 values (500, 'ffff'); + +--Alter Table Drop Partition +alter table t1 drop partition pp2; + +--Alter Table Split Partition +alter table t1 split partition p2 at (150) into +(partition p21, partition p22); + +--Alter Table Merge Partition +alter table t1 merge partitions p22, p3 into partition pp2; + +--Create A Non-Partitioned Table +create table ext (f1 number, f2 varchar2(200)); + +insert into ext values (310, 'aaaa'); +insert into ext values (320, 'bbbb'); +insert into ext values (330, 'dddd'); + +-- NOW, CREATE DOMAIN INDEXES +create index it2 on ext(f2) indextype is psbtree; + +--Alter Table Exchange Partition + +alter table t1 exchange partition p4 with table ext including indexes; + +--Alter Table Modify Unusable +alter table t1 modify partition p4 unusable local indexes; + +--Alter Table Truncate Partition +alter table t1 truncate partition p1; + +------------ +-- CLEANUPS +------------ + +drop index it1; +drop index it2; +drop table t1; +drop table ext; +drop indextype psbtree; +drop type psbtree_im; +drop operator eq; +drop operator lt; +drop operator gt; +drop function bt_eq; +drop function bt_lt; +drop function bt_gt; + + diff --git a/fdemo1.for b/fdemo1.for new file mode 100644 index 0000000..128b139 --- /dev/null +++ b/fdemo1.for @@ -0,0 +1,499 @@ +C +C $Header: fdemo1.for 25-jul-2001.04:07:17 ssappara Exp $ +C +C Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +C +C NAME +C fdemo1.for - Fortran demo program #1 +C MODIFIED (MM/DD/YY) +C ssappara 07/25/01 - bug1788355:Don't use return length NULL in ODEFIN +C mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +C plocke 11/14/95 - to update for v7.3 +C lchidamb 05/16/95 - merge changes from branch 1.2.720.1 +C rkooi2 11/05/92 - Portability mods +C sjain 03/16/92 - Creation + + PROGRAM FDEMO1 + +*--------------------------------------------------------------- +* FDEMO1 is a demonstration program that adds new employee +* rows to the personnel data base. Checking +* is done to insure the integrity of the data base. +* The employee numbers are automatically selected using +* the current maximum employee number as the start. +* If any employee number is a duplicate, it is skipped. +* The program queries the user for data as follows: +* +* Enter employee name : +* Enter employee job : +* Enter employee salary: +* Enter employee dept : +* +* If just is entered for the employee name, +* the program terminates. +* +* If the row is successfully inserted, the following +* is printed: +* +* ENAME added to DNAME department as employee N. +* +* The maximum lengths of the 'ename', 'job', and 'dname' +* columns are determined by an ODESCR call. +* +* Note: VAX FORTRAN, by default, passes all CHARACTER variables +* (variables declared as CHARACTER*N) by descriptor. +* To compile this program on systems that pass character +* variables by descriptor, insert %REF() where necessary. +*--------------------------------------------------------------- + + IMPLICIT INTEGER (A-Z) + + INTEGER*2 LDA(32) + INTEGER*2 CURS(32,2) + INTEGER*2 HDA(256) + CHARACTER*20 UID, PSW + INTEGER*4 NOBLOK + +* CHARACTER string vars to hold the SQL statements + + CHARACTER*60 SMAX + CHARACTER*60 SEMP + CHARACTER*150 INS + CHARACTER*60 SEL + + INTEGER*4 SMAXL, SEMPL, INSL, SELL + +* Program vars to be bound to SQL placeholders and +* select-list fields . + + INTEGER*4 EMPNO, DEPTNO, SAL + CHARACTER*10 ENAME + CHARACTER*10 JOB + CHARACTER*14 DNAME + +* Actual lengths of columns . + + INTEGER*4 ENAMES, JOBS, DNAMES + +* Character strings for SQL placeholders. + + CHARACTER*6 ENON + CHARACTER*6 ENAN + CHARACTER*4 JOBN + CHARACTER*4 SALN + CHARACTER*7 DEPTN + +* Lengths of character strings for SQL placeholders. + + INTEGER*4 ENONL, ENANL, JOBNL, SALNL, DEPTNL + +* Parameters for OPARSE. + + INTEGER*4 NODEFP, V7FLAG + +* Parameters for ODESCR. + + INTEGER*2 DTYPE, PREC, SCALE, NULLOK + INTEGER*4 DSIZE, CNAMEL + CHARACTER*80 CNAME + +*--------------------------------------------------------------- +* Initialize variables. +*--------------------------------------------------------------- + + SMAX = 'SELECT NVL(MAX(EMPNO),0) FROM EMP' + SMAXL = LEN_TRIM(SMAX) + + SEMP = 'SELECT ENAME,JOB FROM EMP' + SEMPL= LEN_TRIM(SEMP) + + INS = 'INSERT INTO EMP(EMPNO,ENAME,JOB,SAL, + + DEPTNO) VALUES (:EMPNO,:ENAME,:JOB,:SAL,:DEPTNO)' + INSL = LEN_TRIM(INS) + + SEL = 'SELECT DNAME FROM DEPT WHERE DEPTNO = :1' + SELL = LEN_TRIM(SEL) + +* All in Deferred Mode + NODEFP = 1 + V7FLAG = 2 + ENAMEL = 10 + JOBL = 10 + EMPNOL = 4 + DEPTL = 4 + SALL = 4 + + ENON = ':EMPNO' + ENAN = ':ENAME' + JOBN = ':JOB' + SALN = ':SAL' + DEPTN = ':DEPTNO' + + ENONL = 6 + ENANL = 6 + JOBNL = 4 + SALNL = 4 + DEPTNL = 7 + +*--------------------------------------------------------------- +* Connect to ORACLE in non-blocking mode. +* HDA must be initialized to all zeros before call to OLOG. +*--------------------------------------------------------------- + + UID = 'SCOTT' + PSW = 'TIGER' + NOBLOK = 0 + DATA HDA/256*0/ + + CALL OLOG(LDA, HDA, UID, LEN_TRIM(UID), + + PSW, LEN_TRIM(PSW), 0, -1, NOBLOK) + IF (LDA(7).NE.0) THEN + CALL ERRRPT(LDA(1), LDA(1)) + GO TO 900 + END IF + + WRITE (*, '(1X, A, A20)') 'Logged on to ORACLE as user ', + + UID + +*--------------------------------------------------------------- +* Open two cursors for the personnel data base. +*--------------------------------------------------------------- + + CALL OOPEN(CURS(1,1), LDA, 0, -1, -1, 0, -1) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + CALL OOPEN(CURS(1,2),LDA(1),0, -1, -1, 0, -1) + IF (CURS(1,2).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,2)) + GO TO 700 + END IF + +*--------------------------------------------------------------- +* Turn off auto-commit. Note: the default is off, +* so this could be omitted. +*--------------------------------------------------------------- + + CALL OCOF(LDA(1)) + IF (LDA(1).NE.0) THEN + CALL ERRRPT(LDA(1), LDA(1)) + GO TO 700 + END IF + +*--------------------------------------------------------------- +* Retrieve the current maximum employee number. +*---------------------------------------------------------------- + +* Parse the SQL statement. + + CALL OPARSE(CURS(1,1), SMAX, SMAXL, NODEFP, V7FLAG) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + +* Define a buffer to receive the MAX(EMPNO) from ORACLE. + + CALL ODEFIN(CURS(1,1), 1, EMPNO, 4, 3, -1, INDP, 0, -1, -1, + + RLEN,RCODE) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + +* Execute the SQL statement. + + CALL OEXEC(CURS(1,1)) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + +* Fetch the data from ORACLE into the defined buffer. + + CALL OFETCH(CURS(1,1)) + IF (CURS(1,1).EQ.0) GO TO 50 + IF (CURS(7,1).NE.1403) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + +* A cursor return code of 1403 means that no row +* satisfied the query, so generate the first empno. + + EMPNO=10 +50 CONTINUE + +*--------------------------------------------------------------- +* Determine the max length of the employee name and job title. +* Parse the SQL statement - it will not be executed. +* Describe the two fields specified in the SQL statement. +*---------------------------------------------------------------- + + CALL OPARSE(CURS(1,1), SEMP, SEMPL, NODEFP, V7FLAG) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + CNAMEL = 80 + CALL ODESCR(CURS(1,1), 1, ENAMES, DTYPE, CNAME, + + CNAMEL, DSIZE, PREC, SCALE, NULLOK) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + IF (ENAMES .GT. ENAMEL) THEN + WRITE (*, '(1X, A, I2, A, I2)') 'ENAME too large (', + + ENAMES, ' for buffer (', ENAMEL, ').' + GO TO 700 + END IF + + CNAMEL = 80 + CALL ODESCR(CURS(1,1), 2, JOBS, DTYPE, CNAME, + + CNAMEL, DSIZE, PREC, SCALE, NULLOK) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + IF (JOBS .GT. JOBL) THEN + WRITE (*, '(1X, A, I2, A, I2)') 'JOB too large (', + + JOBS, ' for buffer (', JOBL, ').' + GO TO 700 + END IF + +*-------------------------------------------------------------- +* Parse the insert and select statements. +*-------------------------------------------------------------- + + CALL OPARSE(CURS(1,1), INS, INSL, NODEFP, V7FLAG) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + CALL OPARSE(CURS(1,2), SEL, SELL, NODEFP, V7FLAG) + IF (CURS(1,2).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,2)) + GO TO 700 + END IF + +*-------------------------------------------------------------- +* Bind all placeholders. +*-------------------------------------------------------------- + + CALL OBNDRV(CURS(1,1),ENON,LEN(ENON),EMPNO,EMPNOL,3,-1,0,0,-1,-1) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + CALL OBNDRV(CURS(1,1),ENAN,ENANL,ENAME,ENAMEL,1,-1,0,0,-1,-1) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + CALL OBNDRV(CURS(1,1),JOBN,JOBNL,JOB,JOBL,1,-1,0,0,-1,-1) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + CALL OBNDRV(CURS(1,1),SALN,SALNL,SAL,SALL,3,-1,0,0,-1,-1) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + CALL OBNDRV(CURS(1,1),DEPTN,DEPTNL,DEPTNO,DEPTL,3,-1,0,0,-1,-1) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + +*-------------------------------------------------------------- +* Bind the DEPTNO variable. +*-------------------------------------------------------------- + + CALL OBNDRN(CURS(1,2), 1, DEPTNO, DEPTL, 3,-1,0,0,-1,-1) + IF (CURS(1,2).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,2)) + GO TO 700 + END IF + +*-------------------------------------------------------------- +* Describe the DNAME column - get the name and length. +*-------------------------------------------------------------- + + DNAMEL = 14 + CALL ODESCR(CURS(1,1), 1, DNAMES, DTYPE, DNAME, + + DNAMEL, DSIZE, PREC, SCALE, NULLOK) + IF (CURS(1,2).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,2)) + GO TO 700 + END IF + + IF (DNAMES .GT. DNAMEL) THEN + WRITE (*, '(1X, A)') 'DNAME too large for buffer.' + GO TO 700 + END IF + +*-------------------------------------------------------------- +* Define the buffer to receive DNAME. +*-------------------------------------------------------------- + + CALL ODEFIN(CURS(1,2),1,DNAME,DNAMEL,1,-1,INDP,0,-1,-1, + + RLEN,RCODE) + IF (CURS(1,2).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,2)) + GO TO 700 + END IF + +*-------------------------------------------------------------- +* Read the user's input. Statement 100 +* starts the main program loop. +*-------------------------------------------------------------- + +100 WRITE (*, '( A)') + + 'Enter employee name (CR to QUIT) : ' + READ (*, '(A)'), ENAME + IF (LEN_TRIM(ENAME) .EQ. 0) GO TO 700 + WRITE (*, '( A)'), 'Enter employee job : ' + READ (*, '(A)'), JOB + WRITE (*, '( A)') 'Enter employee salary: ' + READ (*, '(I6)'), SAL +300 WRITE (*, '( A)') 'Enter employee dept : ' + READ (*, '(I6)'), DEPTNO + +*-------------------------------------------------------------- +* Check for a valid department number by +* executing the SELECT statement. +*-------------------------------------------------------------- + + CALL OEXEC(CURS(1,2)) + IF (CURS(1,2).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,2)) + GO TO 700 + END IF + +*-------------------------------------------------------------- +* Fetch the rows - DEPTNO is a primary key, so a max of +* one row will be fetched. +* If the return code is 1403 no such department exists. +*-------------------------------------------------------------- + + CALL OFETCH(CURS(1,2)) + IF (CURS(1,2).EQ.0) GO TO 500 + IF (CURS(7,2).NE.1403) THEN + CALL ERRRPT(LDA(1), CURS(1,2)) + GO TO 700 + END IF + + WRITE (*, '(1X, A)') 'No such department number' + GO TO 300 + +*-------------------------------------------------------------- +* Increment EMPNO by 10. +* Execute the insert statement. +*-------------------------------------------------------------- + +500 EMPNO = EMPNO + 10 + CALL OEXEC(CURS(1,1)) + IF (CURS(1,1).EQ.0) GO TO 600 + +*-------------------------------------------------------------- +* If the call returns code 1 (duplicate value in index), +* generate the next possible employee number. +*-------------------------------------------------------------- + + IF (CURS(7,1).NE.1) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + EMPNO=EMPNO+10 + GO TO 500 + +600 WRITE (*, 610) ENAME, DNAME, EMPNO +610 FORMAT(/, 1X, A10, ' added to the ', A14, + + ' department as employee# ', I4, /) + +*-------------------------------------------------------------- +* The row has been added - commit this transaction. +*-------------------------------------------------------------- + + CALL OCOM(LDA(1)) + IF (LDA(1).NE.0) THEN + CALL ERRRPT(LDA(1), LDA(1)) + GO TO 700 + END IF + + GO TO 100 + +*-------------------------------------------------------------- +* Either a fatal error has occurred or the user typed +* for the employee name. +* Close the cursors, disconnect, and end the program. +*-------------------------------------------------------------- + +700 CONTINUE + + CALL OCLOSE(CURS(1,1)) + IF (CURS(1,1).NE.0) CALL ERRRPT(LDA(1), CURS(1,1)) + CALL OCLOSE(CURS(1,2)) + IF (CURS(1,2).NE.0) CALL ERRRPT(LDA(1), CURS(1,2)) + + CALL OLOGOF(LDA(1)) + IF (LDA(1).NE.0) CALL ERRRPT(LDA(1), LDA(1)) +900 STOP + END + + +*-------------------------------------------------------------- +* ERRRPT prints the cursor number, the error code, and the +* OCI function code. +* +* CURS is a cursor. +* N is the cursor number. +*-------------------------------------------------------------- + + SUBROUTINE ERRRPT(LDA, CURS) + INTEGER*2 CURS(32), LDA(32) + + CHARACTER*160 ERRMSG + + IF (CURS(6) .GT. 0) THEN + WRITE (*, '(1X, A, I3)') 'ORACLE error processing OCI + + function ', CURS(6) + END IF + + CALL OERHMS(LDA(1), CURS(7), ERRMSG, 160) + WRITE (*, '(1X, A)') ERRMSG + + RETURN + END + + + INTEGER FUNCTION LEN_TRIM(STRING) + CHARACTER*(*) STRING + + INTEGER NEXT + + DO 10 NEXT = LEN(STRING), 1, -1 + IF (STRING(NEXT : NEXT) .NE. ' ') THEN + LEN_TRIM = NEXT + RETURN + ENDIF +10 CONTINUE + + LEN_TRIM = 0 + + RETURN + END + diff --git a/fdemo2.for b/fdemo2.for new file mode 100644 index 0000000..8e24eee --- /dev/null +++ b/fdemo2.for @@ -0,0 +1,389 @@ +C +C $Header: fdemo2.for 14-jul-99.13:43:24 mjaeger Exp $ +C +C Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +C +C NAME +C fdemo2.for - Fortran demo program # 2 +C MODIFIED (MM/DD/YY) +C mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +C plocke 11/14/95 - to update for v7.3 +C lchidamb 05/16/95 - merge changes from branch 1.1.720.1 +C sjain 03/16/92 - Creation + +* FDEMO2.FOR +* +* A dynamic SQL OCI example program. Processes +* SQL statements entered interactively by the user. +* +* There is a 132-character limit on the length of +* the SQL statements. It is not necessary to +* terminate the SQL statement with a semicolon. +* +* To end the demo, type 'exit' or 'EXIT' at the +* prompt. + + PROGRAM FDEMO2 + IMPLICIT INTEGER*4 (A-Z) + +* Data structures +* Logon and cursor areas + INTEGER*2 CDA(32), LDA(32), HDA(256) + +* Bind values + CHARACTER*20 BVARV(8) + INTEGER NBV + +* Output values + CHARACTER*10 DVARC(8) + INTEGER DVARI(8) + REAL*4 DVARF(8) + INTEGER*2 DBTYPE(8), RLEN(8), RCODE(8) + INTEGER*2 INDP(8) + INTEGER NOV + +* Column names for SELECT + CHARACTER*10 COLNAM(8) + +* SQL statement buffer and logon info + CHARACTER*80 SQLSTM, UID, PWD, PROMPT + INTEGER UIDL, PWDL, SQLL, NOBLOK + + UID = 'SCOTT' + PWD = 'TIGER' + UIDL = LEN_TRIM(UID) + PWDL = LEN_TRIM(PWD) + NOBLOK = 0 + +* Connect to ORACLE in non-blocking mode. +* HDA must be initialized to all zeros before call to OLOG. + + DATA HDA/256*0/ + CALL OLOG(LDA, HDA, UID, UIDL, PWD, PWDL, 0, -1, NOBLOK) + IF (LDA(7) .NE. 0) THEN + CALL ERRRPT(LDA, CDA) + GO TO 999 + ENDIF + WRITE (*, '(1X, A, A)') 'Connected to ORACLE as user ', UID + +* Open a cursor. + CALL OOPEN(CDA, LDA, UID, 0, -1, PWD, 0) + IF (LDA(7) .NE. 0) THEN + CALL ERRRPT(LDA, CDA) + GO TO 900 + ENDIF + +* Beginning of the main program loop. +* Get and process SQL statements. + PROMPT = 'Enter SQL statement (132 char max) or EXIT to quit >' +100 WRITE (*, '(/, A)') PROMPT + READ '(A)', SQLSTM + + SQLL = LEN_TRIM(SQLSTM) + IF (SQLL .EQ. 0) GO TO 100 + + I = INDEX(SQLSTM, ';') + IF (I .GT. 0) THEN + SQLL = I - 1 + ENDIF + + IF ((SQLSTM(1:4) .EQ. 'exit') .OR. + + (SQLSTM(1:4) .EQ. 'EXIT')) GO TO 900 + +* Parse the statement. + CALL OPARSE(CDA, SQLSTM, SQLL, 0, 2) + IF (CDA(7) .NE. 0) THEN + CALL ERRRPT(LDA, CDA) + GO TO 100 + ENDIF + +* If there are bind values, obtain them from user. + CALL GETBNV(LDA, CDA, SQLSTM, BVARV, NBV) + IF (NBV .LT. 0) GO TO 100 + +* Define the output variables. If the statement is not a +* query, NOV returns as 0. If there were errors defining +* the output variables, NOV returns as -1. + CALL DEFINE(LDA, CDA, COLNAM, DBTYPE, DVARC, DVARI, + + DVARF, INDP, RLEN, RCODE, NOV) + IF (NOV .LT. 0) GO TO 100 + +* Execute the statement. + CALL OEXN(CDA, 1, 0) + IF (CDA(7) .NE. 0) THEN + CALL ERRRPT(LDA, CDA) + GO TO 100 + ENDIF + +* Fetch rows and display output if the statement was a query. + CALL FETCHN(LDA, CDA, COLNAM, NOV, DBTYPE, DVARC, + + DVARI, DVARF, INDP, RV) + IF (RV .LT. 0) GO TO 100 + +* Loop back to statement 100 to process +* another SQL statement. + GO TO 100 + +* End of main program loop. Here on exit or fatal error. +900 CALL OCLOSE(CDA) + CALL OLOGOF(LDA) + +* End of program. Come here if connect fails. +999 END + + +* Begin subprograms. + + SUBROUTINE GETBNV(LDA, CDA, STMT, BVARV, N) + IMPLICIT INTEGER*4 (A-Z) + INTEGER*2 LDA(32), CDA(32) + CHARACTER*(*) STMT + CHARACTER*(*) BVARV(8) + +* Arrays for bind variable info. + INTEGER BVARI(8), BVARL(8) + +* Scan the SQL statement for placeholders (:ph). +* Note that a placeholder must be terminated with +* a space, a comma, or a close parentheses. +* Two arrays are maintained: an array of starting +* indices in the string (BVARI), and an array of +* corresponding lengths (BVARL). + POS = 1 + DO 300 K = 1, 8 ! maximum of 8 per statement + I = INDEX(STMT(POS:), ':') + IF (I .EQ. 0) GO TO 400 + POS = I + POS - 1 + BVARI(K) = POS + DO 100 J = POS, LEN(STMT) + IF (STMT(J:J) .EQ. ' ' + + .OR. STMT(J:J) .EQ. ',' + + .OR. STMT(J:J) .EQ. ')') THEN + BVARL(K) = J - POS + GO TO 200 + ENDIF +100 CONTINUE + +200 POS = POS + 1 ! index past the ':' +300 CONTINUE + +400 N = K - 1 ! N is the number of BVs + + DO 500 K = 1, N + CALL OBNDRV(CDA, STMT(BVARI(K) :), BVARL(K), + + BVARV(K), 20, 1,-1,0,0,-1,-1) + IF (CDA(7) .NE. 0) THEN + CALL ERRRPT(LDA, CDA) + N = -1 + RETURN + ENDIF + WRITE (*, '( A, A, A)') 'Enter value for ', + + STMT(BVARI(K)+1:BVARI(K)+BVARL(K)-1), ' --> ' + READ '(A)', BVARV(K) +500 CONTINUE + + RETURN + END + + +* Define output variables for queries. +* Returns the number of select-list items (N) +* and the names of the select-list items (COLNAM). +* A maximum of 8 select-list items is permitted. +* (Note that this program does not check if there +* are more, but a production-quality program +* must do this.) + + SUBROUTINE DEFINE(LDA, CDA, COLNAM, DBTYPE, DVARC, + + DVARI, DVARF, INDP, RLEN, RCODE, RV) + IMPLICIT INTEGER*4 (A-Z) + INTEGER*2 LDA(32), CDA(32), DBTYPE(8) + INTEGER*2 RLEN(8), RCODE(8), INDP(8) + CHARACTER*(*) DVARC(8), COLNAM(8) + INTEGER DVARI(8), RV + REAL*4 DVARF(8) + + INTEGER DBSIZE(8), COLNML(8), DSIZE(8) + INTEGER*2 PREC(8), SCALE(8), NOK(8) + +* If not a query (SQL function code .ne. 4), return. + IF (CDA(2) .NE. 4) THEN + RV = 0 + RETURN + ENDIF + +* Describe the select-list (up to 8 items max), +* and define an output variable for each item, with the +* external (hence, FORTRAN) type depending on the +* internal ORACLE type, and its attributes. + + DO 100 N = 1, 8 + COLNML(N) = 10 ! COL length must be set on the call + CALL ODESCR(CDA, N, DBSIZE(N), DBTYPE(N), + + COLNAM(N), COLNML(N), DSIZE(N), + + PREC(N), SCALE(N), NOK(N)) + +* If the return code from ODESCR is 1007, then you have +* reached the end of the select list. + IF (CDA(7) .EQ. 1007) THEN + GO TO 200 +* Otherwise, if the return code is non-zero, an +* error occurred. Exit the subroutine, signalling +* an error. + ELSE IF (CDA(7) .NE. 0) THEN + CALL ERRRPT(LDA, CDA) + RV = -1 ! Error on return + RETURN + ENDIF + +* Check the datatype of the described item. If it's a +* NUMBER, check if the SCALE is 0. If so, define the +* output variable as INTEGER (3). If it's NUMBER with SCALE != 0, +* define the output variable as REAL (4). Otherwise, +* it's assumed to be a DATE, LONG, CHAR, or VARCHAR2, +* so define the output as 1 (VARCHAR2). + + IF (DBTYPE(N) .EQ. 2) THEN + IF (SCALE(N) .EQ. 0) THEN + DBTYPE(N) = 3 + ELSE + DBTYPE(N) = 4 + ENDIF + ELSE + DBTYPE(N) = 1 + ENDIF + +* Define the output variable. Do not define RLEN if +* the external datatype is 1. + IF (DBTYPE(N) .EQ. 3) THEN + CALL ODEFIN(CDA, N, DVARI(N), 4, 3, 0, INDP(N), + + FMT, 0, 0, RLEN(N), RCODE(N)) + ELSE IF (DBTYPE(N) .EQ. 4) THEN + CALL ODEFIN(CDA, N, DVARF(N), 4, 4, 0, INDP(N), + + FMT, 0, 0, RLEN(N), RCODE(N)) + ELSE + CALL ODEFIN(CDA, N, DVARC(N), 10, 1, 0, INDP(N), + + FMT, 0, 0, %VAL(-1), RCODE(N)) + ENDIF + IF (CDA(7) .NE. 0) THEN + CALL ERRRPT(LDA, CDA) + RV = -1 + RETURN + ENDIF +100 CONTINUE + +200 RV = N - 1 ! Decrement to get correct count + + RETURN + END + + +* FETCHN uses OFETCH to fetch the rows that satisfy +* the query, and displays the output. The data is +* fetched 1 row at a time. + + SUBROUTINE FETCHN(LDA, CDA, NAMES, NOV, DBTYPE, DVARC, + + DVARI, DVARF, INDP, RV) + IMPLICIT INTEGER*4 (A-Z) + INTEGER*2 LDA(32), CDA(32), DBTYPE(8), INDP(8) + CHARACTER*(*) NAMES(8), DVARC(8) + INTEGER DVARI(8), NOV, RV + REAL*4 DVARF(8) + + IF (CDA(2) .NE. 4) THEN ! not a query + RV = 0 + RETURN + ENDIF + + DO 50 COL = 1, NOV + IF (DBTYPE(COL) .EQ. 1) THEN + WRITE (*, 900) NAMES(COL), ' ' +900 FORMAT ('+', A10, A1, $) + ELSE + WRITE (*, 902) NAMES(COL), ' ' +902 FORMAT ('+', A8, A1, $) + ENDIF +50 CONTINUE + + WRITE (*, '(1X, A, /)') '------------------------------ + +-----------------------------------------------' + + DO 200 NROWS = 1, 10000 + CALL OFETCH(CDA) + IF (CDA(7) .EQ. 1403) GO TO 300 + IF (CDA(7) .NE. 0 .AND. CDA(7) .NE. 1406) THEN + CALL ERRRPT(LDA, CDA) + RV = -1 + RETURN + ENDIF + DO 100 COL = 1, NOV + IF (INDP(COL) .LT. 0 .AND. DBTYPE(COL) .NE. 1) THEN + WRITE (*, 903), ' ' +903 FORMAT ('+', A9, $) + ELSE IF (INDP(COL) .LT. 0 .AND. DBTYPE(COL) .EQ. 1) THEN + WRITE (*, 905), ' ' +905 FORMAT ('+', A11, $) + ELSE + IF (DBTYPE(COL) .EQ. 3) THEN + WRITE (*, 904) DVARI(COL), ' ' +904 FORMAT ('+', I6, A3, $) + ELSE IF (DBTYPE(COL) .EQ. 4) THEN + WRITE (*, 906) DVARF(COL), ' ' +906 FORMAT ('+', F8.2, A1, $) + ELSE + WRITE (*, 908) DVARC(COL), ' ' +908 FORMAT ('+', A10, A1, $) + ENDIF + ENDIF +100 CONTINUE + WRITE (*, '(1X)') +200 CONTINUE + +300 NROWS = NROWS - 1 + WRITE (*, '(/, 1X, I3, A)') NROWS, ' rows returned' + + RETURN + END + + + + SUBROUTINE ERRRPT(LDA, CDA) + INTEGER*2 LDA(32), CDA(32) + + CHARACTER*132 MSG + + MSG = ' ' + IF (LDA(7) .NE. 0) THEN + CDA(7) = LDA(7) + CDA(6) = 0 + ENDIF + + IF (CDA(6) .NE. 0) THEN + WRITE (*, '(1X, A, I3)') 'Error processing OCI function', + + CDA(6) + ENDIF + + CALL OERHMS (LDA, CDA(7), MSG, 132) + WRITE (*, '(1X, A)') MSG + + RETURN + END + + + INTEGER FUNCTION LEN_TRIM(STRING) + CHARACTER*(*) STRING + + INTEGER NEXT + + DO 10 NEXT = LEN(STRING), 1, -1 + IF (STRING(NEXT : NEXT) .NE. ' ') THEN + LEN_TRIM = NEXT + RETURN + ENDIF +10 CONTINUE + + LEN_TRIM = 0 + + RETURN + END + diff --git a/fdemo3.for b/fdemo3.for new file mode 100644 index 0000000..fa09691 --- /dev/null +++ b/fdemo3.for @@ -0,0 +1,285 @@ +C +C $Header: fdemo3.for 14-jul-99.13:44:03 mjaeger Exp $ +C +C Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +C +C NAME +C fdemo3.for - Fortran demo program # 3 +C MODIFIED (MM/DD/YY) +C mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +C plocke 11/14/95 - to update for v7.3 +C lchidamb 05/16/95 - merge changes from branch 1.1.720.1 +C sjain 03/16/92 - Creation + +* FDEMO3.FOR +* OCI FORTRAN Sample Program 3 +* +* Demonstrates using the OFLNG routine to retrieve +* part of a LONG RAW column +* +* This example "plays" a digitized voice message +* by repeatedly extracting 64 kB chunks of the message +* from the row in the table, and sending them to a +* converter buffer (for example, a Digital-to-Analog +* Converter (DAC) FIFO buffer). +* +* The hardware-specific DAC routine is merely simulated +* in this example. + + PROGRAM FDEMO3 + IMPLICIT INTEGER(A-Z) + +* Connect and Cursor Data Structures + + INTEGER*2 CDA(32) + INTEGER*2 LDA(32) + INTEGER*2 HDA(256) + +* Program Variables + + CHARACTER*132 SQLSTM + CHARACTER*20 UID, PWD + INTEGER MSGID, MSGLEN + INTEGER*2 INDP, RLEN, RCODE + INTEGER RETL + BYTE DBIN(200000) + CHARACTER*6 FMT + INTEGER*4 NOBLOK + +* Connect to ORACLE in non-blocking mode. +* The HDA must be initialized to all zeros before calling OLOG. + UID = 'SCOTT' + PWD = 'TIGER' + DATA HDA/256*0/ + + CALL OLOG(LDA, HDA, UID, LEN_TRIM(UID), + + PWD, LEN_TRIM(PWD), 0, -1, NOBLOK) + IF (LDA(1) .NE. 0) THEN + WRITE (*, '(1X, A)') 'Cannot connect as scott/tiger...' + WRITE (*, '(1X, A)') 'Application terminating...' + GOTO 999 + END IF + +* Open the cursor. (Use UID as a dummy parameter--it +* won't be looked at.) + CALL OOPEN(CDA, LDA, UID, 0, 0, UID, 0) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(CDA) + GOTO 900 + END IF + +* Drop the old table. + WRITE (*, '( A)') 'OK to drop table VOICE_MAIL (Y or N)? : ' + READ '(A)', FMT + IF (FMT(1:1) .EQ. 'y' .OR. FMT(1:1) .EQ. 'Y') THEN + GO TO 10 + ELSE + GO TO 900 + ENDIF + +* Parse the DROP TABLE statement. +10 SQLSTM = 'DROP TABLE VOICE_MAIL' + CALL OPARSE(CDA, SQLSTM, LEN_TRIM(SQLSTM), 0, 2) + IF (CDA(7) .EQ. 0) THEN + WRITE (*, '(1X, A)') 'Table VOICE_MAIL dropped.' + ELSEIF (CDA(7) .EQ. 942) THEN + WRITE (*, '(1X, A)') 'Table did not exist.' + ELSE + CALL ERRPT(LDA, CDA) + GO TO 900 + ENDIF + +* Create new table. Parse with DEFFLG set to zero, +* to immediately execute the DDL statement. The LNGFLG +* is set to 2 (Version 7). + + SQLSTM = 'CREATE TABLE VOICE_MAIL + + (MSG_ID NUMBER(6), MSG_LEN NUMBER(12), MSG LONG RAW)' + +* Parse the statement. Do not defer the parse, so that the +* DDL statement is executed immediately. + CALL OPARSE(CDA, SQLSTM, LEN_TRIM(SQLSTM), 0, 2) + IF (CDA(7) .EQ. 0) THEN + WRITE (*, '(1X, A)') 'Created table VOICE_MAIL.' + ELSE + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + +* Insert some dummy data into the table. + SQLSTM = 'INSERT INTO VOICE_MAIL VALUES (:1, :2, :3)' + CALL OPARSE(CDA, SQLSTM, LEN_TRIM(SQLSTM), 1, 2) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + +* Do the binds for the input data to set values +* in the new table. + INDP = 0 + CALL OBNDRN(CDA, 1, MSGID, 4, 3, 0, INDP, FMT, 0, 0) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + + CALL OBNDRN(CDA, 2, MSGLEN, 4, 3, 0, INDP, FMT, 0, 0) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + + CALL OBNDRN(CDA, 3, DBIN, 200000, 24, 0, INDP, FMT, 0, 0) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + +* Fill the input buffer with some dummy data. + MSGID = 100 + MSGLEN = 200000 + DO 100 I = 1, 200000 +100 DBIN(I) = 42 + +* Execute the statement to INSERT the data + WRITE (*, '(1X, A)') 'Inserting data into the table.' + CALL OEXN(CDA, 1, 0) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + +* Do the selects. First position the cursor at the +* proper row, using the MSG_ID. Then fetch the data +* in 64K chunks, using OFLNG. + SQLSTM = 'SELECT MSG_ID, MSG_LEN, MSG + + FROM VOICE_MAIL WHERE MSG_ID = 100' + + CALL OPARSE(CDA, SQLSTM, LEN_TRIM(SQLSTM), 1, 2) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + +* Define the output variables for the SELECT. + CALL ODEFIN(CDA, 1, MSGID, 4, 3, 0, %VAL(-1), %VAL(-1), + + 0, 0, %VAL(-1), %VAL(-1)) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + + CALL ODEFIN(CDA, 2, MSGLEN, 4, 3, 0, %VAL(-1), %VAL(-1), + + 0, 0, %VAL(-1), %VAL(-1)) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + + CALL ODEFIN(CDA, 3, DBIN, 200000, 24, 0, INDP, %VAL(-1), + + 0, 0, RLEN, RCODE) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + +* Do the query, getting the MSG_ID to position the cursor, and +* the first 100 bytes of the message. +* CANCEL and EXACT are FALSE. + CALL OEXFET(CDA, 1, 0, 0) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + + WRITE (*, '(1X, A, I4, A)') 'Message', MSGID, + +' is available.' + WRITE (*, '(1X, A, I7, A)') 'The length is', MSGLEN, + +' bytes.' + +* Play out the message, calling the DAC routine for each +* 64K chunk fetched by OFLNG. + + OFFSET = 0 + N = MSGLEN/65536 + 1 + DO 200 J = 1, N + IF (MSGLEN .LT. 65536) THEN + LEN = MSGLEN + ELSE + LEN = 65536 + ENDIF + CALL OFLNG(CDA, 3, DBIN, LEN, 24, RETL, OFFSET) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + ENDIF + CALL PLAYMSG(DBIN, LEN) + MSGLEN = MSGLEN - LEN + IF (MSGLEN .LT. 0) GO TO 900 +200 CONTINUE + +900 CALL OCLOSE(CDA) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + CALL OLOGOF(LDA) + IF (LDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + +999 STOP 'End of OCIDEMO3.' + END + + SUBROUTINE PLAYMSG(OUT, LEN) + BYTE OUT(65536) + INTEGER LEN + + WRITE (*, '(1X, A, I7, A)') 'Playing', LEN, ' bytes.' + RETURN + END + + + SUBROUTINE ERRPT(LDA, CDA) + INTEGER*2 LDA(32), CDA(32) + + CHARACTER*132 MSG + + MSG = ' ' + IF (LDA(7) .NE. 0) THEN + CDA(7) = LDA(7) + CDA(6) = 0 + ENDIF + + IF (CDA(6) .NE. 0) THEN + WRITE (*, '(1X, A, I3)') 'Error processing OCI function', + + CDA(6) + ENDIF + + CALL OERHMS (LDA, CDA(7), MSG, 132) + WRITE (*, '(1X, A)') MSG + + RETURN + END + + + + INTEGER FUNCTION LEN_TRIM(STRING) + CHARACTER*(*) STRING + + INTEGER NEXT + + DO 10 NEXT = LEN(STRING), 1, -1 + IF (STRING(NEXT : NEXT) .NE. ' ') THEN + LEN_TRIM = NEXT + RETURN + ENDIF +10 CONTINUE + + LEN_TRIM = 0 + + RETURN + END + + diff --git a/fgacdemo.sql b/fgacdemo.sql new file mode 100644 index 0000000..9217e92 --- /dev/null +++ b/fgacdemo.sql @@ -0,0 +1,587 @@ +rem +rem $Header: fgacdemo.sql 09-may-2003.13:35:57 rvissapr Exp $ +rem +rem Copyright (c) 1999, 2003, Oracle Corporation. All rights reserved. +rem +rem NAME +rem fgacdemo.sql - Build Oracle8i Security Demonstration Tables/Users +rem DESCRIPTION +rem This SQL script builds Oracle8i Security demonstration tables/user +rem MODIFIED (MM/DD/YY) +rem rvissapr 05/09/03 - remove temporary tablespace clause +rem rvissapr 01/08/03 - bug 2368367 +rem dmwong 03/08/00 - remove MURRAY . +rem dmwong 01/05/00 - merge the split line +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + +rem This script builds a database that enforces security based on +rem server enforced security using fine grain access control and application +rem context. Appropriate security context is setup using application +rem context and fine grain access control enforces data access control using +rem these secure application context. + +rem ======================================================================== +rem First clean up previous installs +rem ======================================================================== + +CONNECT SYSTEM/MANAGER +DROP TRIGGER SECDEMO.SET_EXPENSE_CTX ; +DROP USER MOREAU; +DROP USER MILLER; + +DROP USER SECDEMO CASCADE; +DROP CONTEXT expenses_reporting; + +rem ======================================================================== +rem Then create users for the demo (you may want to customize tablespaces) +rem ======================================================================== + +CREATE USER "SECDEMO" IDENTIFIED BY "SECDEMO" +DEFAULT TABLESPACE "SYSTEM" +PROFILE DEFAULT +QUOTA UNLIMITED ON "SYSTEM" ACCOUNT UNLOCK; + +GRANT CONNECT TO SECDEMO; +GRANT CREATE ANY CONTEXT TO SECDEMO; +GRANT CREATE ANY SYNONYM TO SECDEMO; +GRANT CREATE TRIGGER TO "SECDEMO"; +GRANT CREATE PROCEDURE TO SECDEMO; +GRANT "EXECUTE_CATALOG_ROLE" TO "SECDEMO"; +ALTER USER "SECDEMO" DEFAULT ROLE ALL; + + +CREATE USER "MOREAU" IDENTIFIED BY "MOREAU" +DEFAULT TABLESPACE "SYSTEM" +PROFILE DEFAULT +QUOTA UNLIMITED ON "SYSTEM" ACCOUNT UNLOCK; +GRANT CONNECT TO MOREAU; + + +CREATE USER "MILLER" IDENTIFIED BY "MILLER" +DEFAULT TABLESPACE "SYSTEM" +PROFILE DEFAULT +QUOTA UNLIMITED ON "SYSTEM" ACCOUNT UNLOCK; +GRANT CONNECT TO MILLER; + + +GRANT "EXECUTE_CATALOG_ROLE" TO "MOREAU"; +ALTER USER "MOREAU" DEFAULT ROLE ALL; +GRANT "EXECUTE_CATALOG_ROLE" TO "MILLER"; +ALTER USER "MILLER" DEFAULT ROLE ALL; + +CREATE PUBLIC SYNONYM exprep_ctx FOR secdemo.exprep_ctx; + +rem ======================================================================== +rem Now Create the tables/views for the demo +rem ======================================================================== + +CONNECT SECDEMO/SECDEMO + +rem Create new datasources + +CREATE TABLE EMPLOYEE ( + EMPLOYEE_ID NUMBER(4), + LAST_NAME VARCHAR2(15), + FIRST_NAME VARCHAR2(15), + MIDDLE_INITIAL VARCHAR2(1), + COST_CENTER_ID NUMBER(4), + MANAGER_ID NUMBER(4)); + +CREATE TABLE COST_CENTER ( + COST_CENTER_ID NUMBER(4), + MANAGER_ID NUMBER(4), + DESCRIPTION VARCHAR2(30)); + +CREATE TABLE EXP_REPORT ( + REPORT_ID NUMBER(4), + EMPLOYEE_ID NUMBER(4), + COST_CENTER_ID NUMBER(4), + SUBMISSION_DATE DATE, + APPROVAL_DATE DATE, + PURPOSE VARCHAR2(30)); + +CREATE TABLE EXP_LINE ( + REPORT_ID NUMBER(4), + LINE_ID NUMBER(4), + TYPE_ID NUMBER(4), + RECEIVED_AMOUNT NUMBER(7,2), + RECEIPT NUMBER(1), + EXP_DATE DATE, + CURRENCY_ID NUMBER(4)); + +CREATE TABLE EXP_TYPE ( + TYPE_ID NUMBER(4), + DESCRIPTION VARCHAR2(30)); + +CREATE TABLE EXP_CURRENCY ( + CURRENCY_ID NUMBER(4), + DESCRIPTION VARCHAR2(30), + RATE NUMBER(7,2), + SYMBOL VARCHAR2(2)); + +rem Add views + +DROP VIEW EXP_REPORT_SUM_VIEW; + +CREATE VIEW EXP_REPORT_SUM_VIEW AS +SELECT E.EMPLOYEE_ID,E.LAST_NAME,R.REPORT_ID, R.PURPOSE, + SUM(L.RECEIVED_AMOUNT) TOTAL_AMOUNT, R.COST_CENTER_ID, + R.SUBMISSION_DATE,R.APPROVAL_DATE +FROM EMPLOYEE E,EXP_REPORT R, EXP_LINE L +WHERE E.EMPLOYEE_ID=R.EMPLOYEE_ID +AND R.REPORT_ID=L.REPORT_ID +GROUP BY E.EMPLOYEE_ID,R.REPORT_ID,E.LAST_NAME, R.PURPOSE, R.COST_CENTER_ID, + R.SUBMISSION_DATE,R.APPROVAL_DATE; + + +rem Grant SELECT privileges to PUBLIC on the datasources + +GRANT SELECT ON EMPLOYEE TO PUBLIC; +GRANT SELECT ON COST_CENTER TO PUBLIC; +GRANT SELECT ON EXP_REPORT TO PUBLIC; +GRANT SELECT ON EXP_LINE TO PUBLIC; +GRANT SELECT ON EXP_TYPE TO PUBLIC; +GRANT SELECT ON EXP_CURRENCY TO PUBLIC; +GRANT SELECT ON EXP_REPORT_SUM_VIEW TO PUBLIC; + +GRANT UPDATE ON EXP_REPORT TO PUBLIC; +GRANT DELETE ON EXP_REPORT TO PUBLIC; +GRANT INSERT ON EXP_REPORT TO PUBLIC; +GRANT DELETE ON EXP_LINE TO PUBLIC; +GRANT INSERT ON EXP_LINE TO PUBLIC; + + +rem Insert Data + +INSERT INTO EXP_CURRENCY VALUES (1, '$ US DOLLAR',1.0,'$'); +INSERT INTO EXP_CURRENCY VALUES (2, 'FF - FRENCH FRANC',0.2,'FF'); +INSERT INTO EXP_CURRENCY VALUES (3, '£ - UK POUNDS',2.0,'£'); +INSERT INTO EXP_CURRENCY VALUES (4, 'DM - DEUTCH MARKS',0.6,'DM'); + +INSERT INTO EXP_TYPE VALUES (1, 'AIRFARE'); +INSERT INTO EXP_TYPE VALUES (2, 'TAXI'); +INSERT INTO EXP_TYPE VALUES (3, 'RENTAL CAR'); +INSERT INTO EXP_TYPE VALUES (4, 'LIMO/CAR SERVICE'); +INSERT INTO EXP_TYPE VALUES (5, 'ROOM'); +INSERT INTO EXP_TYPE VALUES (6, 'FOOD/DRINKS ON HOTEL BILL'); +INSERT INTO EXP_TYPE VALUES (7, 'PHONE/OTHER ON HOTEL BILL'); +INSERT INTO EXP_TYPE VALUES (8, 'BREAKFAST'); +INSERT INTO EXP_TYPE VALUES (9, 'LUNCH'); +INSERT INTO EXP_TYPE VALUES (10, 'DINNER'); + +INSERT INTO COST_CENTER VALUES (692, 7839, 'ADMINISTRATION'); +INSERT INTO COST_CENTER VALUES (672, 7839, 'US SALES'); +INSERT INTO COST_CENTER VALUES (667,7506, 'ASIAN SALES'); +INSERT INTO COST_CENTER VALUES (670,7569, 'EUROPEAN SALES'); +INSERT INTO COST_CENTER VALUES (668,7507, 'WW SUPPORT'); +INSERT INTO COST_CENTER VALUES (671,7839, 'WW MARKETING'); +INSERT INTO COST_CENTER VALUES (673, 7505, 'US MARKETING'); +INSERT INTO COST_CENTER VALUES (674, 7698, 'ASIAN MARKETING'); +INSERT INTO COST_CENTER VALUES (669, 7566, 'EUROPEAN MARKETING'); + + +INSERT INTO EMPLOYEE VALUES + (7369,'SMITH','JOHN','Q',667,7902); +INSERT INTO EMPLOYEE VALUES + (7499,'ALLEN','KEVIN','J',670,7698); +INSERT INTO EMPLOYEE VALUES + (7505,'DOYLE','JEAN','K',671,7839); +INSERT INTO EMPLOYEE VALUES + (7506,'DENNIS','LYNN','S',671,7839); +INSERT INTO EMPLOYEE VALUES + (7507,'BAKER','LESLIE','D',671,7839); +INSERT INTO EMPLOYEE VALUES + (7521,'WARD','CYNTHIA','D',670,7698); +INSERT INTO EMPLOYEE VALUES + (7555,'PETERS','DANIEL','T',670,7505); +INSERT INTO EMPLOYEE VALUES + (7557,'SHAW','KAREN','P',670,7505); +INSERT INTO EMPLOYEE VALUES + (7560,'DUNCAN','SARAH','S',670,7506); +INSERT INTO EMPLOYEE VALUES + (7564,'LANGE','GREGORY','J',670,7506); +INSERT INTO EMPLOYEE VALUES + (7566,'JONES','TERRY','M',671,7839); +INSERT INTO EMPLOYEE VALUES + (7569,'MOREAU','ALBERT','L',670,7839); +INSERT INTO EMPLOYEE VALUES + (7600,'PORTER','RAYMOND','Y',670,7505); +INSERT INTO EMPLOYEE VALUES + (7609,'LEWIS','RICHARD','M',668,7507); +INSERT INTO EMPLOYEE VALUES + (7654,'MARTIN','KENNETH','J',670,7698); +INSERT INTO EMPLOYEE VALUES + (7676,'SOMMERS','DENISE','D',668,7507); +INSERT INTO EMPLOYEE VALUES + (7698,'JURGEN','DIETER','S',670,7839); +INSERT INTO EMPLOYEE VALUES + (7782,'CLARK','CAROL','F',671,7839); +INSERT INTO EMPLOYEE VALUES + (7788,'SCOTT','DONALD','T',669,7566); +INSERT INTO EMPLOYEE VALUES + (7789,'WEST','LIVIA','N',670,7506); +INSERT INTO EMPLOYEE VALUES + (7799,'FISHER','MATTHEW','G',669,7569); +INSERT INTO EMPLOYEE VALUES + (7820,'ROSS','PAUL','S',670,7505); +INSERT INTO EMPLOYEE VALUES + (7839,'KING','FRANCIS','A',672,7839); +INSERT INTO EMPLOYEE VALUES + (7844,'TURNER','MARY','A',670,7698); +INSERT INTO EMPLOYEE VALUES + (7876,'ADAMS','DIANE','G',667,7788); +INSERT INTO EMPLOYEE VALUES + (7900,'JAMES','FRED','S',667,7698); +INSERT INTO EMPLOYEE VALUES + (7902,'FORD','JENNIFER','D',669,7566); +INSERT INTO EMPLOYEE VALUES + (7916,'ROBERTS','GRACE','M',669,7569); +INSERT INTO EMPLOYEE VALUES + (7919,'DOUGLAS','MICHAEL','A',667,7799); +INSERT INTO EMPLOYEE VALUES + (7934,'MILLER','BARBARA','M',670,7782); +INSERT INTO EMPLOYEE VALUES + (7950,'JENSEN','ALICE','B',667,7505); +INSERT INTO EMPLOYEE VALUES + (7954,'MURRAY','JAMES','T',670,7506); + + +INSERT INTO EXP_REPORT VALUES + (1,7954,667,SYSDATE-3,SYSDATE,'Customer Visit'); + +INSERT INTO EXP_REPORT VALUES + (2,7950,670,SYSDATE,NULL,'Customer Visit'); +INSERT INTO EXP_REPORT VALUES + (3,7954,670,SYSDATE,NULL,'Customer Visit'); +INSERT INTO EXP_REPORT VALUES + (4,7954,671,SYSDATE,NULL,'Customer Visit'); +INSERT INTO EXP_REPORT VALUES + (5,7934,670,SYSDATE-1,NULL,'Training '); +INSERT INTO EXP_REPORT VALUES + (6,7698,670,SYSDATE-7,NULL,'Training '); +INSERT INTO EXP_REPORT VALUES + (7,7698,670,SYSDATE-7,NULL,'Customer Visit '); +INSERT INTO EXP_REPORT VALUES + (8,7934,671,SYSDATE-7,NULL,'Training '); +INSERT INTO EXP_REPORT VALUES + (9,7934,670,SYSDATE-7,NULL,'Training '); +INSERT INTO EXP_REPORT VALUES + (10,7954,670,SYSDATE-20,SYSDATE-20,'Customer Visit'); +INSERT INTO EXP_REPORT VALUES + (11,7954,670,SYSDATE-20,SYSDATE-17,'Customer Visit'); +INSERT INTO EXP_REPORT VALUES + (12,7569,670,SYSDATE-22,SYSDATE-19,'Customer Visit'); + + +INSERT INTO EXP_LINE VALUES + (1,1,1,500.2,1,SYSDATE-33,1); +INSERT INTO EXP_LINE VALUES + (1,2,8,12.2,1,SYSDATE-33,1); +INSERT INTO EXP_LINE VALUES + (1,3,9,20.0,1,SYSDATE-33,1); +INSERT INTO EXP_LINE VALUES + (2,1,2,21.0,1,SYSDATE-23,1); +INSERT INTO EXP_LINE VALUES + (2,2,5,200.0,1,SYSDATE-23,1); +INSERT INTO EXP_LINE VALUES + (2,3,9,12.0,1,SYSDATE-23,1); +INSERT INTO EXP_LINE VALUES + (2,4,10,20.0,1,SYSDATE-23,1); +INSERT INTO EXP_LINE VALUES + (3,1,9,10.2,1,SYSDATE-33,1); +INSERT INTO EXP_LINE VALUES + (4,1,5,210.3,1,SYSDATE-31,1); +INSERT INTO EXP_LINE VALUES + (4,2,6,21.0,1,SYSDATE-31,1); +INSERT INTO EXP_LINE VALUES + (4,3,7,12.1,1,SYSDATE-31,1); +INSERT INTO EXP_LINE VALUES + (4,4,8,10.3,1,SYSDATE-31,1); +INSERT INTO EXP_LINE VALUES + (5,1,10,53.2,1,SYSDATE-28,1); +INSERT INTO EXP_LINE VALUES + (6,1,10,23.2,1,SYSDATE-44,2); +INSERT INTO EXP_LINE VALUES + (7,1,5,210.3,1,SYSDATE-28,1); +INSERT INTO EXP_LINE VALUES + (7,2,6,21.0,1,SYSDATE-28,1); +INSERT INTO EXP_LINE VALUES + (7,3,7,12.1,1,SYSDATE-28,1); +INSERT INTO EXP_LINE VALUES + (7,4,8,10.3,1,SYSDATE-28,1); +INSERT INTO EXP_LINE VALUES + (8,1,5,1120.3,1,SYSDATE-27,3); +INSERT INTO EXP_LINE VALUES + (8,2,6,20.0,1,SYSDATE-27,3); +INSERT INTO EXP_LINE VALUES + (8,3,7,17.1,1,SYSDATE-27,3); +INSERT INTO EXP_LINE VALUES + (8,4,8,20.3,1,SYSDATE-27,3); + +INSERT INTO EXP_LINE VALUES + (9,1,5,1120.3,1,SYSDATE-20,3); +INSERT INTO EXP_LINE VALUES + (9,2,6,20.0,1,SYSDATE-20,3); +INSERT INTO EXP_LINE VALUES + (9,3,7,17.1,1,SYSDATE-20,3); +INSERT INTO EXP_LINE VALUES + (9,4,8,20.3,1,SYSDATE-20,3); +INSERT INTO EXP_LINE VALUES + (9,5,5,1120.3,1,SYSDATE-20,3); +INSERT INTO EXP_LINE VALUES + (9,6,6,20.0,1,SYSDATE-20,3); + +INSERT INTO EXP_LINE VALUES + (10,1,5,1120.3,1,SYSDATE-45,1); +INSERT INTO EXP_LINE VALUES + (11,1,5,1120.3,1,SYSDATE-38,1); +INSERT INTO EXP_LINE VALUES + (12,1,5,1120.3,1,SYSDATE-38,2); +INSERT INTO EXP_LINE VALUES + (12,2,5,1120.3,1,SYSDATE-38,2); + + +rem Create indexes + +CREATE UNIQUE INDEX I_EMPLOYEE$EMPLOYEE_ID ON EMPLOYEE (EMPLOYEE_ID); +CREATE UNIQUE INDEX I_COST_CENTER$COST_CENTER_ID + ON COST_CENTER (COST_CENTER_ID); +CREATE UNIQUE INDEX I_EXP_REPORT$REPORT_ID ON EXP_REPORT (REPORT_ID); +CREATE UNIQUE INDEX I_EXP_LINE ON EXP_LINE (REPORT_ID,LINE_ID); +CREATE UNIQUE INDEX I_EXP_TYPE$TYPE_ID ON EXP_TYPE (TYPE_ID); +CREATE UNIQUE INDEX I_EXP_CURRENCY$CURRENCY_ID ON EXP_CURRENCY (CURRENCY_ID); + +rem Add constraints + +ALTER TABLE EMPLOYEE ADD + CHECK (EMPLOYEE_ID IS NOT NULL); + +ALTER TABLE EXP_REPORT ADD + CHECK (REPORT_ID IS NOT NULL); +ALTER TABLE EXP_REPORT ADD + CHECK (EMPLOYEE_ID IS NOT NULL); +ALTER TABLE EXP_REPORT ADD + CHECK (COST_CENTER_ID IS NOT NULL); + +rem PK +ALTER TABLE EMPLOYEE ADD + PRIMARY KEY (EMPLOYEE_ID); +ALTER TABLE COST_CENTER ADD + PRIMARY KEY (COST_CENTER_ID); +ALTER TABLE EXP_REPORT ADD + PRIMARY KEY (REPORT_ID); +ALTER TABLE EXP_LINE ADD + PRIMARY KEY (REPORT_ID,LINE_ID); +ALTER TABLE EXP_TYPE ADD + PRIMARY KEY (TYPE_ID); +ALTER TABLE EXP_CURRENCY ADD + PRIMARY KEY (CURRENCY_ID); + +rem FK +ALTER TABLE EMPLOYEE ADD + FOREIGN KEY (COST_CENTER_ID) REFERENCES COST_CENTER; +ALTER TABLE EMPLOYEE ADD + FOREIGN KEY (MANAGER_ID) REFERENCES EMPLOYEE; +ALTER TABLE EXP_REPORT ADD + FOREIGN KEY (EMPLOYEE_ID) REFERENCES EMPLOYEE; +ALTER TABLE EXP_REPORT ADD + FOREIGN KEY (COST_CENTER_ID) REFERENCES COST_CENTER; +ALTER TABLE EXP_LINE ADD + FOREIGN KEY (REPORT_ID) REFERENCES EXP_REPORT; +ALTER TABLE EXP_LINE ADD + FOREIGN KEY (TYPE_ID) REFERENCES EXP_TYPE; +ALTER TABLE EXP_LINE ADD + FOREIGN KEY (CURRENCY_ID) REFERENCES EXP_CURRENCY; + + + +rem ======================================================================== +rem Now setting Oracle8i Security features +rem ======================================================================== + +rem ================================================================= +rem Creation of the application context +rem ================================================================= +rem +rem SECDEMO User must have the CREATE ANY CONTEXT system privilege +rem + +CONNECT SECDEMO/SECDEMO + +CREATE CONTEXT expenses_reporting USING secdemo.exprep_ctx; + +rem ================================================================= +rem Creation of the package witch implements the context +rem ================================================================= + +CREATE OR REPLACE PACKAGE exprep_ctx AS + PROCEDURE set_ctx; +END; +/ +SHOW ERRORS + +CREATE OR REPLACE PACKAGE BODY exprep_ctx IS + + PROCEDURE set_ctx IS + empnum number; + countrec number; + cc number; + + role varchar2(20); + BEGIN + + -- SET emp_number + select EMPLOYEE_ID into empnum from employee + where last_name = sys_context('userenv', 'session_user'); + + dbms_session.set_context('expenses_reporting','emp_number', empnum); + + -- SET ROLE ? + select count(*) into countrec from cost_center where manager_id=empnum; + IF (countrec > 0) THEN + dbms_session.set_context('expenses_reporting','exp_role', 'MANAGER'); + ELSE + dbms_session.set_context('expenses_reporting','exp_role', 'EMPLOYEE'); + END IF; + + -- SET cc_number + select COST_CENTER_ID into cc from employee + where last_name = sys_context('userenv', 'session_user'); + dbms_session.set_context('expenses_reporting','cc_number', cc); + + + END; +END; +/ +SHOW ERRORS +/ +rem CREATE PUBLIC SYNONYM exprep_ctx FOR secdemo.exprep_ctx; +GRANT EXECUTE ON secdemo.exprep_ctx TO public; +/ + +rem ================================================================= +rem Creation of the policy function +rem ================================================================= + +CREATE OR REPLACE PACKAGE exp_security AS + FUNCTION empview_sec(owner varchar2, objname varchar2) RETURN varchar2; + FUNCTION empnum_sec(owner varchar2, objname varchar2) RETURN varchar2; + FUNCTION empnumline_sec(owner varchar2, objname varchar2) RETURN varchar2; + FUNCTION ccid_mgr_sec(owner varchar2, objname varchar2) RETURN varchar2; + +END exp_security; +/ +SHOW ERRORS + +CREATE OR REPLACE PACKAGE BODY exp_security IS + + FUNCTION empview_sec(owner varchar2, objname varchar2) RETURN varchar2 IS + predicate varchar2(2000); + BEGIN + + IF (sys_context('expenses_reporting', 'exp_role') = 'MANAGER') THEN + predicate := + 'COST_CENTER_ID = sys_context(''expenses_reporting'',''cc_number'')'; + ELSE + predicate := + 'EMPLOYEE_ID = sys_context(''expenses_reporting'',''emp_number'')'; + END IF; + + RETURN predicate; + END empview_sec; + + FUNCTION empnum_sec(owner varchar2, objname varchar2) RETURN varchar2 IS + predicate varchar2(2000); + BEGIN + predicate := + 'EMPLOYEE_ID = sys_context(''expenses_reporting'',''emp_number'')'; + RETURN predicate; + END empnum_sec; + + FUNCTION empnumline_sec(owner varchar2, objname varchar2) RETURN varchar2 IS + predicate varchar2(2000); + BEGIN + predicate := 'REPORT_ID IN (SELECT REPORT_ID FROM EXP_REPORT WHERE \ + EMPLOYEE_ID = sys_context(''expenses_reporting'',''emp_number''))'; + RETURN predicate; + END empnumline_sec; + + FUNCTION ccid_mgr_sec(owner varchar2, objname varchar2) RETURN varchar2 IS + predicate varchar2(2000); + BEGIN + predicate := + 'COST_CENTER_ID = (SELECT COST_CENTER_ID FROM COST_CENTER WHERE \ + MANAGER_ID = sys_context(''expenses_reporting'',''emp_number''))'; + RETURN predicate; + END ccid_mgr_sec; + + +END; +/ +SHOW ERRORS + + +rem ================================================================= +rem Association of the policy function with a table or a view +rem ================================================================= +rem SELECT POLICY_NAME FROM ALL_POLICIES; + +rem POLICY #1 +rem YOU CAN SELECT ONLY YOUR REPORTS IF YOU ARE A EMPLOYEE +rem YOU CAN SELECT YOUR REPORTS AND ALL THE REPORT IN YOUR COST CENTER +rem IF YOU ARE THE COST CENTER MANAGER +EXECUTE DBMS_RLS.DROP_POLICY('secdemo','EXP_REPORT_SUM_VIEW', 'exp_report_VIEW_policy'); +EXECUTE DBMS_RLS.ADD_POLICY('secdemo','EXP_REPORT_SUM_VIEW', 'exp_report_VIEW_policy','secdemo','exp_security.empview_sec','SELECT'); + +rem POLICY #2 +rem YOU CAN DELETE YOUR REPORTS ONLY +EXECUTE DBMS_RLS.DROP_POLICY('secdemo','exp_report','exp_report_policy'); +EXECUTE DBMS_RLS.ADD_POLICY('secdemo','exp_report','exp_report_policy', 'secdemo','exp_security.empnum_sec','DELETE'); + +rem POLICY #2 +rem YOU CAN INSET A REPORT FOR YOURSELF ONLY +EXECUTE DBMS_RLS.DROP_POLICY('secdemo','exp_report', 'exp_report_insert_policy'); +EXECUTE DBMS_RLS.ADD_POLICY('secdemo','exp_report','exp_report_insert_policy', 'secdemo','exp_security.empnum_sec','INSERT'); + +rem POLICY #4 +rem YOU CAN DELETE A LINE IN YOUR REPORT ONLY +rem IF YOU ARE THE OWNER OF THE REPORT +EXECUTE DBMS_RLS.DROP_POLICY('secdemo','exp_line','exp_line_policy'); +EXECUTE DBMS_RLS.ADD_POLICY('secdemo','exp_line','exp_line_policy','secdemo', 'exp_security.empnumline_sec','DELETE'); + +rem POLICY #5 +rem YOU CAN APPROVE (UPDATE) AN REPORT ONLY +rem IF YOU ARE THE COST CENTER MANAGER +EXECUTE DBMS_RLS.DROP_POLICY('secdemo','exp_report', 'exp_report_Approve_policy'); +EXECUTE DBMS_RLS.ADD_POLICY('secdemo','exp_report', 'exp_report_Approve_policy','secdemo','exp_security.ccid_mgr_sec','UPDATE'); + +rem LIST ALL POLICIES +SELECT POLICY_NAME FROM ALL_POLICIES; + +rem ================================================================= +rem Create a trigger on logon on database to setup the context +rem ================================================================= +rem COMPATIBLE parameter needs to be 8.1.0.0.0 or greater +rem This trigger should be created by an account with BDA role + +rem CONNECT SYSTEM/MANAGER +rem CREATE OR REPLACE TRIGGER SECDEMO.SET_EXPENSE_CTX +rem AFTER LOGON +rem ON DATABASE +rem BEGIN +rem SECDEMO.EXPREP_CTX.SET_CTX; +rem END; +rem / + + + + + + + + + + + + + diff --git a/giffile.dat b/giffile.dat new file mode 100644 index 0000000000000000000000000000000000000000..aa5faa0637fb9e04d21ae82323d6490cba77f48b GIT binary patch literal 64920 zcmWh!c|6q58~^OR%VOQ@h;<)1mXO<8N38pn(7Nv;Lh0CL-IA*!x7;DQ;v2QreS{=Q zXrm%WsT5uI=QppJKW1Jt&pgjF&&+F{c|UW?(p+1|XAkrn*k=JO77K&HV6j*U2?-q? z9U_rPB9R;&9sQ1yhX;vB)KOELs;LP(Y9Wzo5)z^v9kcxWvOGK-)zlQQSmMzrEY?v% zLIHyzVzEd7h(-d#ejWunYBV*4Xe=gLL1MkRra2+H#Lt6OlGW)*bi`shvuN`PVVxc% zngX^{M}j7SSt+0mCxq4LNR%W*XNCE(N@yeniIoJuVLwu*qfRqPtw0US8t!b4_RDf4 zW<`h5!u+B=97$>lonemi(T*NOoe~csji@m1r!(xKHteWCBdK*dDhwxh)OhHy`bu<; z*r=hgnrZtbVbMf|l?2jyv`&GCPIDM>IDu5)sK8noE(s&`g{hU0Ff|?$tUg*a5nEG0 zBdSSEC8+gvHg`7HIFg9#!$-1^NJO3W=CGOs(tL@>RDol20eAbsK+WK(9 z{;pYrlZCpT*h_ z>+9?6>}+PSz8tN;qa%sMnm@9U_4Pgl1ql{w_{;v3qlcq{nu0DJf2bM&_998|o97~#Y60+1tj#!ch#v__YD*+UA zX!9%uk7%R^&7+_Xqeeoi9j*PmT38K6f!NtMj3v@Yeg#Con$EtduxOfs+L7(jNR9;( z3Spg{eQIhtNaT?c3Un}jM-%H{NJk3Lk7omMeEVl%7Ijj6sg4GVbxG3_C)B?=)-#>H*uP5)iSNpWBE;_M(G~)0Mc!F zJ6Y-Y`?b%CA4Psx3TdsIE+-_h9V2zrKfh!`QPx0!j<2XX%tbV&>t6 zY7I}SF{iT8+TV&`K}x*1iyzU{sS1-!0fSBJPY%`gake%Y(P6J1_)V1AJpLJO-(Xxh zZ_pUGxkA6lf*X!IMXj~au!5_NCoi~-Ra%wX_Wh3eICiQ>vb|5Q=*yd)Kdj%j-nYQ& z^wF$S4_59x*rP8&ijCfa{u%b|p4@1EO1*w~73dZ}P0xBsch5Y)(T&hr8%!f%e0@KS z7hXY476_#n1ERhaJ^+^1U75zvFs7!-*IM*v{L}EEX3GAQx(DN*TQI$$?Xl~7L&$l? z6fUrrM1`67;{DQyYzkFbL>>inuJKRa>THK8`46`oZ7lN8QU0`y(|PNF*3y4 z-X}WQp5Ul{Vbe9JGg%UI_>El^c#i^9+pKr#sw|`vmV8|;aHBHSQTBCUR@Z!RP*#fh zcu@I`*c5QZtw7m2b>(Gn&!8uju8j@#7aAMu2ZcsLqMx5;xs@um)JsB}ISF;7 zmd3rs<3dm1$G2ObfZ31Xd&G*%j!!&!wUWR&x?a|S*qhB%oewOI01rvin;$L5va56> zuN-gbLhag5CT$y9RMNN|<0ar=n)b^KC(Y+HHFZaOUtXgU3qK>dvS4Yt(cj25E`Ft) zNXGBa2dy{l1A$>Qm*3w3w03NX)GbqWg|!@e*${stySw4<$EAW!*JSD%3RUNFCw}5{ z_WOK1OJle-520Ywk(;AbKkD0|)bT#gUL{1fl-<})uwY_N$Dov5gthHAp#U~1U)(>E}fQiz45QbMOxx=wE+#G?a^P?>n$6UL$iYUbVB=N2WFv2SXKp4fr=t($ zjPv2$c=q!ep8CofSHO!&RCLi{b1u684vPN(J=f9d;EIF1I*|wSZou;e0Dk;4+;BDv zqhDUQTR03DDH}-*oT@1L`$k;VP6#I9Spi1)X8?a)B>Vr?q?#AlEN%Y0+he1sr70T3 zq2@FtmY1P_kM10nhMl^+7_C+No8z2$C97EWTfTNhyf5F4_7de`Hr<8XTSP&{`?lST z$`_voOvFj|ZR;780vD4_Wfs$K_;zp|<7hB3Ce7NW6;x9r)!W8pUG^!$19SHe+rlSz!3(sg#nMevu&kcfv2{p7E9k+&E8|xO;-~ zv!nLMT;$~!gC4oruGRURd`V7bi7d{TiWUN=u|e(`yA1)|-cnBU=r<_4!ntm&X2=Ec z#-)#1g4N^6Eit9+%lU?JHL_+Qu}=TZ7Ei_0t$g?-zKvfoV@j}JA7w~x=fG?i`ulb} zO@wEeE5F81a_pBrxF+&E?cdKwPk(c?QV=C@f(EGGM_n7o46>?tp1ESg?4JqL z*{j@X4c60Me7+U%;9fiK?9Y~y99uWeUwxbKwlzlg>9=N8Ik^6&!?fF6~ z)~mk1rC+Z9nmB8%!I&=`?L31ArFs7m##|{hZB5!i7wI|qsKPi7$29|k~N(<5$vJruT*evl!PDsTE6at--T z{dg<^a$vj**Cz9USSGXmtD84({{g@ltor0Xzj>#`wx;rlo~aCBa_YuKK0Ue)-AbIjK=-dJCMa?0X4BsT%X=1%w_ zu0WY4yMQp})~s)XPxXCFZ<&k?WL;idqd@m?v7Bl9moDcHP=q>%du^1@F7_p?mz~4guN?LTqGi*u|VM z5``ABEmDA=ONQuG3>4Oymu_pix$$m0QRmKwq`uK&5gZ1GNY$1p{_fl-Tq3;LB_N193CB&-(49HdUmpHrUS8ROHFoM>w1(qGJybvcAWS>8CJLvE@`{dXBQxD|XHqcKQqeP6gg;M;cHf^$C%}`@q>z%zfku{KXbn#1ov(qndkLg?js3!|jls6cyt;0U>Ph@~IE)*%Hz(=VRHkT2Xi8 z3lmZ7S6q-hv_TJbVv( zMFL<4d_>jxzpe7|wE}M+0%DF58$rGeI&53qR#j?PbO&L|&k{Gw)$sL(MxB{aq@kg& z(Vu%pnVKLT03x>w;PIt+9C%+I{JZ|EFp+Ku8f<>g~8w&JKPR2 z5GD$uk179(D*q+~GQdD!ry>QlsfN2$+y;r{Rc?Fu-<*-h8Rkv&vj+C!)iKg2ccCw+$dNj=NSCyeGqs*2&goN#Ip-rVG(ZXM}h`uMvpYCr%(`Ru+71M`}Cd> zD8}efjFr%?)b_oAs{jZSpZyI5dG{LP00jK_Zq+)j2HI<=5N>2hTNki_4nA=mK0MAz zaXsr>VM7rC$>fzWgFH`FuKfu9>JoBbMh+pvp9?qNAjAEFnhVMBBr?1ZkG#liP6Arq z>b9&2wjL9b|k6_EuvWLPUa zwAC1K9}e3xrjT33_F6@u4+{WP4*sFrsDS%MoWmz%FyYd*T~rYTUXE+?&~EeAj<2^z zCZ@90Q{eSXq!N3(l3u&UM4Krqy8TpsyUv7$b-t|ATDuc(2T`ws#M@zO(qU2DVUfw+ zW3S&IEiuCDJZJ(!73e#_B>2Di@XZSPzu=11EuMS9WfU0|q*?dso@F(k+Z9ca{>kE3 zYXIy{_P^JN#zDMf6-X8bJ;Z?YabWJ5#*rA10}k{R1)}J=r-gwNx42eNWz1it%rVH% z*N{(R_=?}w4eudpg!1oWkX_4i=qm(ojw>loMyLp6M1cRw!C>)_C$|t~IS7p($eR?z zP1lg{oW~(Kj|1uOzBlkdpf_m-{?ViNV;RY>9*hxXcO=6I_U$Lmpn56nx9yS1 z6gF>4LhNd?aRt1gqHSL>UNMvH@-C1ccEr@Bnyqo zCOqVuFm@PaYpZ~3+Rt?ELJNSJaynZPvs&?3ir)dMfj(P~Ptn?%(qMUMXce=a!yt`v zu!)ZHX_Y>ydwkkXCPur$W;bGpkw>x(7?!Y?63$_GUgi||nDGyNsgjTbcgk0R1eh+Z z&QY4TCC>~~oBgB9O-Yi1(K#aJJUFQ63xl3HNw;~fAHLH5IpvthlKB(XS8iBg@gNMd zd&P1jCc(9V4~LfnW$upTC5&D}gMvP|2I<9kySQ?@M=I|Ri&(h5%$GdD8>3n{UcZfU zz&tM99d|qRIKzCRX?d~b-{ON~6P@9YJDvq+ryw5vMXI!-ns$+b0N4V61~Z`nIpNAP zh{QzS@)rmbGV^#gqKfU|*IFT*ysn(P2p1L}ssbQYm|zlN<(&}e{Wl*noeUiOn2Bwk&8_evTD(U?q0u!`{6jQGBpG4omLo4v0UpcT_IZ)jS6nceu z7lY2lpt5FQVfGJm$jR82IQRNwY;p4G(TBmns>H-YMXPDqYpe2QtBOxnmCD-oO4{%( z1NO(9Z9WVRn$&;X*T+`9#C?-Et0(QJXJru!*A7~U|3SJB4Zyun7rJE7-6#Q`ftnub z1mWtxuXYJbqDz);mR7szJ{sAuq(1$PKLd~6lple=0$fz29Rol_eB{^HK*W#e6O=j( zq5Et4NV*c}FB7o(%4OmfQ-@|V!Y>Z}7t_jmJl>k=+4^QYF3_=Qa(sMfJdU~1?D?tA z>(kwqPa3d^xX6oT*Mi;THr@9To$M2B;hR<2h*rwe2ARrXb$6*``BUa{8yWMG}JI%su6{F4v%PNG8KnxJl5?gKuny1B87+m?}~lKcwj zdlk`d7cNAJl$S3-P&g>|lhwr*H;~7OCTk@6ZN3e~TQZT8E$Q4w8T~uRrOD{a8RP34 z#HSk(a5nSujVBiowapvZpU0cgKkQlK&S!rVJ^4hn|8br0(9XPKRLU|mnYX~&TD92uq6O%&XKdmN$43$yrF#&uadY6l^hqBJSpod z(FXiV@uB@zVNsy2kzid4>=FYx%pw5D@~dpF5)S%*n-vZPXQBQWy_H$uQYmX> z@psE-+`fqG-vmPhvg%aC2Gj1D8vDvUd`A}v{VM!3(@jAkj{D8KZTQVPl!chlx7Fmd z+c@Lw$aht*Z zEie_DiSVA&jxwVani0&%9$#tHF|%awp#R$^eQ;iJ!$LZ9wlkxu8cFVq+tlXdcFkWnbT+dlyG zq6mNwAtaP^$Nn3%Ms;LQeNt@*DwCn{#=2dhZkX2IP^VAbRM4+$Ydl^(>pP)j^eW?c zOHaY-R?FkR|FH&I&A9Z?H_d+~qVaT|i2>T#YYkatlf;|EVH?2?n%q^ppFoLaN>QtZ5*`0P72jqc}k#R+8J)3VT> z>^w^WZsKWgfKJrel&>5Fab;}X&V?t3NTi;7{A2owEQLUXMS}o3?RrWfC0Y0&Nv2lG zlP;OJ_PgB(__VrcOxRGd zSA72D+X5%smILUV-5{@^P)=Q}KQP*1K$mVbznj8P>pQkDpTaCR10_ zlq2ISIn4oVZDxnq*9zKc09Pt#RBPdzshm|&edY}EQne;WB2)FY@-A*3eFCiZZhozh zelI)dYIjA-T6{kvOQY;1wOroRD4SbPI7B+-n7RFJBUz+$6h$evaNgTv;SGq!5y^ZY zKsogjKxP>C8=S^5FhpFt)8HVltGnA|VJk?WmkHOZsNhH=gW3Ki!2{{y>}(%dU^Mg{ z*n*IV@(dIL<`@tbzMms)H&GA|0M_vXy^$0cFj$Qtxidz!BEbndpb(Reo3jFugRn`z z5V^a#=}-O>m*WU_W(o>ohXEmA7F9(CIejybu|c z_(EcB4pqlYSFpb1e>(hbx7CVFzTPu`GO=gODUo!mURu%N9TV=-ID4zfQzmE|Z&iOG zk@v=EqI1n6(sp~ch#^gIyZ7!TEav6?fh;)BdhTR^u!;Dj#_)-ISTou24dcD);|3xz zk`2oiW`YUN^}mn1A)fKJy4?53YSdb2MA5MfO4SWyv2g-1iUo*`)#d&ivzrVQXt!K! zBEWu6Q&U_!?tRz}wESjp~m{e^#AOnmxAlv+L&PT$z|HsiL3SJ%zu! za$+(*S%1-Rs@3Lnxbwb2{!^=<7wm_cXU@5cMn60qLh~H++Xlo1d{UJ(644nhvOG`! zqddrP>D%%;?|!pq(zo_v^JIaNXHmUm%gaupvaph`_#by+hj!DGdB-(jN>YEvFPbB~ zTPaqik^{oAE#5CAX^-BU%EvmidFszlv2V;UsoL!_r!AeymscCI6o#m+yqOU0G}|Vb zVbxl-%&h`n(E+~UGexAVtDb(ibs5!^G4@QGZ?83p3K4;SBCK7oKTBQALuo{&>WjTPEbzezlTBWCj!Y zA0o3AFNE5NEIhD-gg2bJn(KHxn22wr6kW@y&P0-1EKgiCqUD0{cxPl{I9NIOIaC75 zSsTK5SZdqkt9OYpeBx(RR*lz=_%wD@_3&#~pVykvl`~6gE3w_w-f%Iy4@-F2lQ#w; zKA#Ueb97;T_}}a0o$z&$3H{j8(Y+w}YChFQwnB51?GHf@4|0{ z^?v3f$1mXtdTW1Tt;7$RQC|-G5i4G%V>ai$nMhrJp0{B<;nWg*yRPJea`~lk?!GjW za?kZl+@(=775@ss(`&ytwcW9tFPc4z-&(Gpyp0k|6FHUe&gpDaX0FP`>(koH)1UVX z>Evx$!k^bFTJiK-Egurv&#Z-%pS*E=<=i8>!O>Ol(bA5}x%m7u3UTM-Iw4cB$HaR# zRLtZ1|JlU1sOl|le?Iy2am(kSKWBz?U9a>*SbT0uBDuG?{xVrB5f_~FRrSTM&X`Pn zFI8oHQ0D5WIP)YecOUe=eL8a_;B0~lf-&Kt6<<2c(ukN~J=sdR9`$s@HeMiZ`Sp2^ z*bha=b~I$(?vDu?z5`Z#*N#5{caUM&if8d{Cs)4c+9vcaXGc8>y0UZrPF$bK^giy+ zpP}8_KY!Oa_y2<|D}T|t%KFE(m-`*GAVL5s5y1KckhK9!sRwFJhg~5cHFV|^`o!!F z*qi8V9XjUGJ$Ev7Zf9yZAdTG{=r>>JSHF4G{P@wOd%ek9`m_^qv|89j zH@_PQOIP!~F|M=M7uM+4GEUS25ykb10RzQ5_magUwVJe_Uc9HZzt;5~(x*_(xHv#m zaMn9cGgAG_ICyM?mwqJ2cQSR&pvYIDprXxKvW10{(rHNKcQ^p+qLb|xVEU6LUJJQ!uDL$nbK0{Oz%s|B_Z9-@uA$K z(y3_uQ%DU$qy`~Yi4aHYi_02`r=5ylGLP#$mC$tRYWPTmJ^}7|DqrMOjHm_soDRB# zo@5HRl8Ig2MENTgsiNiyf6T-N7=Dus)~_w-f5+QG3x>n}NAk9Ma!g0i&ON72Xjle! zSU6d_`&b(D!Y~C;ZnW{;Cd=YpONV%hPScp`f~D>iKo?D_F>9*BVv~|CzHDhmrhPNItMUsIO@8C)AV9GGfdi09* zcsK=WL4j9vOqf#42oxv*m@%b@VQijD#;ve-;~zz{Wp&m1XmqFZor6 z&71Jlr9qozbpOhrWifi3RV6xJ#Rm&NNL;hF)#Xc7)1LC8r+6KJFHvkiHQ8Qjo!T5U z*(^xicyIe@drJSWtv;WfiISbk`zd|XX)mVjp1+-bjNJik`bUY~CGzxd&*|TjcK_z= zViu-{;)pS?C$CraffG4seu(SLVFxmsfn2qZsh?rvutyBpvoG6oF57eL z*kd@Ja|EQa$vE)r%o`A9oTIgVk4p13wgiCTU9)ohJ2O$>|rixRjmm$ zeLTb`EmS#ab2w`yztBA9Y%DXU zZ8K-W@0{V`eCp~Pp>Ja0KPytRvsK@m!!Fdi*}3brv)!_DU$0f)-wB6KtNsovw@8?{ zm&@z0m)YA-l@5~JVY&^HbrPEzr;{|Z7G65$V^FVM&=}xsSek4%l5Hc^59S)sNnuMv zvX27nY4gE5h>&L2&>AFrx9ib92p^(^UrY-voeymWf|FeXHQfR^+%Dd74ShEMdsI?n zrxn8sIO4_69KdWV96Y;W*OuL`b;8bI;Z&G=BFBOc4sP?j;0zh2r=8UN4q{$EtF-K> zx;)EDS9Z#L=6>U%lco&dxa+RF)0ktBq@zqZfj_OQ48ZIux&f~rFTF6hdfFiQwBhm# z%bgdxL$3`>oegW8%XVIu?abN!n|tgpV)M+o`eO3EmvdT2P&5|ihDmfT^=N$7+pq(1 z+km(*)m=sxUH^HwY|xs$Ub?urxB+k%T+)#}wtG!>d0BV=NFF+3Pn+_e0g$9k8P*5- zcHVf;oEbrT_FtTYVwZ+utjUp-k!>mrUq_!k9@>`cnZG285>dI320NgN2ZNt!I^~SI zPBu~kU0hS?6m&f${MJ0%0aYm2^&&pzbPmjQ!Q1ad*A3>Y>wPfl zG50gwu+tbY2R7w89`QmbP8>-L;tBKPR6PQkHUzlg*m{|$wA3g}B)8A@ZFFP)bi1>U~& z3iR@N7U1>#84%<3D)=90A=%5o+$&7RJI&tfTAr6titF6P`6&M7vbT~M z8lfW}fp(p&rssa-mcg7iyuU23c;>)7Mw1<;U`~b~Jn1l}K$v7O0*(Yc-E03oJNsux z5ipd@GpPD=j974VVtgN8Vq zvwum(wRmu^kg@YV=Q-bDy56<#cs#oJZm7dYwsy3=Z~)3n^y+!yhBOWm!{fc55&b{O>ByN^8=s$}6`F_8X_ zpQEZj?Q1L3(}4rW9QuZBGzJ|E4irc{K9qKL2jSTI>1OO=aV?VE>Gf?mO*Yb_*c*5? zcV3o3sgH}|A_(g&&q--D6Qk|)kRwl@eg2FO+R@*@er_I#q0h_;VihTXb2|D-RnmzU>y{h zQV7(^K;Vx)C2x32&|?s-NAPFoiJ$XcFFhp=zPO72FpQ+IVt=48iSoM$1f}qv*yg|3 zPih3vz3ipYD_sBeWU5_VAJs65 zKFlBfta#Ad3Mq?LoU(w}%9qzADteG0tP}N+j0X_o*7z_XXc#wb+dWCsKIx_#Bv^siG<=Cn71y1W5@d0=kRvG~!W*hv1K`shtB~Wy+;iP-L}}ymwQfyHu!!r-b~x zGs0WrN!n2e0fGV`559Q3iZL*M#a92v?!hO+G%(^IxKUvF+6={ax-N$-WnWQ$Z2hP8 zvHaol`3;);lhIwNCXZuZbzPc%`VXQzifc<+&oUy!&%`w?t{vdww!BuN4H1h#uNf64iUWkAD_F$!sb{j#v#U;4up0xUubJPBC3z>Z<2g7{ntUn_xS0K%`Ig|tKnu&Ypih}VZnN11|rgf!!b^P%~(mYF8!*dSDTpP&( z(Ujc@71fqtD4V=I9=B%10m&*=t043jfrD&6>PI{EgMA=0p)-WxJF4nIB(^_k#uPl* zBH_okPG_8B8grMx;6&j5rf)tUFdh@Px$7Q0YlnrQ zu{0ap3vwcv1Ix!c&*$mGkblT~%{gA*b(A(%pv?YhX{0}BGVza3>&zF8%~|Z>yQ&{I z!B~8CV3H(kocEkvY3vtHzWV$xM$|*3oMFj zI0fbG8?VBAc%+dtclQeB?>m@`{kyD@KQj~OJj#9O{OhaU?>QD9rMAR3g976@U`u?^ znut5jp=Du}^x%CWPNj+YjZLM_vs*%?yJ=P;1-t4w6ByR$bO25Z-OB?)RLE%8(v?B~9!iL6sAC(HVkV7&6f_*d4fOXtR-j(`YB{+YrhRAIX4ln=)@2 z@z5i|_vL68wgh{wz2h<}`tkA=l=Fam$IB4;+z!YAk3tIM#QOTm_N+^Lyg_(?URU zmrlW6!80iKRlAot9-KtUXckTts z{qDak^~su1rSFOwck*yk4`vdXQy*p>Gp2R7mOR1;k6b@LH+qrRF>Rx_{C!GyUukdp z0aN~acJZL&`}s3r922r#cm`4_U_f$)fH=mNzSudr+LdodR0t^WKU{sE7r|?qqueT; zu4UF-Q6%e{{InqVt{{v&3pSCsJX|bdIhCt+FNc~B_V>)rw>u@{vf-G;3s|di0I-es zH(nNnw_!_s1kpPsQH$O;|K*$xEPZGA8ZG!Y@-gHnbioAO^1IzcynF`$L3u1N1H1Yb z(*yT0dlG|OC!7Vsp?Hfg23&)SA8vASro9mo;?!up2H_+NwEX^@PZbKRjdE@QHvVg4 zoe>{Z{x%}1?NGX@k;q#jj{|eW(;*}<^+qrg@&VS5SiMg@n}d6Tmq@4nu!2$!5}$y7 z_H$z5q|mbfDG=@n1** zBgHqlJIT_%fscriV1W#@O~?hw zRJ41=o%zK6X5vFdS8i4CR6c>rmuVpW_Z>ngz80k(NoAj87R`4MIuv&y5(FH0?$5_v zGHxpB8v*?JF##SM@+`=^0=#7%)UMuY^W#@V*@ydt_Cp614rG#688%t&=d1Mh-0Rn2 zUYx+aq*T`FAnw@6`WUEuDJT@-9a3?pcl#ysOMK8h(SPz5eSUB)CWzCjo*^ChJcG)S z$mv<1Bwl8Zv_@Cyf0W>|olbHpzKy`>{`hoh4&!Xx1TrYVKxO7<@CWwRsrlH~P6^ny z>;Q+%zx`Z_pV!iymk=DD&+H`j@-rTub1|wX49QJp%(q`73IwwPl9iZ>nLWdrEj>AA zD(<H-flB9#0&-bk3rI_73J@mgka>)a&Q zi2F#)1)-A1tZfM(zlZ+*lw3eun&269ApJ-n3B;x$aSMfeTN`h0=&0eNkr2Y*@)xm_ z$YO%b{I{EesHCy^RdMp4gRn54T{C^?t0;g17G&bZzHb=A z0uErx{{hMD#X%gVFO$SpD$-8&N}w~a7cMWFAT=>nV>Y)3gnts!3`L zGfJKCyloINO9BOBb|8sl+5o; zgrXZoUfhJmoCKkQ-^$D4(1BDdWGs~exqIh~xM<*0fxQ-Ac*kL#IWS`Jf)Z!3`mm;T?zWSySPX_CY1?|OFD)ri_}`6a&TVP7FndH7-9L8U!^umc*CGTxx)$^TJ{M7^#F($hdPONdQPet?jUOHGBLq)0-Pz9}o z;YE!1GTsGXHU*1hC2w4``o&6&LL}hLPNj+C`nk_(f&^%s$vgz&455|hc-bz(_&pJ3 z4FIZhRX;oL9b=2Qg+;W@WvCoLFdY>%%w8pzn06X}d2mkU^mqnc4Av^{Mg<9*)CQCaEZdz~`M{=Lmg92!2?T8>#k zeEZ&>Gf26_Ltoh$m82r~D3@2H1)BbXsFyj*FJZ{#zjUQ&YLmzowqbaagF=CkO> ziGp){uspvPgb85LcouMrGN$^TELGSqmL??42Nv807O5x!sIh28qRgbR%uFIj0SG8y z@X8y@R4^n8fZH8lzNUVcuL!}@+{Zkgm;M?N^>ry*PW9j?x`L{3jV~($TtvD-VoSzi z8*i-86rjVh_^%~Ep~}7QKc=53ve7SwUG(O!s_+q8A2PL$FEjsZ@+pF*Kr}PLCaKv2 z8=X^JSqyn400zw@k@@5x%C+hTBE;{M!FS^=Q!M&L2y&Sj5u{&362#^I{Fb@9rnaJs!vj&}9 zKb?m|ty#D6gDFow6#x5RF2^i?`mdP4Sxq=JKIDIY4C_xkd=shko@mG*3QLQj3ol?6 zj>#j;Wlymp-kS@HGJcfzbCg&p;-KoD13ku;wf>f*iUAkqpo8ep>5`%T>i9^{5woH~ z7YS($I0qyo;Vxk>z~JYsDX2k6cOV?QMx^VhgEMqT-CI|z(Zco&XImK;;t{w7c9E^& zmrUgA5OQ~|bpH%GJ$%|dJD@l>z@xFo_Or2K1-LeOl^O57Ig<_)2$!OVz2~allj%VH zB3DWO_QlNJojfuyjlV4NU6Wm9RT9pu^3@J}^w&(Ic1pP=I~>L)uS5Ty&ZTY1_2m~U z=@Gx|5k_OA#AuZ!JVw0=9(>bl1N;(t!&UJ@ZHm6LNByeF)$*esx|al3dS*nXdk@0@ zeZBV&R44~5NPdJzyZT1!%0++d|EE(IvuXbHpH%Gc;-{eZ$Dq>2iq*y`>&9Z$W`+zY zD41GPcj<1>g~A}SZ{_Ca{I3XNq@ z)P_+#98$thD2zvE@gTE!a9Qlw$>iFclv?|z*1?ww3)9UCZ9G83x$;A~^69Rg8R{Fj zztx_coQko~)mGc$R@;r|V>fPlm+nCnt_(Fje0$cJa<=|#cyo5$@`j&!3f!GVP;9pA zsu+|GP%WI+ZOgl(OZapEfCt6GH3QE|lDZ1#-Ik{0wdr-; zTzFTy!cKN+Uh*%r_=A`EC*gu&OokDfex6%Se&+1IWq6frU6o{Ll~(A5kH%uiB+c+7 zb$N((Aw;`+Kx;BdF5dW}>#9+$)l=h5BahWsMc=r?GlZ7L#@M>p(7OAK#-}jGu>3ym$lvOk7rA)#692L!1sI%fw9So{i>a_{fsLqGLp z(DG8B-c3z^T^-*+6?0ya=;)U~6D0;eWM=p(Fw%J_bn&CWVI~D#aSVv*H`6xrTJ*Pw7)UqGI~2L_wVK;%l&UJdv+(9UV@89gxoF z33`7Qkf|QRqZyz61M!BwD*swqfd zDQx~F5siVt!zsMMNB^}z){}Gun(EO+_4NegCn@l7f^_{5-XAc}qI0zZnBZ+$e<)n3 zA4Z`oRhu0n)5Cw>hSw8**TQ)Hq5SUs$SlGkm?FMC3#+HYap!LV`Pjll1RW5{BHRWD ze4eI!79f643Z`0>m(05n0eDm&gM?E#=K4=pFU!ggd)=kOy8+-YBh&knRNHEqwCx~K z=~RX9=Eg=Y+gIN?OYVECS#;J|xdwHfQ|{GfaRjBA?}Q?MX2gYSJN)9C{Hl#r7arbQ zg;SEFq7#W1^Byk23+p%G^`GI@zatv|+az$dyz`be*7c9Ct!w#s_Wfq#1yBEnzoXuN z>_<>gGw&++;~9ru?+=BlQTW99D3D}y^`$NfUw6M$Az?VtQW@JXbD>)1jWKeRB9`L} zm!}S^Qw6Gxk*Gu?Ps(R?st^V(qr`yDP=>n_`S&vW$zY>+0J?r3Pd7tUdo6Mdgf?;3 zJ)?6L(%JqddUW?2q5Gk&bdIHOMoY$gF#x-%Y9W&IE}1@f4d5iBfJwTMKNVw2MFkVs zs*eF3M9cz(Bbb#4oB_moTDkrV;}1 zZ=74?Xw}#rn;H)&wWp|cqqxEbr7j5HjnNpawcI2R`rjBNYkaNXQT*50@nkF|>h=Tc z2@NCRAnRA=|IE~E*ENn#83A#{*MU(B>YG)%jaWHF!FBir$-1Ta2)PZoh~Iks?`Dy> zx`xl@%qI`yc>H~`7+*Au11Or2n#PvhNj&~k8QIlU?kndIzHKk(SCxN!d&KH@2f(OKr{UA|bJuOdl4-CcuMO_fE zGz&25^#J>K$#2}2k0Ax_Q)>4p4c3fqtO=wrUnzqiL^hT-1xuw-j(6;=cGEelDe|;L z?I;Ek`AE715HI|06rO)VVfZLy8t;q}021ZW_H?-VIlBp*yNSHP6uG^dP~=JU1_gW z$2TJ9-+s@JyY*jD7gP7%XYCFAx5Jc<0?-7K>O+!V)T?XpuLKmW1UIc7br=eS@~yu? zn?AJtqQQ4PBJ**#?J2d_Pr4)K;&13FzV`Skc>XJvb#M=UDSEy+MxZD9BWuS=>QZig zsK|b^%e_sJS8AqhKfKm{tb@01v5UU{_V&=>oaI#=QOYGti7FA=C4fN%*l+_be0>`P zDLMf>#$F8}mrOV}7O7#%V~I;BGxoze~BMk5^(f-pKIL;+D? zgmes~MI9hW2!hgxKM+*f5h@_Mm-o89f1JO+*L9wAp8L7)&oR;+0_lQ*?}pR~Z_1y$ z*~8BDyWxh(P4`2uKuz(&kRrDeAg_!TJywg}UmGC-`eUd3ok!FtN#3)0swUsxpm9te z?}{uc6ZuDGsJ(02q*{u8-e?`gH1WpbBBNREaQ>Sr`=;u`ue<)i`z_RJ=^uHCX+0Gs zJ?X+R{)*4**Dxko^_A~cM z8^`>0YB3ecyduBfJMoV)r2q@k|23g7$iL$#IbI?AuP zqU5mYoNA6T5(J>W6w~J#P38pBLND|~TRKb({w{pu$_o0E^}B;PEvDC9mZjiDkN8ji z!oylK;Z@FPuJ89gFT8kYukvd5&vz<~O;stL@aXl8fps>GwV<=LTPm&$9#O2+q19Tv z5KL*2E`icp=1%D!LEJ4h8T!tpQ_3}@p7*c(2Yd(BN65OU@J_iu7~23oociAM?)wGu zyU52K^ z^>U7)9~l@w7q5Am_WIQNUWm=T$h+ET^1gLge31X&Ut#y=!d@;2Fo&Lw1i}ornebUO{~ zn(bo@cLv5N;)|{BZ(YBJvo_k)nNx^*=d6JrG$X#fy7vb8e(*))VYoKusQX}%_>COq zPvqRelte9>Ut4WN08I5j=Ob}JRMuBsT#yQ(1m4u%>eK5XYMnl^!p>-kC!P@DZ zd;QQ(*HWHEMSlO?PS+E|{y~dt?>Y-X+wN1z=W9Qv)c?G&;8Wi?|Csh{b~*R0!bZ|w zRV7*HyY8&8s`~Zwn_1@;XQ3s+Y63oe>&bxtA3RFV0Gg<%g5Ehft_sS%>qQ$SHg)E2t#&G@LXUgrY13Z#XcRi_^8ru)()88-Vm2k$ZJ<)<@vb4%&MKFUl#3} z{w3+a)zQ6W|NS7Hf!H+Wai}q=h7jsP8f|XRM2){zMI67o3N+E0Qli9a5xKcbPd?m` z=5cbbYGz%YcclKkj z5tH1JIGC2mAVV23`Ksu*PAAn@A;lgqEJH!(pc58#k6#2R*4BZQ8!+VX4J+n9IcmFVN5( zusEs@?6(Af^ESAt$@-wD34ocXDwz@)ur!`ugn-lsTv}wnPqjFM9**#HEEyVTFg?hp zJlqs~hRfFD1Q$G(A5mBA#rwP)DmXsf6scmQGiSm)jF$f@c0GFBw(vv2hyy^F4Q=8) ze^glf##1s{bi(!DwIY%WN#>r4srwbwz54ls2E?VaHpR8F*k%Of+`NHx4P=v@( zJzio&t;7Z3KHPRo8`S_z(_pS-e6*!2%n3+$Vg>^*z2sNMEpu;UtN2*94Gm~M+%K7} z7QE`KsW@)+=+((H&Qog1DMLe5dJMbDT)j*-AFb6X20&SS$Kx`?Y$gvvJpd$A1ceTv z?4}^pEt2k6^}}>^{1;xZNRr?ek!)zx9pDYLm&03C(>B(RMQ&Hc9p@VC+%q3N8F^Zx z_AL5s$SYK9^st}WZ&ezrH_uBG?s;R4EFFff*p;N&?zwTSIJ{M4Wsc*4iqNPzzSdW4 zFML$1etlrcGQ8_~`QIj_uF3NBl{XzvpaJSST;}%vg|t=a`~G7V&MTi;yL*48fbl?D z>N;%}I)FZJ>Iz;fC&)9L7V>aS1dIfLG*Z479}Jzh6#(m#2C`hKE`I{c8FB>X0QEdX0j{f_ar+ z0aJhIQxdXDMnZDbChGwNemdI|4A9#FCZy~_O%LWr@lCxE6w1#q@fc(%AnULhuczw} zD>QF217z<4Hfh$(+-aNQS+L+3wRk7$oQ-ad7d^NV<1X)EWa>HI$C^T)EF!Z6{@rpyGUaKg_H zIgR~(Zxza8T2hZNhYh2Teck{YiJT(FwCZCZ&iUc~L5eifJplDdB^!yg^KGnDg57TewT@O>I;?vkyYP4DVo&Z_)NL2wz58@{@vi# z9<)mBK6te2^BuAKfM8|1UW^`FA3%xgo;K^v(>Di>xR{cImCs#UzhB1>WZ@YESZ^%8 zk@o^)QBIr-MH^T1BT#1ls&0R5N6ShOzlR5BZGi6 z4E-Vm-V*c@P3z*3-@rNI(2GEwmUk$D2A_)@7RoGr+kMH@^!g&}rE>1eUlY%i8Au}U zNi_bi9uP?l$e$q0s^Gf^AOM}k0G+xPT_^(!w-&2L#cv-i)@uT6TY0RZd~Cr$1|I+a z0tW{ES+M3|d68?ZAVM+GcQm#BOU;i_X4z7igY)U_(XHFWGNV7}kP=wdL`%~jv%tR^ zhp4wdHl~8QmKpxt-ksjc{r7oqi+&Pt69{Aoo-Ph##m%rj&gs63V2#OQb8hRl(PB$D zWDRIz^Pgc!n_-Ix>5gja)(8N-4cybV;H(Ydj79?~#zcsx*!-8#N>=0hZu^x-W*X)e$1|Z|2EAjPKWG2gV^Zy|E11M(IDBOH(25j?D%|%u_LyG{GJ03iJ4Hz*GJuP zEt2u#l4*WD>5V<<6FoV*Qn|Z5*^R(|1R#Y~izyk%g*fK@vUUH};oPTmkO-jmqy@?& zwxVv%?nS&N3>X)}$O*4eDTT=y;Xp`fcxmurGH@AfUL9evbglKZ7+Rhs=;U9PLT#SH z50imU;^5EXN^*E5?=_GVn(y8*wR#vR?pTTA0iQSq%q{U#unB%z_cqlR;KIjtfCc6> zFfL-~2n1vgipB!>%LB;bp~dQupgxRZ(Ezd#*5JAr=E`+QU;?V2k8^AMeAc&gXXojZ z=u>9P78(R&vnYxYfuWwA=-8WRl6W`E!2Bfi@A7sBc1rZ4M8~ppnOz7A^$nf-hm*87 zwl5?k{dReDbj?rn+{5*qnawYZ?s31Bd1=X|fC2P{ za7B-^Loi${VgM0BEtT(lI9>H%=Cj4og{WrU)MM&FKVt=yyfE5i06TEBOFe}#Q9>PN z=Dk{;P*AXj8CHNue#&#q{ZYZ7)aHJdagcnN@_vUh!vhlR2oy(BPB=CP&nY9Wf#vZv zCDye&yKf_`IH}Nd7JQ6rc+}|{qQ8<20A{$x!mtMz0r81}2Iwq+D5>qyWZG6{^pF?R zM#KZ#7h|?^vTd}pM2LKw+fU3}iLcjoFPyTpm!!p3f7r**Y2V2IyCo{7)S;7a3%j7* zCbv?~gTCKA_)fUvM6ty=ma{mu)evaJ%FlfXstNi7cL+z@W+WEEuT8ViS@Zcvn#wrl zh*^Ub*nQaczT16%xeS?)TlZ6a^R@zIUmCZTj8V@u@P0EpQ<(8^9ui{z04@Z=#daHDB5 zkCo&A;Np+#OkHnh$1$C7jC=h9F?hihqoTfg%wIX5l?>V`^w2d4U!212m{5$nErw&l z?j`NJ+1B=HQ~T>#_O=ra*9X3>?Y;MJ@t=sG%ok22?LhzLtu_o;i!Wzs^-}!VbfO zIBzrE7rj>0Q5A>p5Lz1xlxg~RVB%@wZjc~%L%O=@VRZ?%j2iBNnTljEX;t`6 zkd$KK6ER7l%rwo@w@pNX=I-(CwzJ#V%ldt@G3l^F#II(T4c7kKR1ErC6bL*mTkZ;= z*gI4A1a4=$OtQFe^(26Qn|<@(kF9Y*C7Fc|NfWA-SvRET-zIIiF}4$AzPA{%H6)8h z8d6w{0okGj+1vYA$@wdR=QI%qX5;hc>&1nlCH;sO8ksLd(C#q{m%3SGT2Exmf;&!; z7yFAAY5w{g7@hC13k$08cUs8?3Jym-_cOcQ zzIHT|d2NTNK0v%^X#Le7dYsuhQZ&(*+lrLW)w}K}Sdm$6+DoOi47&G${o#*;h4z%dpfQvPTVVIR_DuAYZT!L*W!6-|N2+lN>fL* zg85?TdyPw}vvyL|BsR08K+Z8%BYG;mCde|{KV3+G_P4i(j^edNMdJA*lt7^zzwxYa z;f#T-hkFv`&ExNhqI+n>2TajY3F-sBdA*PE1GeQOiI#JKb_a{x!L(9j2Zk=3kjfH7 zSuG^!#bu(H2zPE%$!gL4LvJzy2?k|K}Q2)_-yOWh`cCM22q@UB8U5Hf1 zg$AB1MKG#H#WX*o%8isOsb*Eocyu3av`{&@m>#2K&bj6xjsX~};>OxudCc9jmYTel z^+3{b5`!q%hsPFjewRPPe^IZ0 z)uz(tezGVDSf~c%#xldu6EOf_6rMNp2Co>v^v3Vf<;QYq^`Ptu+4}=*cS+QXOT{uD zBW!69Mz=wIf2diPLD-0FJ^(0(y;|#Td5dzDN{P}T;-}EZej^~QVM06SQryam2hxvU zg#?=HDK==;G*LFC$X^()%@w_OWBdRJ<6LjHfBE?FS@Y5|{hI2$^wW92(iYj+7NyuB zo+k@2s|)cwi+}s*(J_k({fm*SZG6s)DW$E~KP~B~zo8h!z7Yl@PtmA`>u;pAR=RJl z*yC8Fa4h4bmEn7+@p~xaflK%QDhCd=cyskXp3gHcKe^-B0l)*}sQcVz1)J%hcD8~~ zqwF=(x7=^^Q2{h%>!I+m#@mf!ECfIa{7L@F=qQ1$I)q3bBFwxUzG%=>r{ouIt(ZySBaaylSP-gZUgIC z$sUgKy7Z)$)BOx?fPYc`;7uU%BVMV2WA~mETz@<@|HkKGvJ#E3^k5ucph{89Qt{2} zbn_+i-lg*tCu((Z<$!?;Ig5Ei`C0a3Ztacez>hf$olpW3H;#PkV)#xh zlT`wf6^<;te#lk+hN}FCkM{`t`pw@m@}+wY#!FVB9P-{e3{xM`Gks&mhca7d?tjVb zq{-@rL%H&@2I5dyt<&Tnb|=2yk>%{E6|8abte{JWM$Tzk`Dy&XX>RN9nE(FElzw6| zeZS#s?o$A8XRgG=VeH-jfPTC2OI=~|x&e-y^VDS{bYEjD1jNHEmR=x1u zDXs@cA+cJCRPaIFVj`#3!&!^lv`ezjj0%Ju%QoMJew&QD@Hl!Z+EF!AEvG_rU-izG z^<#(fyZ16}_pE!&n#UEKf9)@H25kJI_9M zVuimP1_A@xJ;jTg?K($MjS9Q==ZgOs4l~C4ht98i@gb9{PJ3Tt7;>%27rBsFSBduQI~Mkp2Ozsf{5G%~Yt9 zN&1ZBwOp`=X)x7e4KkXB;mWhIPUJo9H4F-uI2NJlpS7(>#X1eIDZX)m_5OUShO}w5+qjlbkWnEGhb=YNTBdmPVd)Cuk6sbC+;9sA!9tfxDXx& zGTf=R28~jhaxH5{Jc}xD9Qy^+Eq+3Mah2kn!{@j?;acPqBVzmG_De9MxKhCJM@7V6 z@de``p3cQDM>Jha-Y+D7FI(C3bgw1xzB*m^&f+MPU}%$U<2i*#~^WJaH%qZ+9AxE z0zFa`R`tY!=*j#htTQzlCpZhACIE{sf3hVepH@W_0Hs&J55Ox>SW$$tU{SBCJil!@ zqV%eCv=OFwD!jy|RM>t&b)lCYS>ThfD{@@?&VpaA*!QZq0(fE)J0e$F@zpzUJI#9Y zT2XCJvUHJks;x_+${QEG4pT-RyXi!hXWkM3YpB;(xkOYv)e3NJz@Q{#!16VWnY!CmNdCM$ft!b!{CFTk6f%Kb z7XuQ>C(V_e&%$EcsF}93X!{%H^nz!A_tsD*iu`u!p@&!Rx``98i4RJ$wPEbOfE%zo zB0yStD@UUV{(k_Kad=l~QGu=it+UFIabj5NbqOKP!<32Ztl|6w|1GgBqiLWvEJ4>-4>4|(_uyes{5`W4#SR;Sa+bmt|L0@57M*JL z;UfR7JszJ|^D(XtpTsNHw72e_O;2Z-z0(I57i$PH$x(4s=?i`-9`o-SgnE!`bl-?@ z#10HuHU)zexu97PJdh^OlwFw%gJLD>$L*ca(jiy$na~To7qcJ^qBWHlS(oob3nWVt zV`#6_V1?al{?&iP9qZ?dHnsZrteB@H+PE(U@?SQa zI31IXTtGm+x*KMp*O(0TUWJ%4ZuaI;DUzHAuJ)LC!cyd$x1G}lg{?~1MStd+Jj(Zs9HcFtb) zv)F*SJyV^lIeX(9HQZ>VtUcdRrqF5{Rx+!u)HA{_CHH9QomWb(YWK8R+bVUIo3Q-S zPmuk~vHmoFp;xWvzl`${`VWw`{%yD5J z1OOHw`m!|QPTM+;|IX81hgMFO8Grh)pQmg&;228Dd&iBV&~EAMu1y!`32q5RZ@tg> z`ydfu>ZOpSdgF?I!Q+#rYTLJc7G+0wTA>hcFQc8QH711y*7;U!DUCy}5V@bGf8F{J z{zjn8A&ZhM;cy5ao!~#peGhGyh_7>*9z1&L4V6-FeRn%x!ufMaQQx$u)Q5u4tnphB zRMZ^=#KGQAa?W2N%Xfv6Vf!%S;7RTvq&;H_XYR2om5VL z3IURu&z_vXZj52CN@A}pU~frO)iY$r6RE63V18)WCDHUYAtkphCFjtoeG?XkOnuJE z>4WEdp~Kno4c3=PlVSm@Lnf!la0Z=9lrqdXjQ_FFL&! zpWcrBKf?6sLV9*jbgoE7fnmm@Vnh##>P(Nny+}Z_T298Dwjv!z`$d+|D)6cTPP|%? znHa061Jn_uWgiG)K^ojmq5#{r7=>mS-B^RWV9eoP0j5GgtS;&%Gti6Fq?e52hlZAp|VTy%f>lb=ELoVjy3lfO4W}abgl750N3}>CK+hmY2$yk5b7O zy99kI&<=p0mkhZC3+iMd)g>9yeht!(MPNjdbsduJMj!aCU8d3=+$K_8t51Qhwf3sj8YdDHBgaCiy;ZV;{3t)u3*sMfckW`6c?7?kFF8W~%c_WDCw>{ePr z@uTFeM`?AG^pv{vET0Td-$L)R^d2-~wTln&K#o}t2*Lm>L>OC@b%E0i5He0+mH}W8 ze5Pm(#4^$YXccCZP(;8z9U6=3uzyn$iBNjhRARKzR1g zA{%>~I2jqwd%-}d+7ij`P!tk6Rcvc92X?bX1rKvAnHp*wJr@jO{`pJ}SIHuf{ zDcdwETX!szR)I;0=JPow|Ja6dlMz2UUBT zLnH)fh5*LV1QDqXdZ}?3YDEAv8vwYBqKo4}3^V{A3{pT0`OE^Ifrkl-AoME-IX!^~|ieyxn&0grUU2R@c*o%~9 z_{g^&q0JduM2RTM5S0^y3g6+U)g%JM^o36xau3*rI*XOiznR`Rc*&v7bmnGwy0`L$~66Bwj1+^!F!HFg;4`u*|XOJsilOQPsDmE-g zh*ZvHLG}9#(F}l!5~(0$1}*@CB1_v&ruKn=3@_Q2YhYC@^h+l1H6+BAK%GZQ!yw`P z)6koM%K`?InkKa2X>{>GAtKZ{56DF#(49k4Fo=I^^qLl6#1LX=8a9yz5hg<&(I6jk zR1-Ps=GY^>%xa^O>QweZtmt#s-gI}BLZy{ztWmnhQg!-b0K1%ZSLCxF`qtbLflfQP z8^|0PZLc#spx_-wc|Lt8n-DWVXt_H?Q${ZwN&)g0)s37!$-K=JAr{KT`1H0mijElO zIt+dV_v9x(zG~2IZR>I8NuAFGlSGBBP$XU)XfG1NQNgHzh79=%qcBYFax_5? zYrJZJT1pMo%TG)34Uy>5#_`_LU8<%Xs)#kJs$D97i@px0#-3%WBw`>NJ#D4Q)lR~C(DojNTM`$pb zjvfPEdO-6_g}0du$(fdDw~!P?P@?k;Byx+=MnSJ6{=8h@ZPzP#eqRJppGU*S?bH0x zw=@JEi-$i99!SX>V0oG@^8^t{D%5@=$9c6#N!yw_5s1PGgw|X7W)_8gWVj&%q*+r^ zcogJ57<;F)ixh1jt!1ak=N@y^>G6V59Sv7XwY?I;c>LR@5?f-JtmI*r<;k3#n(3~3 z*=qdivYP95Nb#_W?fHkc6FX$|akFoS877=qcNsqQ`&eWc;`MMM_oA4(7*YCUrT6Kd z-U{))H157<;(cv94YhuKbta7g!KGcdOS}3SQE+N0GJ=SPY7rq(!7ySB!37O|O~!Nt zS1C=m43QBx(NG=|G((2+A`b%#od$8hp?CoN(Hii;5`kfd_+eknj~C?S(WK(RCzc2+ zJal&jdLW+mau;|ai?AR-*|TZtv5#U%fY)fSpajAXK3rVvMqcphJYl7w0zvH> z4EmXn4;g^r0FWXqZ?g>C4-Z$vhDQOYO~{a`64wpOwtgg{2?IwWp?wxK&K3{;4Is?( zz-|^)0{~bsp>d_R^lmWpqYLj%GQ>EKszPEsCKxJ4uKIIGfF8Ht*8qiRL^c7!O^~rh zQaxHr)y_~eivHxYM%`EW&<7pmmrnEIOJ(3`YQR?N{EgMwfcFWo=LVbuD=$|wM+>13 z!g>zQ`)`8EOKvb=IvhA&*sYC<&@s#qWwwGe6$3QgYR% z2%kj=sF}KP0-5Bs3>ESpd#rezEZlD!v+eLj`Rdx=L!tuo?7W%p;re2|v>$WM0HRQH z5FcQ1bdFEK8)ZvRO#=k?W$4wSw`}dL1F-aQV{iQQhTF?ttw7cfMw=Ren`&{J9&NqT zDw_?Ntfk@$jmA)y7hsGGsGMuwaLwHkZIgh9*pM3naSN5ZR5paKKC_*MYgAp!RH=AK z3kNjBwE>O%ZvBvIKDtz-r?2NW)m<5g!-|T3OP-w!EIE)sae{hpDst)rStvMisVYaU!y4w3CterWtS`E)mjTm*Q+AuAb`2h{ zb_VV)-G^zV)AVAs&lIfL-tehffBsGvr2nKNOxuzd#VB~EI1SFsnS)Z6wNa9tWdihu zfIpr_tlde(gf;Glf(BGxDBPLr*`?&lS|}Miv*_-Y8S0TrrcgU?Pw$trvB=% zzHj5h+2M@uru*N`tL8_-l*`5Zof~YH2S-g}-&&0Ga8iwV+28%qW3h3KqU?>2n);ev zUn)EJfVDYsOmU8>v{9uEigYVyce6e(xWI(4u`QPo+|iv0v5g+OtG?{2usw_B?u>M+rEvvp8Iom{$=FrE3Ox(>Sg0k7Cw)~)>72>R{!&5`0rk=+R65Ry(kzZ z?jrv5cf4R8fcGp313HY_q^FQi!2?u09>`o6Z>)?qT%bc|kXGRxQAh35DNMi$>U^*coRNb1vPzKg;Luo~R=SKY|4IYI1l(-{V zyK~a;UgPJdaj}J84;w`YCFB%ZKGxvdEwy{0;Zt?;J+~!*B3lOR_h`606XHaOS&8si zl`0SpLNsYKw`@kW3c*C0id-#BFhr=tv_S&pCDPeM@)l3tq@tc5*VnYTb9JfS){-!K zRjZl;`WHX?H*%JLkR}8eq}2~ASNtc`%+<_i{iGSr+B@I7oUJwHYX12Z!}dDr=f@yT z%EhI^38j1Yn<1V~Ji%U3*z;E44YL~wnw&{0?K*hu07ta-BYcV0efBGSPoW< z#|uGxXhi#A{7ts?<=%5|X^kHX_kX-5@9uiMI$xH1eG#$o^2e)x zC&vq)WB<^R{{#JyK8=GOF8+6mimPdQ07FWWB5K1Um5X@}hzU;Nd+w%rAP}z|ztS2G zW`+eZbN}K~w;?8SGR;i57E&=OR?^>>!O^75!Wg%jjPO1Xm{YK#K4i?h7|Tg-!o+B* zTg~T3;50c2PS@#JN2d7bEIg!~7AQk8a5gNEPJ{~Y07wY|Vr`!u%_`T+U*Z`vn618C z9!J{&*&2MApEr~B+}YiM5D@@yvj?xp|4cNJmIPSt=~HTH$;okd`y!~2{08YbIc6TuOX&exeaM?+!LJshLYcmQhl<0hfzpHhx6e5pc<20|`Lv5wf2i!mmXo z(iW4G`7Qu3t0?Vp0GXPgTS22J0y0v|G~;BK0+g{2GPxpcA`6)>bFP(C5G?I5%pDMP zliryvSYKy&R>X6Yf3>SvOzMFCL6Ey$7->5BzXblMk19>!`W1^lmTyrM7)iNnJ=;q@ ziE|C`R;8bhF09vE{aY_M*!@usyIbBKvlC6Y`jCQZ%(s7OfH4cZFEM8X?E5yk|byjg$qx+Kocl@u5(fy!V=n-x+)Wk}G1 zBe(FhHSCBgC(^7PJ1oz9*nYdr-Yy1mR_s+`5tHMa) zK3hE5)A?Th^5b|Igkp6Mz4C279`Fze;>}NEkPl|(-PLB_a=!tm+hgPq;gT+VvMO%) zd=ajuIG~8V<*J?#&(we&+JaZgdkjFNioXao$XIY&4f3MU153q7!7S53UhUxeB_bBe z<5Ug2qAUWy;u7Mw&@>VxS-=Oy@8x^=w~A|006aOD#}p4$EasQ^cbFs*iv{N^FQb-q zp)9R{HG}8cEK($Qw5jY{3Luf^Qn3F6T4PSF8Ym92NUXASgWthWKnQibxhr~|mlZHX z8~!=@xdUD#YIG1;ISoYB;j6q+E`t7X%($MAoI5s|6@6R!s&=J0S&fY>@9TzDYD1<64BJtlzx>?2pMXhG?!xd2b_NnAd5)LMoFka?8vWU~A%zF+`Jc=oa0 zt9`fUvWaw0*@2MMV2kHk6~ab`)xs{9lZ(^mnH0kT2t_eC=6UBAUbd|eYEWbc8uAS8 zHw~n*2<|whfZ--GK$Nnu&}k-n9>gA*stCuw>h0!I=EM{ya`;^5h9!t*LWc5F0q7KT z9Y}CGA#5j6JSu^Ul&G;qZI4cY$^hvcx}IOY*5$;nv{WhkfCe}%;LZ-HMGK7H&1@a2 zng*7xG6G0$^xxPewlHcPI!zt!+S`UrZ=AGsVhZ2zU+HpJ>rd+FaqlpA!D_Ujw%IFx zL%e*Bzh*#gXknb;g247K9V7<>T@40tqprIyLPRXUqDaWFd#7VoBHgKU=2`#_RWz=Nt{DT;EUj0{+8I*}xB#N=i9yDlh zT7Y<_foMbEfgGn$Uba6VB91o(zgc_JQaCAThvGE;UXua-vvz zBFi5DL)0~H)SKrGiA)Yje0A5FOGenp0RB^e|B#4$rWUkgK=DXWXs}XFe6*6p&&7?e z`$K*GPa0qB6T?iw=SlP!E(uIQ&hxCC@5Jgs<3XW^IlRS#CNx(>Xv;dCU--6ZOS#BP zK7C>OLG9%q?IU#2PX`9qqpLqCqUGiNxn$WQ{{e<7d1E<2 z?5#HO9UZ9gF)VW%Z2%>T$Rsc#xuv5D)aw$(qZ15IQ(oJM>)$q9fSD3trRmu;quHbA zi;1as&o`s8^uz`=5KUfMgCBJ#@6#GRkZ;Pf(OwG~>@JvG6zu3qD%5_irUy>Zc9xK= zR_jGE%w&QN(m@}V%R=F7`<7F;&RNTub?$H&FJv|k38;JD9j|{Vv{!8${Xl5rL0O*`#*Y;lVLz*I! z#j9BH%aN&?mB3Xi5Sslt1LhT5SZxl60qDdu4pDu@=IQuTlro&BhGe2|4Rs*?4* zIPp1wFgo2oIwLVDAU`>qY`GAAV?JD4%S25idva)SM#N+6s;SY6i`t77?X`y;FOJou zH(y+`k@iKJUk`PBy3y7>E*UfA%AG!+ ze5q!&VLG*!@xjH7AwtynpNRV43#Y{)u4ezf)nJ95T?4(!)aO>&X&zii%$$ zij#?F{>jmKsnB$);l+;^Z{Djvs``6k-XNE%#bVL3Y^tj_-DEwRdR3s`aZ#SrGUIAy zeHZ;)b0;i|_x^ z&NhfUXzMNN=vg#{IdGU-2!ZCVl_1hK7yH-wi9-&fFBeDn9*#*?wd@Y$J!7`My2NsI z@|%p~LzY!i=!}=q(s!Agvl5fpf=#zsw@n;>F^qWhz3>H3?g2{#6V{--BHy(ak zExSKx^5I5FvQh7G&iAN?h~GyEvZJ#OS^0I8 zJ`N>RE=vnxa&2ZUyUAX*x_rOf?9}jnY>u~<8dtO6@+Zq}Wa3hCp{Hcor{u!pMZs@h zS&w|2>PlVjRJe{l|GZnBwAbO(AnzW=9e=nEJBXX~JD<)Rvc9eu_H^V(GX z*w{xQ(io2wU~ri=L=SDJr}ueWAZ8xrJy54pY8eaU-N&mJ%3rIhb5Ds3tZ}RCIqM7e zzW#i?YF~(R82Rcl?`c!8y2Mj-Y>_*6ZQZ%h(>cd;S+A3FmNff8aMp9qsM6N?rz2mD z*A9%AU1J?%(Y&zgWgm#MFZ>#G<(s{bH&fvHIo{J<>RWjJxM-a5$V%=~*q3N2HXFHA zkPrTf55y?XTJ0bq?jRwa-UrXRl|a9BW$pWwwFLY(pqa8yLQaC3YjRwfd0gS;{x|>q z(3XZ^`d}`FH;X=X~BXOJ5zJ+717_8#M37bnq?0vRRGr z>_jy1jh%mB#NJO!+_zV|we-0h*pz2ia_b5Yj(mOV=)d7czOiWR1Rn%+rGD+BDDJu_ z{y4G=y8Mo7ayv%8{pS_5c>iY3foGV8*V})AVXR*3W|FL*0~em{%vSEawv#+D@~hoH zXt+{TZ`WKeM1K8hhd}$ivnBXu#5&F_FeGq2=T~s|*R83XfQ$p+jM;vgRDcmSVBRj^ zqtq5Yb)PYJAKCq5adporE{Gz<5b)XSgo8|7o=cF}GY?y(QVOPG_;wmaejO2fB`7qo zFxVWBv=a#8i`oH2l4Zl4U=04DQn=>NyNL3ju2esdIKS?)^`9eO`xJkiEcCwZ8@!yCDWiCjHiI}~6Db`CuvlR^(Dih=O>bwqcV zOQC1{67A)$v`A}{@;}!YPW)v86p*^e;-Tzc4-Nh{^3VQ{avCqLO?ng6M0kL{8vNQRrvQq9=2TF zwA;0GY`7nh_QA{K^zgF&97Cl*l$jsPy!sER_2qs4?nj57^MSQf!OT=YnEwa5Kt;dq z?v_5DACGci=Vk}r?j$$#D-ZOF|93&ZcVbucoNQ`(FY*HSglAuBD`)p=zj&+v&SuEw z_V~v0TlV&D?`?I*@HS6#UN-mkCiin6>#ja#VkU1|r*+?sVW|%UtH+J3&-z){dal=c z%eL$qr|a4kdm65Bj^^krK>M}dj7+EP5vT39mvPYUXMUDwz8-Gn_U>W^_AK9WBcJwT zzxPDHcfsfPc)#vW5ctvJ@d%f9WH0v5dVH7v!pZ+E+*N8YD01eWccAxjp9lIp|9QdI z_MiuAwJv?8Z+h}}dNoISUXEQ6pZnRT{n)nSi8k@k7IlDTZ5}vvRafzf2L9krb>SC< zQ9phaPySS2e&z>$QD}bUmwrh&{^f`M>lcMM{sQQigt-QGOk3{Y=IfpR@B3k|_>rgg zK|gu!Ci(G@`Tv%DU`~0#|MkR=d_kxD{MUc|$9#aG^}|!3P6h82G-xnT!G;bOE^HVv zB14K6D@tUj5#vUR9XEmuDRLyqk|s}z^w{Z6Cr^1^zGQi4W}rKN0{zLEa}g&_k|e

&P)3g$9g{TF7^O&&ehC$oDAlS~sY=Z{RqIu$Q@?tRnzX6XFOqx&^5ha!o=z*> zR#fN~uEMry=ic$u@~&RDefJX7TQIQSw1Ek?)SE}GVYP|XLRK6(^5T|>FJGRlc{69t zi5GVcEqb)*PN1655-1p?M~o^pPIM@{HEY--X_v%}ayLrdynh4#|0p};MU4pKHazYL zq1%~m7efc-DGI3SUaEt-F5M+}xP9_guYBCL+>C$o!VR3TQ`_e&|N1@L_wV1fiw!r1 z%zpBI{-7(_Rw&*Wi%W_6)KcbaS;la;e!)?$dQE( zl1S1`H-&^EPAlew(}_C42&0QJ_7S6vH{zIMj6UetqmMt<*hi2<3R$F)M81~5lChw4 zCH{6HakH_Op`R>8sL*(Hc}N#?2N~DkO0bOwqHHR@_@ku%JTCIbB0el~X{MWU+Nr0X zf*LBPoQO&)Cq49pYN|c0D#@v?!s^pcv(j3tB%=I;E3UWRx~s0a+8V5|v-0p$50Vu7 z>aoQh+e5RGJo~Jx(LxKYv(`@AthU!Wd+e##D$8xP-I81GwmtAb?zqLWODwX(0=p}% zz5;8jyu9K&t58Dq%7ZMl+-Z`Z!4)bYp@0h79HA1$#-YOu)i`5~IZZrqk84tjsim22 zT&bv{_OOVmto8(Jv9+FDFTDEd%kQr)?;EqsGt(^87c$@cz)(Wzd^1%;T@|#@Lla%J z(MKblw9-p6eY93jKNYpqQ&U|vQ%i-i3o5h-vz=xC9_IGpzz43UF0rdVyY0KoE(Y$p<1SAs0tqo! zC$7xZhw#O_WxVmKbi#Ze%&P*ukr%&R=A3iijkl*Ae~fC#BCp!_$;ZB1KD;lZAG6Or z1MPGBPD3u1zXvkRaA31~ps9T0&99AHyyr@#T?PIeKT zAOaysmfJbdf*Q;q?mFnf4@$6uywe>CcTvLs6Pj>$yU>LgbYVgk>H>x`Y@rNeXu})A zkcRB|-9LKh!yf`Mh(HX00Ok>Zf6(KH^a#Kah3Ld53bBbtoZ>&I$iym6k%?N|A{V>p zMF9{|ivj>65y3ddGLG?#W@I86+vvqN!ZD6=Bx4xexJERhF^ziMBOeFQ$1(a*0D;`& zAo=)5K_b$R16U*@r7-|ULh_N4lm;cGVT?;&vIz??#sWI&Nm5LJ6rvPmC_!n;QkGH( zq%L_N?S?_mBKWpGMy<+SL%tEs`Lz_&}mM28dIJ6 zw5BvAgAj;H1~RxJdeK8t+brg`AnoK2O{66+1Au{JVj!y+=!aIdYSph|z^YyC2U)v{ z0ScHktrl1-1}xClwZhe{{cvkr>&n%!mem4eW$RY=8rKW}HUk#OKm`IT*ufq)u5cym zTp5djf8e5+{}7}ym)Xo_Ub310r1(QL0?@UW{J|5zSVSW*(Fj0b0u!7FQx@>h2|U~Z z6#rNREPx?^X4-R;xV>i+IC)QD^ftG_)nq+2xd7wt)1&&-XhjD)P*OPe33Z8ciuJY3cO6HWv|m{8=UF$1v6upaZmS`2Ge#p>0tQUJL9 zXu^o^N&&qJqr+z1YZIDKfhNS&uX9~&jOW@{8rRjWdfl;N;R<88R-ng0?y&`ayjHG4 zwwM~AY-KU~TVaqv0RLeBrYHWuiAG!*5S&mgt4<-6Nu;(8oETFcKp|yOTw;;DohNYV z+2Y*RbCbqJZYSxCPl9$5&v~|Ja~BX$=~j2T)*bX2JOR|5B09SVb!d4nI#Q9Em%Jz? z1t>;QY3)`TrkSp3rQPcZAqc?}t`Nc~%pBmK$F137HJ?dA-6u+guFM(_A3Noky z*GJ9ut^=HFU;nN7aH}&k&lNk#f|VOl+B(!BwODS%BpfjbL9l^T zs^IoN7*U3Q+>_0njCq~$sYyEaH}VFV*SNQOf8@ zLw%x?hUs~6dR|LoebexDFMCOC;8Ytp>;+au*vW48=m~-BVh{VQU483ZyQ0{|jyoBM zO$J{O8}Gi*JKyt8>|+BS7`+&LFB&lTW;5IH%a(StmA&|8S8A$H{N*t%oM8-KRRbN? zJXk5WNpTR<2`{&!zxe^(v*+ux3DY+GmSd(tbs ztVyn7lP_!k3}!Y$7=EOnc=eVgT3p15Iv0HBpsX zFxbNORU#!0!!Y~;FZ{wMZel2QA}{a)0C?gp*g-T105JRl0Wed|A=hxl8T}=f{dtt0 zS(J2D6rk;&LKQ&&_1_sNfH3ORFdmvuWf!6~ok307D7nb>UslOp?9tU&v4D01Q`0>D;sB`*Ac0IY&7c-B7A zVl5^Yo@G?U^%HavltKv|paq&R1|y+i7XjAPc^%r)G1Ph`qcm1sdSPQWVxyFJaghic!89gSw%Wh-qQJja3EwKyel)aT;g;avJBo zE!OGHz#G2dS`pmo!5)dx6<4`cis4>P(q3QHRaRZ67&cbG_0=I3QveiSI{gF5S;145 z0xe`;YFOWVT3>2VEx<4oZt0aj?z5g<#U*LukstF78MB2|g5-3+eXsgWJ79oRcorV1jMfxV~; z0)yFMCa|f(jV7B57Td7hoet*X;E^Uk65eVa(5z>*>AKLA1|*a0d)pY(kK zD@0!^I07m}A1lbhg4kzO;^%(;0w-Ex7YG3X{K7xH-+|uQg8Gw3^;2^N6w%@8p9vjX zF4Ukc8g@qR5^GRhXih0>P01Qk{nrfI+O1(`fz@CP#-Oyy;Iw9|u?<^Nb>@xI z=(o0LJaX#`)@Ti4X5Aqbu@#u!<>1~8+Y;{G5yEDYCS;Q)z>?}~zBcKT>MN5XfFu}$ zE*Vo0Rh}4u(Jy&n0C?U2Y@z2F1DT>>ov~YYzSX`NYFV|Fz2Ry9ohIjV7FLi6RvOx= z8dB%!QRlx2D(exM>&ctF5f*gn)$pNbr0$j<(Ly0u0UpQ#DxkurI>LhVto3c`sM10% z9BnQj?a`X*B~E276oNk7gDt?StaehxIhTS?*FR+~TnZX=Q5V=Al+h)iLJgF4HI%Rt zYfQz`Oto!($<*7@)Bq-H+|Js71sJu`APuf-fq^Tqy`bN^;NIRSf#IkO_Gq@=Xt(}t z4Q8vkW~;8%nIBnRmim&G z`qEZ`qyY58J-umh=AjtMX$G_;jCt%22Db` zAN=M5BIv^d@B!6EgU{7po?&f+g00Z`6Lbv}(LEPJ5uL9tu>LJt+5T#s<-|6$#aUH{~z4e0z7^S3Q zmOUMxBR~Q(fdVS5@2LKZ`yTDTyzl%zB`!QN{mQRw>4Pm8gERne0au)!1ypo((yihj zK^^b_i_!rvl!7vppGA~I9Uv<=V_h<%1WLt%ok z_4B;-WKMHh*XUXciL&YS<2_ro^|cRh0x8rI6ZeoX2~*7i5@Ba41w z1Q^r;^n)?DDFIA?E4k?cys1CGX=oQGK?^}>htg?-ah$T-50rL6W9*FuqQ=JIqW;zN zQglY&X-2;(2+T1?7bh4`fJM92N7t zntjcbp-r7kX_rplK-szA31cwoA$>>M3WNn)W}#6=7BM1k8XNXFzUe^pq1Fg^6ITUn37d*ivK#MU5 z0WR2q0Qgxj60m}5tthj1DDPRMNBSsTRHbJWNzL~tDIhaG)H6n41rK-yUmZ-@@-2^O zES(w$ubr+$+Np_)@83u6IeW6N!-U1Z_IeF;$p^ z5fNc4@g=dd4;ARuQh;rS+cAA9Sf$ku09Bd3n49`DLBHuKAvvh|vp=6faW=teznB`k zX&-=E>W$bLzF2h%d0XA?8v+)eez}rgz@1ifm-joD>-Gg?0GU^jq<-W*aZ(eYWhYUR zAP~Z0y!jWbmL0IcAgn?E9bh~ps6ofCff+nP7DxhnKtdOE0wsNtLMecvuXkJ4DqG%S zc{e;RBK0k5)XmekGct8k-*+_z=2OcQeT`^=>2lk7T?h8^S4(a@!d=sw-PnyCgIi|Q z(>2*irmst8^C*u}6^YiPBd{|SR4LflmpEVx_FyAy8Uc|8SduUpyJrc222em|S>c5d z*R)@lSz$W`qDwlO0~9;b!11fA#yeWcm`HZ-m{DGp%){$KhI%pTW^+MfRYPA zA4Gw>Z~2=>!RLd16bJ#AW57q>Rx^F1oYmRQBeya9fgU6R9yCJX^uPfo6|r+d8W=(% z6apIff&dspd5<#xdlRDq7~?06@+~U=%rF1_p(W1ed^B#?rj7ao{ybrB9jUEXs-4=b zb^ob-zuS2u*ah36`MNCsp$}j|nOd@gxsG^y$<` zAVGr!|MW?y@K3^q4H+Ut$f?giix)9s)DVDU#sLE?3Rqw)fB<6@jGg4jQCQ0W|1?+( zuwcO%ngq_AA<(3Wu^&JBVZfk4sD&9#gb7uOp~5JqPe)Cdu#~D&3QPMnnIPmxg$x#g z_Op=T!qy3ADpcqyb*m7mKP_MwYhmoy3`{4Kbt}Z}g`XEL%mDmDuMiN1^9I&H3)epZ zEs;j131$KRsmhi~WzI}9rL@YP0^wmZsLdcYY~0xSLqJ;VXq92p#Ee;XP6cOfpRp_( z_U75KefI`V`*Ls1$7dtgJZd>9Pnn&9f+`)VQ%}}MUBB*1h%4{iM|l??UVQoQ<-2o7 zzutWNPOkd6>Lf(f`}m#k!x#TPy?pQQ%X=?B0sRw@K>P5+Pap*c8i=4k{s=^&2_LG^ zLWdMuWRaLM>Tsi%I)v$?0gU1BA`>qXfB*t8kjWUDXlg=$05qtPs2hnAW&x+j80Ckn zh!X0D9ift{iL0=x3M;e7s30i0FbKOjrzsq03~PCHM)8_&G{R&CGKR~-OwKmTZzkHGrsgKr>R zU8(QB0uux_!3Bves1FGxJXYCG5<*rX2_1^|!f78;$cILn2(d#NwbdY{mPlfWCIK)i ziCdUNB4E&whO&_;twzZyrv)b1jox@6eUuEo_##6UQsPolDXk{Z(*k%Wh-v~b`4wVJ zwW6^o%6P5}D)`bXiOU2zgBb(^Oihzf_KVKO9>WvQJ@=%n(nNKuSzc2A zYQ|a7ofp-4vz!z4Iq2m^d9-M!I89pVr9B0u(^06a4ixP~-L7g;h0x9wPt@DG)mOm= z8$elS9ZRft&#kFC~12&wJc?}j+}LtBkH3Ne5IOdMb& zV}zMe#FPY>(HH_0DA6JgXR3`1n_w##DGE61XMrIL#<^%cDM(#)VSaG9;ZYnO(*Xxa zY2ryCVdr;Yp=iVa-q>gF!+|~^?kcUgCPuz4uSV8O%;z15LWna*9=T+{e!!s4mLr3C zW}fA>IsBZ2wpr(#6{Q({^nJ$pjH3OGf9R#@XAZijp@TY9QL&be>Ql3mwf1oTZGZ%l zj}XZApIXVPKV$n3fqtbn11(5D42s(Y7c>wF-R)U_xLZT`2106u@NXsjTNWBYuED_s zBau^Kh)iM(kYMCRF=8BNT6CgxAxaoDsu2dR5&#V7NH(U6m!8@suy$=kbo=7h!(=zR zF)8dU2@?Vt9u}2=-AGAc(Go%UvalI+sZ4d5fS6|Yhv*5R4{>rBoCp#H!el@LxL_G% zy0<6a@XS+Z@WlJ9^FDb!hkW5nANbr?NZl}Jk)3iR(Y!;3@*vGq`Fq-@DCtN{l7c#% zoKC5(Mzv6)%4-BXPubMtz_cAGSPFC{D_3bN2^xq&#;T>Vk`)MM)eS=bBxIHdO_+s; z;NcI%RE;r<`3Kb;GnuL>VHP+6q7}CAg_m1^G-5&`nn;5qisQ`U6h{D(#AGHqQJ1=C zB8vtYHTc zo&z8Nfia1(Od%U1$u1x!Ikm+C+iS_oyf>Sn<*bs4Vr0;C^GEk3QfKjUPP|lFQcK44 zQ<8Lr19}AvRrG3W(a~RZNcBmmT*rU@%Nlh&kyPyn(3D~;(AEs})L>0DgKV?vEUnr$ zU0L;5Y$FJRqV+6>n6N_2RHibsV28AFLalA(#9G~&20L&zg01TX*>B37CjP~1fV@S@k$P*BqRM*#37D4XP_CJWdJjRe4x3Haij zR}{hml1LOGHlYDM@PPvw0NY+PAOSu|Kx|1dqy-2ANfgNEqx^ZK9}Yz*6mZIuf}|v{ z&_yk6852Qf2Z8BfU}6;=W0|~?mgbek0U#KYKDIYR$>a$Plfo3uR$4Pco;1DBIq4s> z(@3NRHK?Evf=|h#3RO5j6~NHxPQBxaslo1lRXf%Hk}5#+G&R8Z@dPV@rM6k>GOHTY zptAyj;ZEd|SXSL2g$1HZ503bQblV#+r?pHwEaI$oWvh$-?P^!N+Ci^+HA5ZDaN|1Q zc*k`Z#Evmxh9G024n!t$k9SPi!8T&Bd2K`^D3J!kUe>ZAB9UT2_`&p zS)KIIA{3y>8JZ9icWJ=Pjnffuec=l-_+oZPl8aiJ@B^4335Z$YNl;XGP}L1uDWq^% zY#ZhPV9d4wz?kS6q_P0D2*C%h-BJa>LKV7zsRGo^7=C9|8N@2VgiCZnqfVh)@JTfj2vv40`Sdo(eX)g1#(9`ltX;cyh3V`I)y_8AStt9@}_z z+T;lpN{|x97BH2CElt-FL><77D5w#7P>-lY{qf!KeiSmYX~JwYMZe~35|B@c8g}?M zDr6ftYe~%xvQOomKB$5q4d{d2C2}9G4Tx>CbasWQy`T)|(t{c9b}z$S_->bb+a#Qp zxg9UU$X96c7jotzh?#D-D)X=Frt!OXtm7a53t|w1z_;lIu?E$vf%UC-y&519`$@>Y z5RQO^?QI|X)Hj_jac1; z&#sw9KCBT1u-J>)^~eD}=s^#7&pZS9#L^ zhav-@t^wS_pez7Pn$CC_24dKvVM+VI06eBci>Vv?GMsGnf&Sp`HHUOimixH zukPvygAfP>3khkg-CisR^NJIg%*mMl?8%-C;jj=B06`12P~ZeE_`q-yC}9%Fa1#8$ z4>I8l(=ZLs@C;AE58f~iPvH_yVHM!e4b?Cc^iU5cArnsF7P4hI493@1iz0j|$Ry01ohhZBXN7iKE~93T|Wj|X@F0USV27C;}! zARiP!D)b>I^r2uXKp!mN3>?58dH@xhptyXF9~@u;`0RG7qIDojqGo4dsKjBe?&|y@ zqNE5KC2A_@;w!3=E?Q&)A4C4Y;Oj8ZlQvL)q{Dx(!`H5(J5YsyLQsORYT5?x9n0-P z_(nrCBntowu-Z1CV>w~k_`P|5-!0HE}2fD z!6wVV6ms$=cXAWT;3hXAD237{b+QzU@+eoqC^x|ts%**zKo~|uol=4(q)9~xps}#e zL^QAZA=#iJEwaht%?uhr$B+!jitHm1P7t#5;IL3TxwAXBlRLc= zB*`-i$Fn@q6XCW{Bn55~0D%noU=L4WK4UT|OCc77GCwsTKZ8;e7{NdPlMxsp7#IN- z2=qV;bU!kpA)aAu+aM6~&E zV$KXeCtyS_6~MCyKwsia0Y+3RO9Nq4~Oyy1k?7`R(KM)A;sO=pE)!ckDnaV20gek`CsyNd?An__W zfvgd9026dzQYRG)N3ZluZ&Ueg5R`!Q_zm9xK@CPV_r zH8v7Rpan)i0zg1Wzn~rbAs>D~A8bd^hC+zWpfUH-VyaX!h2SrJ00Ev6(M&5d`Equ2 zhoSg_=!`BVCNNHMjugtPHT5T{#A7z$4p1pu7Y-crATQv;FkPLUVS0^DAel>36))C}36@0Z1$q;Yrc5m}GZ|Qb! zd3A6H7jVn)Z+~@IPeBjovvKE>Chap8@H1H*lv!J$7B2U4Yk^v8p>u0t7JdPAXJK?h zw{*e(^>jt|TfLQB(RCPjK@5x!vE;QRrg8zka&Q(v0SsUPs;ow$Z!B5V;zE=wN8(>k z1SV#p7uu2^+Oik)A#zm582Z5&Du4`p-~d*~2)1x`W&t?1_%d7SglNIwXgSGg zl=eLy?C;z$YGn|`9^w%U)k1P`QQ4|dUu?wy zA&R3I7pC|=C3kX{@)i~p7BqKrJ-2j67j#RP7ebeed4U&ZfsE7mjLrBL+L(-07j(&$ z7g~YgAWL2oixIUY8fGZ63V;j>K#y4n`~D$!GDdvkyUNI(WsKm@Rt0bsx%{s|USHg$-rMkLb#&hPy2 z7k+V;pp+s=xJW4`p!^y@GlPzRrO0*m31|D^P4Ogwod#*AraJ&H!z9@7rnVuf_8}A% z4|cGxit`A&cHVZ3giEjB^i2)cpjFp)ZF!Fj(O?qL01X^Lo@sau-w+O$m_CvJSaErH zK3U-uSm6~|VHH@Rps6?)SOFJK0T&V)pmAXp9y%8onu;O%pY4byFZ!W1`V}-9qCJ|5 zH=2q$`V}C0iXj@LOTms(+KyBj7gjnJa6xi!A&Z$67HpvvaGDruVHi@EbjKKt+4zjt zIH-x5jfa|z-B@+q7ywr2b~*GVA`1~+qyVVeUdd^&W)!UBJyS;JY z7T`O+W8oI&d%o#gzVExf<9omPyTAQ=6Ko32mb0U{uJWM>~DAh1K>0RlV8d!PX(ph^?}djeVu{V>_J2+&B9 zf+{RqD8fR^xttiaq92kgXqmz-=z%dbKp396HB~!m$!fOM&Bf}9u7vR2I5LE*6B9@n z6O=&D0Ri9w4)}nN^-L8FfE%9SS)QSwhCkuBjk^n=Te_z^x~tn1SOL4Qo4dQ)D7Cx0 zY2g*V+tWe1({X_oQhKG=`_#!hz2DosVH&34TfbpFzv;WauUNldU5ob{zyo~OZ6Uw~ z{8>A97CtwO)413{SEzy7!Has0i`|VySB#Gx0KQ;_xaHvz2b>5IMy(GcD8LfiuU||2 zo5V6V0`^6x^d`n~&f;uyY~l>g_x#)!0o+&0-FlOe9I!+GVGK@S48-6Bj@;k<9m#_{ zErdW9{XrLR*%Y5t2zv48Fkk}A@0Nw2xS~W&D;`R+d?{=v)085!tD+z7f?@Ijyl^35 zpIK@1V8bdT3+!>l(&`UhEUk=F#x{7bsIbnTjNY)5JokJ({hSg4PHo**49T$2;aOPG z;1iNQ=^@<@79G+b9iSW6(oMlwOTj+v^C&eviaWjQJ^kxNoiR8%r5VH2OWmbg`s~pj z?N|Ej-Jb2&{_XEGrfa?KuULy=Ar`iHi*FjIJvZ2iU3Ag-*q!~13!m@>KXe11*guzA z-55is?D#J0`N}1ndMI-!$0kzZBx-lJJZp0lz%s)Bz1?Y)&g9HC;;cq{fq4_a7sTo1 z5<7L8z)|?26i=~9f*IlSQlkFXA9!G{=^Dug`}dLj$B|qVT3HCEcil-z>5|F0JRg0%^yPZiqJTXGb14q=Q*+tI&$Yhatn1p zY{}Ma(N)M0lzonopS+`uTLKVkU|ePpvYwah1o9r9z4v zS?ZNZS|(r7Lb-CKN|h*a(ZVIO)XbYQY2v(z)8;FgFjx9y$r7f@khns|TFSI(ELcxr zZITMBDy&vmTh-cHD^jglTW5h4JL^~3Uue_+nl)RtEZ4VixeoiqE5N_Ic<*ZXXIF!O zzXJs1&8uO+f(6Em5g>3_fw6ykHAIHIKmi#t3M^mt#d-7PQD+E{I^0-+uY8P!VUWyP zLjczSRtK1X06`BP4Vv_8V&TVv3KJ#>=>sCT@e9HyRIni2pFaqF`uuS~oqC@M7k&tF zAOS*k2hpnw`C)3`7Zz1_@-)k3LS~$B;t*4*BCkM*4w}AEyl2WJXV(atTKsmGRM)B!!ex zQ7OG-6fHKjB&JL}l_}<#U%tc&Eo-*PCM$5VR8p3)l(N(&n=rCTEPBGih@Vykb5$@{ z#pM-O#MCm(FvR>a7h1z?6)9X;*@0SH1A_w5fe^Z|hcG4KGx0}re#0uK>DaIQb-P7A}m_`-W1b@I}CTLckw z_gsDTsn-B?+x1}`bqyTcFa!tx2Pj-V0UnqjEg1aJU?&esXvZImWN{&eBWsAE4vo}N zN6I4BAtHz)Vj@C_Gnq{Fn5xGk+{T9qx2-=gU+tDK4#Y_Jw~Y5<9m*2Jm;geKUs3(!i2 z0IjhmKog5OKn7@M#2)))4m6NJ0u7LX7zNK}&Kd?7G$Eh@)&jp;ar^3^BxazI*;G zLa+YwiQn-52us+18o&>ItR!Qj@PsQm(T500=nrrZOcaSpP79(CgDABt znW7?COCr|VmbSJr(TS}11S?Jfr%X(7ik~or6tx&dE@qK!Ni+#b>O{so#bQrSiAq#3 zr725cWf-z8zINXsz@$Vi?W;``7!`u3?MMZKulr`iI`B~YE`aj z!UE1S-j6wp-@a%Bu)*yc9VdQT4~P@Y;^ zAOjhgfeA9O%jh{k2iR*D_Z~pKVzR4y(=s3Z)aAWtO)CZxxK418(+7VEX9hFG2@Yj&pI`9c z1w-V)5J}=@A^=3qLi7clEfi-lN~q3W$TL8+a1wy<10W`mLX2{Bqafv>4n=yyB@Jna zD1DmKq@)pxnBpRzh-pkSp~bCbks=V$;zc4d(}?i&rw{?EOk-M8IBiX9VicoNoWc~S zs1X*oc*-sRGPTF5#!*v=gQHd3I8{q^^%jyFMiT~UIRO}h0;V!+A`f#bVX!V)dkFvm z&Y-))Fa}$=TBU9XaG7EO!vV6(jO-?GhEXVB6vDEWB+1Z=9wY#rWbgqG5YUSS0PlAg zC{MZQ2TWp8uU$HT<~4P2uXag52++eN26lN%;8{RhLV$pMdeF>dVw0KHgTV+KkXqnn zz_-8)u4}d90Q$s7KI(D6WiNX%0sJ6=u2^7n9=M1d}$%kPkmRsgW+>2d4?Rz)WIN zP$BaF2}dw^ra`@kBYZkxM^tzcj=*pxDjbms`_!ilJ_SaWc+@Q+WvNV^YAmJ-)u~EO zQ!n1C8)Xb*s!9&5U>yb@$a*SM-9@gd^6@_?z$;@&<{!cc%^4<10K*Qb7rr1K2AI{4 zNyhFldL_Vi`Z|FHjG`CBb1Uzr{F+k!U^T(DrE7)2gAdb+&+Tmz&uMG$21h zh;wiRu#x~Q02I)bt~}?-iFqy}f)&DU8Z0#Hk=dHN-`%GLF}OhuZpecL4R(nN+TQp7 zmdJ$jP4><(>N6MRC`TTBc8)SCq>LslNd!((la?mo2FujJ4Yshj$4%~Xk9)%o2KP{7 z3MVPDjZH*pNhy*-lUU%w-YbqOj=u_4TlD+JIQF-|_w8?j?|a|F;ISY%rz*%mrZu}F zfG35Kxl!>dSPMWaW-qG&V;q)}3J{JEmdv|;xb+MU$hfnd72MdcoYTJj0R-;lfC^xs z&bu@L1}@NtC^#Sr6X;f-hkk)S)A`SV26PiLP#z3apbtKfz#^`Rz8>hWJ3@%Gr7J*Z zt_S+)xx}=gHJw?qmrI;z&s_!nQR*g;ViXBfAjhO5q3X8!)z-Z`$Xv~d2y&wT)@i^s z2M14h4S}c;F(Z+&O9Y~uLGZAS{ImTGgiYSkqndPiOV5VQ!d_G*3i zcXlvqjgSUDcp-r|cpJ1qE8`(4qcR@kGD_$nOsFzuUNiaL@*IFbG&^23Lp) zg206-A_#&22w@n8E%JDk=WG^bQ8l6lYCt2JH&UDzU`B!@AogvJfC{NsdZSl*Xn=aG zmxrwfd$ETKve0_6aEMYgdy1F~xR(pG(14eY ziI{i`13*@o<9vECN{K-_$>LUrp(_%neX;|01aKhW*BhizI}t+$U8WoTAOQW~8)qc0~r)Gx+JQdIY@Zlbd-~$mOF%>`oY=;XP&;+1B3M?3R3p95Q zv}$#S2lDhW9s@xTWCs%2cR%QZKG=g6nUOtM2WF5mS~v(QqcR{Fk{}6^ZSV*+;0KIA z7rX!fF6olQ00=Gc3$f4zP|$@+;Dt&6hA1)!TnL6<=!IQ4lwBx>E<%QaKqG5F32n%R zY&au2ltV(2VMBs6N}?p0@DMSTZg<#+s89%|R|tKW3S#L9V0njViHCzIh^W8{ZJ7#( z*p`I&3AiT4=y(n3EWoeJP6nhH03SXo{->8Lu$_%%WBm zw-<&nSHZGmb0s?qpbx&{I-oI0wUYpV)eo<+X_wUxXJ9)%kN`eVjIP6eEa!6W=UcGl z0NUti5m0|f5C#6g1H)8I)$>`WETVJ)oAngO#aXZHg`+WV=jwePTfLw zrfHhkk^$KA1J2`}Kaee4=R5>L3ZF9*0m*^{*&y)LF$(#R)&-Fgxd?c`3H2$FJGg^s zpr09;ksPUo|EYy$fC(RYg(PX9S7-)?umrWh3%oE4jX(jba{(Zr229{6bI}T2;0RE# zlY<}#J4uv635Fs1lROEAW2gpzprUH922I(9OSzQ)PN@cv010jghX!GlN}>>cpb!_K zmEmS#c=!;7fQLm|q-cN&c$k(-+N5&nma;&ItN@pXSfzJqmsqNoTAG+#+NG7~rC@ps zprCM$=^CU$D!S4SiDWIPg8{}6EW#iet3y}{U|Fm|0cYhqKX4ffpc>f;JhAZu=;sf$ zp+Cy;r>-?y=+hn0F&@1YJrHnB>%s%4<)|_@0+dP}1ehJ!L7ol(FwLnhwzV$!l0E@K zAW%nv>>_{jS3g$w9_d1V_J^pZ$sD?v52XeMpunCDat9Fd2MkG1AA<)H`3GrmgZP=B z{n?*S_=E&H2xfqV(3*u=XrLu&tyhSJ2s#M=kH7>EN|RlH3H>2wQQ!&7g95zp3$V}y zHn|2LilXouuPC|(f}jS1um<=F2>9Bf{OY1>KnP9=2?5K7HCm%IiUu}H31~nN4C@F5 zaS)$?20mI44E7M_rler$q)vK=PWlN^DwlB?rB#ZTSc;d7XtH3MvWKa%D$8S-!xv{- zNCSYUK}I^cvKxm%n(h}W%Y~YpR6DP;0OYY;&hlDtM@#*%8^AFN`4@EIi9Agp1ic9# zu~a?*V@`XP0oX`B%mk|I@&M`*0Xr}O-C?7YN4B%eTf8T!;3znzk1T0t%o| zuD*H)kHEN)>$quP22D)4og2k^AP65i#Z+v?@Jg>>XvMNi#UFaPZEyux;3$go3ogk7 zbU+7&fV+aA2Y7G-wh#-baFbQMx_STyNw5Zt@RE#h351{ssk;V{Ajpug2U?H>SO5US z5C?Ri1}%vNpRfs~zyy~-$)*qjrceesa0-ba1%~hxT%5=4maw9sL3y=S(2g(J!(!AKu}N z8epsWW3>Ro10#Sh0E5F9Kxlx59G`kGq$R5O3^3_af8()#v^vAyoF1)dFbi{Le(Sd; zH_^iN!AF22hyNl^d;7rN@Hl4dl9Mn8bnpg*kOfIw1yG>6dcXzf$_sp;14>{D zbFnDAfCXx>2asR|lyC`H;GpT+1x64I0FbU|0RE=d;vkOM(5%)lJ7oK4Ke zT(Vn=%*@=E=sVhsXo{8-8LB~Fbbq_Xu{JU<8h0K+7G~S z9s$D5!KEGV{2sA{KLlf)5C{S8fj;HKO*`Nm^5SyBg0@fCV(b3Y4$|2`~bTkgmMY3X#AF4KM|r0`W1X%Afqif=uJ8j%+XQ=Bzz3|4=0qT8KmobBtDu0mcaR779nuns2W~*D zZm{3~cEI2Mjndpc;NETqxQm4buHabct`1J&4ldz@;NZUdum3u{080paKnPV31u3wS zWQ-NJ&@`000YUk*-f51!hnPzoiLm9YqkJ4^dDB6);Nr zFaff_1tnnCj35P85X^-D<+jiTF0cc#Pzfin);SR72+sszP8YR+0=a+*(jWvVz>>c} z3nGvY2txn`kPm=>drt}{RXWTf3%+q4=T}5&dRqmUnGAko1k!~m(QMC=K> zng@z&-*>>cs;|VvYVCG#?b{yvBYnHzKH!63;J8cEgFxX7-tNC!yZ~Fg%v-R;AMk}h z2vqRa82&~!*#de{2~-dXjv@ux;t5euuGXLZo*)ED&;j;43B(2V+VNwI7M}nGGyn-A z%L;RT1tkCgbioKUFbIc82rZECU7!RKaEKby=ZUE&OcaKYfd*Hu zPeEq!;#CU@AX>R_vGT);7A;n+KFJ#SDI_advQVX5$j}+Vh3J8d;$t9kU%Yp(?E#g2QN%8A%h>RkOc=Ue(~`WD1v|l6;vD{(nup^ zc|ivNDB7fmHuh)%09(3nVTY6;>7YqopeRB*3&QNjf-%FiAOIn5nxqDbcxmN{Nj@=Y zPLbravraifB63fb_9Rj!KUew_CYxk|M36M_2&9uv`sm{iP8z}F3qbg&6c9i}XoQnR z7Ww1TKhjtum79*D38zP@QWYuzS`FYI4FsUT7z)nX%2r#=(&{<17RYOYQ7R}4x+czW zptHmNa^NpAglOP1!yHg-2hf&P?J#VQ?P0dZd?0OsekyQaTOLH=0fGsh|I6U5b=&F=&mFH8hKA7>lPd}Pz4)Eri2OMw>J>WormoA{F zA%!*;JWvlp64`(e5=W%Pks?y?@t0O;2!aYkHq^S1N~8b)fMF`B1Qi~A942TX)yQyd zNK#3K1wK*)x`-11fTasHASlFbEdlt27g&lYq)?l5>f(u*AmO0RH`S0OlTRRzTu#aD z{KOQ?Iy5=Q*R=5)Ca)essXM7>(xM#|H=iFRdcT@R$(Z3 zRjOPCFs6wGjBzV~x6ne33^FDl7Uju|*{4L4qhQupm0}o3pEl z2^=tPFn-uF%P#3KFmwD2aCAU|MSfdWd<^QZe})SDKsAin7hyhAn(>jZVhTG}11!@3 zGLYg2q!@(*RDrF(2%!QNdyaKzp@AlBED9XUgC{Qh8{FeU7rsnAEOTMY zSk|(b!ORRW(~r#dGl)0f;X}iKfG(^V^ zFv4%Vm_-rfPzgjJ0+E)m1Qo#cgccY{4~wG+ES^A#R5-#Bk;{Z5I@w81%1M)>gq$Wh zH_9UIsSre3<>yo~h&+IybghaV>uj02*bP7cvTK4T*Z>Kb{HZ0mc$My=0=$1{2|{n0b+M*&sMC)oRA2$AX+Q%8roGij#s?FqAN|ba&9`v# zU|>q%Th1VaYML*3@6%`hguoit^uPxYfYA&9Sb-TROfi8G4!t6?2nYP&IrZdVJb~3L zAvA%X}voVfw=Y)6og9=v&|HJpZ5QZ>qAx&-io|@v+WHF7Y z%H&fYJKTX1Pi)07z6Jn5;DHM%+yW68k)mJRf)<}p!U@u_0VkxW7OiLnFOIs2O;ALt zj;O;G6hVg%tg#SBNCFoPfis;MNDn4pg4`H^iWZEZ4RV|#B=oR>GBoLLzlcPWj_Org z(87(3q=N_AL`FUA0YhjQB^o;ENlj7~4V!fYWk>nh%o=G!ej4p6$JWY0B?T3Oz=L-l z<%v$%fe=b5luJIh5?mM)Dq1P#S&~^&SpAlCzFQ{nFwg{jq{}VO0p}0KIa2f~i(nN9 zr)i|yzjn%xOz>0STS&T3Zfd{+qi8?^29tn@|NZ5oJ@A)oTqCc?L?8x)xlLqz^P3(- zYyuV7rvgc_-ofy|0q;{_`pW68znJDU%=riiQOX?>h6jZtdj!eQgNOCF@WSUY*@iFN z;SGbh!y`VKdeWmFFJyHRfoMT2Y%z>B#kdui7@;Tnpqd@53=c@)Kv#Vvw&cp+IdP-3%kp2TL+Q0GZZA`^GEvzd3_nheo>Pe1lCV}@w;Ys zp_9O=9M@N5I2Jz~uz>J3#{$MG=Wo2_8T#%EVBhnB1K7E)P8Qsg2=WSoZ-5FU0A3kT8LUS6~3r)Qbalke@R|b9Gpmj_abJ z1{%z#W@gwSfD93ZGoYahI>^r;{v#kR6XFm^umA}Du!BF8X5*>J!iKWYs<#N>ExK%# zF=(JRG^kC^QO9$h^UUX}-x<$*|L(J9H>>EaWex0OC;Q&Oj*47J`YFYnic9x$k8z6B^P?fI7>Cj`Ak((RF(Fo$UI7qZG54zzp;r>;4A@ zz~Jufcp{}Hl<>Ug9Wr~Tu%#>w+455;vgea0WO#sng{d$7K#+&|7A6_M&Ep0th>XK6 zR1XzgXbAa$*gQLpA&;u*T5Hd~L94qu6tp_5 z!@5GqGe|&#$&x^}K?F!hBpakb9Lx|zkSxi9gdXfcw#kq}*njPEV#YBmI#A8-mM)$kU}aDWP6z4#%i?|KWps3-El5m?K^&v1Z#;62~_z3q5Jcr&3+ z$b(5_luj@{Ow2@0+{AhN1LN~VmO8$Ao4%InzI{8zd{aMFY>%DdDV3=qpUNQ~>OVH{ zzaE+yB~l^;{EwTn|AGs=zzuwmV0;h+Ap{Tv!ATfFO2{)BSVj{(!Do~+X}mfRoGeIC z8#$W5HIM>fBm{2Ug9ib}ZXCyM+ylv~KnM}WA&CMctO^16on~sLSRsqLn-#vxig*%+ z)x!W`I5jNPu34L({#mGHakU??fF`JmCTv0~Y)D>dj=NZZzLO|UGoOAChGOA0ez-4m z^B!;WLR))_jyjeEScGO91&S;mxX44oc#Qe7jA{Xmd+DCgyMPR!4(rIR0ce6I_&x1_ z#7Hb5?-)wr0}rE|M59bfN=(X1q{K_S14a>#OMJ>Z2!u@Z#0m?U=o1;PygutA4+;xQ ze;dnvBe4=Y|FIL(sh)z5^vj_g;vxInj~*((TFehN0FeB!0$sF%L-0kL8xUXAgG0E$ z1yO@FpajH30TE0_WuycYm;@12gBD0etD^xDoJ=)v%wzmOI6@F9;2AxTf?qTc(F{$w zD$UXiMgs{(4RM2ZoV2Jorg-EuW1tI8<44q~3ksN~eoCNs3X^p?L_&Ov1t5c7NRH$v zuU=3!GYrG%=m+&l0O@RiULXSkSb!hM3sob43Lq{~qX6`2o_orm{c;X1q&4WMfKecW z^12KJ7>xYMAHgs^XQM8Qu>eEFmOhA<3=)Ea1jwBHhn?(6p9IR`Bg&yHA)!>zcvH|4 znnc(F|Bt3*6sHUi3YAKz6#T@V=8-zx5-rR%}0> za*z06OIfTx{Gdhti!%PGIs3CYo8u1-9E85?OCYrZK@bEbKvE^e6vS*&7idx_jZ!I< zQYGk2L0AJ{{0|Ns%rMYWEAYiO;6O1A)4>c=!IUc+Y)7hSCc0au(b1(_K|@?oCS1`K zY{Ew|qz-``6X)oMRr`Srio#oA(}PJ!D)hs(;5A?%0|gj`ZE6Ancpfq_h6*?XGVlcl zSWXN&jExkH-$=dTWUe2mAoOyDW*G$uIt>A8AY}2+3J4&D>CerJf(9VS8~e`$3Q(-z z|H%R+1yB%z;1j-~j6?)2R%2aI@8|^BlEkHS$~#!fsm#zzw8~E8L=FW-tYj$@&B{+n zp%4{Ifa|xNVo??~OSOd28mghT+`swQ51Ek}y6lf!JV3oXz&5DY9lbe0zyu`aS3tl7 zObJ+l9aunc0f9AGgB4gM00bmuSS3ADLGV$$%*%W|g#G|bJqXj9>r1351T{4#yt@@y zsXHf}Q&B^nx)=Zs8Xv`*4l$VyVdx9&Y{--4tx&s_Cg3&coX!M5faGuhU+@J5I0FSR zPBJJSTIq@fP=Lc&&IaIzaxy1xDJOmyDCB6iGtj8$@CsfNf?n_i0%!t?L5t|Z|ERur zwbH;i)3^XwI}FqF4GCD5A6SR!huK z4c$=24Mk7%#6aNIQB*!E_&4!0#eP#!d=s&9eGe9eskQv68qLugwLiN&-P0}ImFvGj zr~}ungF(OqOi%*Z)q#J-1cQ}b7XVn^-Q9oPUEif$K(JkYm0j9B(mD`?I=DG|?NR5I z*L#iLFolF81lcu>ielQGW4c~6Y|~t`JF`%_juPAWS-dEu*|b25?`_j2B!JHF1z=mq zg$yovyp`RQ3yI`Ouc)AAnLOeVf~r+DLyc3nn3V;%&NDazOf9FYRkZ|m{~idQfP6?b z{Zx%>aUjE3u(P-h0p-;K&D%#5R$=X15ia5HAYl6~*BG54m06i6*a9zLfhdOJEx-XPw&E?w zVlCzZE#BfMyHWbP50-0P*98LEt=%(DW8OUhOkiU+mfeDt-7KJjB{%^r*n~BxgEZD- z*eyT>--5z zeV%FR9RVO7UaOvCIgIB?VC)>HRtr_C;9$EgP*8ZV6dvJgR$*)=N>Ff61Z7YKRaS9! z%1MOEN;K!GjMjOhN~@$w@vvdX{Y2)IT;)@tdm~X4J>nzAH&f&{4oge+cp)zsf;C$+ zuZppPF6bwKgBz;RT4cG`RRTT61RYT0Ha_DMxZUB^fgJEEHv<4hu!4#H*W1N}zpn*CF z0yR6T5%`DQBmiUJY4&|(t1ej$5C#G`gRTB$U?X5>(rN_`|5`@n>S>}CSrG&cdp9Nmgi91KF8HcA%4CQEyb|JT(Trfl2Kyz zGl3BRn>Nr#3jm-d$N&v^svnDmBmk3evdI_lsxHt144YAPjm35~gEV+u*G=P!#$8Mh zf!&4U$mj(H@PI1ws*na)+pXw-72erZ(mn=||5$0$C4@q#UbRzXr`UlM7=jcSg#g%q zNT3J+z-d^aQ%(~AtRM@l;AB+}>P^!XPPUa+`2#3G|AHOpfDh1tzi9;%z}}+p(3M?E!t zw9NnoY@gH)?f8L|D)PcEY!h}+0k8&YFaTtL25f)^Xi$fBNQZey?C*$B#J%jq^=u67 zY~%BCF_&R=w#piQXAULp3F~3juCN}y=YO+4?knPc#sd>5gJ0+ZB?ttDo{#m|fLeem zUWf%LNNzuO10+ZRDhY!YU1GLeOEyS@G%$lkh;B930pd+#OwoZ0Z~?;#>FEw$fDPE$ zWmtYaQUbxbHaLX*$XNDHm6uM!*c65o00A68{{h2df=9OHR^jQMc2l~eQ<8mUuULQq zXbJ&>5ek6K3~zR4Z{<(Bv;e0j0T1xlDe8^8PKlgqpMJ;P;WY47-`kXqampU@HH*6S z;17nx5oY(jO;#|--lm|3Z7_#)=!R}Ehi(uDb%2L;SO;~82T}-`El0{rlwmUG?1X>H zgh%)nrcj8t#Hfr`GpAvB##ZKw+~#}Sjjw0rBbn_3%Y8OQ{FUf?JDEGcZ$XcRDTrcSbp-6XbmXma!PlHB~l<5`$K!5=u@O1AM1o8gY>4syH9`z$- z*a6`(13834cmu5eB1DMw-MU^Kuyq>9|Mi@1WstR5uy9jM(;fH*+2Fcfd1w2#e`Mj2 zCT&MrIBn%#-=)~0fL`Y=)v!DP4$m{MzcWK7Ro+MCE00X@}@)R!e zJZOTZ0E0X*4*{TuU8;s`hzD|*1_1bmaG-`}K!#=*hwBvv3w2PYlu+4!`0(Iz%tqXZ zH)qfm?M|q8(Vn+JcwELszN}nxH_ytO2bB}m=Y3vLBEGPcCx(@mg7Q$s8FCNm`v4`t zf;IaECJ2J1TECfc126CZ9cYE_&jA{!0-z7?3BYxV2~PBs?I1FyZA83zRq}|Nc>|Xz^c$B3*s~=*Wu^jSUwmjsSr}2>@OIm{ioD z!J-BeMr6SH#cLRrCpTVF)F40@&z>e;Kw)C@7b6rOMphICB8ikI!=f+^FyloH8BZ87 zfieUGMF9h(Nt;JX2of7Kp5%Cv1%wJ4NSL-1K*87o0>%Uc=o>)5PoO>j@pS2uuwlai z5-$#b!6k;pk2PS>x1b*d3XlKc!u1b>uqL9LfGG_I6e&=uN2vzInzd?Au|0XpCU%jcb@&b_dDJ@-63E8 z&YeK$(W_7I{?8rw=;g0}|1|&6AN=|AZq9&ju-^)R7EaJmLl(ZaiXw3mw6NL_bYbfPn`psf2|UjbH); z2rW9~gbp2H5keWYq@)rPf>5G^KQ7ENqC)_bQ6m7elu-sp9RUyvQy73yg-QTW0?H2< zV1PuH01P8iMJYtV0!k_|a!~+C5OIT%Vn*?U02lxfCIC;2w1XBGL}4Qpi)lcEmW=}N z3l5AlsuEQc{SZVIAiVHo4vP$+0TNhfIj06$6hTE4QA7g3C8P*|Q5hZ0(h^-11uy_$ ze~BfGF?t0x*h|5-|HPPLE=i_=W5^;qnVE}m=Gjk8geID4pq!Q(YT33H+qT=%mPcRG zSmTa90~q5>HRI6ZS8RE#M;pAhK{s!_-`Wc=z0iHDO)ZoyD zVKDqiiz#)Xq9JUUVTK1NG#ZN%jc@{j&<_0qhyy+}k_7}&><~$mGGH=E1QKupfd@W1 zbjg2p^g+fC9z3a%pcQ361rS=^a@aq@41vT3H~`8eMJa&5Lfdjy6hIY7OzmP*I|Smv z22`p91w~O<{{aZq9%b;46-ZeA!7MZ{5fc)9fPujVEksGx3{otS1q!PUL(v^k5aEFd z9ncJb5|5++gwO!Epn)fWP~iaxCahZPNXY(WE&<6Gut0816*d@Ri5Xk0qS7DxQfL1J z5ZbiVRtw4us9~$^_}zjc+xedGwVOB6cyo?5-Ux#nZRe+N|GnRypGW%m`k%kOo>Lv| z@QXX-an5=KMxOSphk^7d*uoy>u!r@>J_HKTgf6I{4JycE58_1^tiUi1+D8Ofpc$YX zK?qjm#*t9M10Fzv*+#?%4Wt1HAJ{VgJh_EuCfYsHnC4olNe#B3*&6iOuUot|-!}2rTX2q(|G4)f zZgKxdFL|AlIs)_#0;5YXde(IN0DL1J#8LI$X~2`!`n6As42PM^R; zGZ+yNSQCN^SZM_ZACYNB{o*46AORt)azrfAUSD|Pi5+}k1%ML7KXxET8*KF-NQgpR zZGt4GfC2~;P{9fk34kb6;de+-ffqZ%1PxpP1W`z`nk--|zD5BDC5Vy}mN0}UsNe=! z8UgVt;t3z9f)p3XfCi{Q#>$33d%fZ%uBxXj#Pme~#<(+Hj4^-|4-2)${|n}?QX8y6 zSC1mF)gEX>Gp*X5Mm0asmbbbkP4i82x5DkMHu1;JOB=Vi|Hs^TVFx_jf#*CQ z*f50Ev(?$PXFltLuvI54yA1Qh2S7H9^@h-06^odCJg`KY)Zz%u`L%%V0E!Usf)$VO zKoE|^3n*-1WC_AA5>^ETINTuv(N@WV(@=+(0>TGMoG`fo5dk6e^hQ>AsS#bkk0*~P z2ZQKD3?$HjQ#ynQDCWx|vrxA%@d7MEn7{|FFrqg`;SU{n0e^WhIo&8h2peEQ<{rfp zAOK+r9~i+4pVX)vWPwgf*Z~q)V1p?6!3c)Bfm=sZDX{>?3{o(|{}Qo4g$ocN3qY8G zMZuy04~Qz`4bWbo!%P^l=s7omMwYpRp(v$?IWZK;o@0bDTQJbpwzu^yr6~=~@v&yp zk;e3<&93R;4i~w{rJr(}i?0Dj7uBg=n5}DVF!@N(p7Zf8tEmf$2K}NI>3u>KJaMxL zHEf@Gs6pm*{DdTUfjN1InF&GwfKph&6H&NBJOSLg1JH22f2HypHUM!atBg76d|HnScqL5CG%=)lFbefYzODR%-CISR~~eLO{JI8)WUjs1TM6JyVwWP z*of#sp^kOLFrdQAJOT%d9~LA5!wi@k`~e4a(nrKzBfL}$=m3Asf)(IFBj`vY@W2D0 zA1_405(pwNNC3(~S)fb=Mf5=wT!6@RK~QAD2)KX~{~XCL@I)GUzz0B*mM{)Q%m5Xb zfCju30CYh`coh|Zp0uHmjW|RtK!GGGK^o`)3djHyuEakK0**-*m7HNKJV6V{KtnuA z7zDu%r~p_2qX|gC5U>pm7{riKATH6IU;MkQo{(Bh+*!VZYX2o1<1AOYxz4pnso zBh*125CIxeq!T`7f5BMGu$fOFb#2@ID z4(vb?EaO!E0$4zR4}d@hm;eeWWtcERAY23x>_8NJfChj7`c0(@*#Ha305K3;Pi_JP z{DBZe!3LNB2}H?Ew!&jT0u2m-3P4<=%mP=CQ4Rz}_56h~gyWtSnl06tFKHvyDNCT0 zAUkT^)>R8=s-U$rTBDUuqk#{$uwXs<-M8VBS%mx9J7tFv9 zWJU!f8 zQAIR?=aB-}fk6hmO05uC6kven4TG6jzzp2z1~0W>y_jlwgT+&(?KaXu@MW zuIXsvRy-1(|l{Y@sQmf##c@D?Gxf*M*Oq&f^TsAf$a=YQP4b zN?L1H8f?Vo+94!CYEuu|#-QGdINb{Y?dEm#<`6bVc_{3{Htah&s^49qq;6*$idUr$ zRDzUed2SFK;6cZB?5DZ`8`yyzut6G}Y$K$BtFG+I!fGSHDkr>bBZ$Bv&}uX!4*|@> zF3m$Uh}Jyt5(eT~u6AIs|7NIbQJ@A?4&o$@(l9{~T!CK^K@CX3TIiAbeJj>N4=(ux z2#%nz5Noyq3$bc#Vf+fSRs@-PW;>2XxwdWFjwYk2t7yWhZi!tC!eDEZ&!qjM`Q)pg z?rEUzR-h(VsLfq&)=P68>N)LZa|owza))?KWOUZkcunf0ir1!Ytb%kb$9imveC+3X z>Zg*d$)YUFvaHKWf)2#2Bw&IAoCD9|Z1UVJXGMc9{cN7;1D*+kG=yNV`h{jH9eyIg z1)K@9!DUJ?K~+-gI96bn8c*|nmItO7^$eQy1QYfak7^B*_4--a!cEw!qxK9ynYLs1 zmO&jKx;-I=)%?e79_^cGJATmUFcKobn<0APRs#NXKp(`Q{K zIsO^5eyw2;hOSKJ@$ib)$=UWw&!ADUUjXmdUPK9!ueeGJ+pZ{Wk%k(t?`XoUx;`3d z&STx$Dc;s;-rg}D-)X$^E&uAN|5g)iM8QFR(=`clyaepP8gAlVN8)xzbUE;PJg~t; z(B)EU=3X!d|97g#qR7X(!3S@$Cv&iXxdF+JFv_Mu77Su4$Lt`Yu#PBzH1sUaau#Rd zY|qMat?C61>n@)8ZV!L)5{GH{YU3?U;9pQLpmA^aS`YAMuQDsf)J0Ef*#$L&aqtGk z7?L%m9lS8tkqRvwUNv!2wET$re26JviYqCUxE*yL^=t49Nk#Z?> zf+?rL38OL!vvLFE>Mp%745PFy&#(>OFfSPcFYB2v=ZeuLbJpH8o#=|!0<)l59T(ry zPX{#@|7)=p(^=7iuN0$gY#p&So3T5pF}0-eigq(N$L%0;ES7D0%Qo?=4Ib__^-tjf;XhADBP*-|L$V}8(Bd^T1wZs7aIQvAwC8%PMQ5^K zYcxsWK`AFTCoBRggY-yaLIcohUZ^w-S2jz#a1G-w(8jb(d*BGB7&2Guw~j3?RbVqq z@f2&Z^=M`{PEWC{wor4iG*7YkY5)haV`n-w3hp*luklpZmikt8x~8jEtEjc42K*K` z7#KICy=%6(;A+}$R^MR1dK16Oi~RsBHvNwP3$Q@T^}*J)L!KVPPV%c!tfX2jcQO8!4C_y;_G9)%WR#2Ckq6x&Cm|HJMZTEb`(eFkM5kc{8--UaF>Q@CLQF zd-ru;$M=9xIR8Rk_acn+uWpts3;2LrHZ9+5tuDX~-x+7m^fCK|pDCRN z3Ug|qmTFmVYzwubJm!b5wrjEW^bET3^m#>Ok8K|@`Ks+`Ov|{c_)|wUi=(kr|Ch$4 z!#MhOvoJVQ`gFp62ErdahqXj?8$;T)%;P)5>l|+jy!LA~S=v1hu5lSTK*u$8hE zDwE5alT+|sV=5h#=dddXl^^>Bcey~N_kZl?evUaO7z2Rw($7Z2EvLCvq8xJc}#ZqV3iYQhdaBg2Wp>z##s= zAU@+uyyFu-#e+J=-+{)TacMC3I?rizkF`IRJPxjPKVuWid$(LKE+g+c!%DK>N$`_f z@+D&~>|1I;VXEw7?!@9tNP{~RKmp_fF!VwLBtQfBLILD# zw+}yAlwYAE7h`ZLkk3XTO*xD-#k)}Pn|D%1p&%O8u@3Smj z2y)jw#c)4@+>Z3baA9eNmh)dV7bim>f`-qO&w2#zwU27I@SF>!ve*L-?FV;JG z^xoNc=MN_`0R&Jmw&1WaW74DvFh;=FB1vChNV3d{(`C#&GF$fiSrVrn2^x?gFwd9( z!U6_J8!&*i0NDX(*AAe8Hf{~OZ}aZWTX*o=y@v@+`*)?Fl{vG^xT)3_WXyOv*%bg6DMxDx+FV^^11BvA5_kO289QW_9@6jXsHgc#U zPXaNpqJl2EsFMLRdaxt>G71R~kw`kJ36xR-gC!1M`hlkO(j$r}n@TJZr=XlFh(&@} zd=bV08+!egaq*8Vq$y8;d4TD` zvM(A54YMve;h~2fGQ*MwNyIc$v@SUd)5|U|gF!SOfLUY_IUP7-fdybwjkfT#8?LzG zbgS(++Xy3Uy4=FUEdUIJ;jki*Isv7L>5vQ5I1MnE|3N=HqFlrdP(h6nqzbe6!&6RB z+_V7Fqs;-L+SXFw%%vVw2qn zR*^uusHc}URB478NC8nqnOqu|r-J~qk4GSDyy(D<5@e9UXXS-(*%=|6(Ozlu#rH+N zz6$F|yp-%~uO^XdkEw$GSftBF=;VaXh!*G`kM-3?u2J>ssuaG>YFiKdDrtiUgCG>Av z8yocG2Ucilf)re}PUu!s6m}Yiuu|n zPfV~sos}IHB75&`+Q5WrL@-_i4QH@$c4Mru>ByfQ9P%3Fg)yr;wjkIGFPOq=z(4xf zuMduJtS_X|LGpplg-?!n8ps_rk1_~E>K42>z4qjR}dG)3nL5k#PbS> zBkGN0Bm3c3z(U@*F$Ud$XHI> z7Y3`B5wZ0Ofem^fLKH|u>KQRXkJI0~Hn>4)70wf2@Lo}Jg%ARHErSm#oI%<(IqMCJ zg#DWzfc#^;5Xui(Z1Yb-uqD7^$**sAv(|qoSVA-wuxy1}m*EWOHY}16kyb<>LB`0U zflLjN2TEKbomfCM4$F-D;+MTfr@DoO1bDpz8OUUZrrn{5O&puu$8y)Zh_Q}!!V8{A zJXto$xy^FXt0En-Sff0&3yWR^X0ra#%Y0;b}0#Y`qPQi^v>R<4MZ&RljPy_L_QWi%lA6yndFW|0=GsFkk1Hal8$4R$LV(W1GOlnvW2_u3sa+-`(A47Mgz-kiJ zt^9PGlk#`VriPG~q8mv`J*mRs0gs0*q}X7`q&qBu#xfxFVVyoXyjT)XbfxoPE*0k_ zmtM1`xhi8^1NzoSuGOXo|6~>hABnzRflVPzm=&Z53dSTl5L$p-D!t@)*EQ0wZ^~-p z8^ig(uJR9_5*jC0^(Q#VK@ykMG+ctj$WsMAS8E5c=}mo#)0_4bAx&w>Og-U>ClPX{ z`J0h&)pjn|*$|@^Q}4ybB*Vjo=3iP(((=rOOY1Shf+K{JVy9N=CyTz>>d21}T{T9W*O&)E@ z=2ftUagob~t8}r6RvO>ftzQe=G^0yC^L5r-Uv!8Q>&nzhVnmONl^E?nY9Z0pM?ZRv z?D2B>JYMxut`2!{|3nxF)6)9WpNzEe;lO5N8!yGETf;7zb^KtU(kgKK1aJin60AWw z%a$aBXNJ?L(BD#3#BCFFijzgv+V*+F?1CaX&eJnuw2V6}o&7apKoc^Mi2NgT>I$I#HLI3^Y*V)C&1(?xXLMo8T}tyB*uh4y z*0e~A3IJJxgd|`t)9B$u3r=o&9w1ZqJU8PR`ft}BG@((f&B|fUxyNj_EjPL6*~*Q8 zr3=IfH=^#+<;a7QUH1v;4bgf>wxp-d>b`}yI$5%iO=gpP1WIH7Dxw$Zwxpt7lnoEJ%bN5}}`}hdxkxzv~1`;3>W7Pj}_isqRX}Rvl!Z zp_30rSK1>6t$F1(`F{~ub_e&GR|+gJt-bg~?E2K8?KvMl8!~rI>$u~>b_f!FeGt{c z*ENuI4 zKmYq5&PDPt&~(X_5X)VgI5Yd%*Ip6;(Dni_0CVsE1Tgm!umB0L_8O1@3orq34+14H z0&(vPE)WC1p!R|%5Q2icFi2>at;i}uY@(>MOm2N}Ey3!}`eJIqHtiv#iTb*z`DhSV z9_{Y9PX|4L?-)V|z`$yLfVs|%#keWY0O@S}NX0rV=bA7;oDe|#;vx>{Q!wK)1`q~d zKom6a0z)AbzTgYLunRMg49k!U&2S5Ej|&3~7ASialVfzorSaAkFOWRh>*+>?{ZLlEN#~?4f`&U6FCv%RErgaP_~wZa-hu=SJ4y`FKPsm z{aVq)5V95VLqZJhNsQ=z6rw4hqA5VZ1C3%mK;bAXa)Ur=5n{kIdJznhF&K5h|0Jc6 z8W$n7EaDH`=hN^EBj}0{7w(uWsF=j*b2Y zDyi)$0g@o0GAgwaGm8)^+0TuNXF`spKRT&?bjFh?@8>!Rzfg$XB#SlGEl1YvHQ&vH z_GLCT>Etqu)Yi>%Y7;iKXTN-9rC!oEf221@E=OWhH(OIV>y0^^^Mtrg|24U86oOFP z6!IXs%JG;m&&Y56CX;f^%_$p?+E8(RqRce&>O9kP@`jE*+cOt4PwJe`mEe;;lkVyM z%CYj3J^RhC)YCuz6F@63h4jtehK@glXFr=RKSN3LIB)AD#s?Ze78J8O;V3dw(J~dU z{UB2^!OlY;WSx#{)MRACI8;2-536o&uLATynXa+ybD~1YL1&aks}5qOPBdgkOmc@} zm~1mXW@N%7^g@sHYSc)Nbn~uGVw4m~lT`FtNc27rhd!@%zJyF(4@+UsGGI?jXAc3W zv#TzY<)m^<`^G`f^fKf?h9(Do?s_7)HTE6@Q!Ls4lDQ3+5|AFxsfZ~!0mQ5W?A8#PfOa8ofg zQ9+dfLA6vll~X;V0Yg;*Ar)3(RRhyd4QbU@+W{5!u|ngAJkyUV$J6{ElU?E^M1A!s zb<1v42Q__;Jta!&dZ=|$Em|G)qr4eOQ^-~?y0AsZRXZ2ib z^$gk24a<-XbI)Dd&|K%WRxL1H;k90EH3898U-7kG`Bhfabq)uXV8aj$NAejH_8G?j z8&E+pU11d;b0Cd16^X|8%rrxfML$AlWAlyQN>ktP({%!i|72&BWB}C)Ju3FTl~pgb zRq0g=wUAx~whhUUT`zD8307z0&|rJEXAkygcUEYJRwRj54#lu&4fbG{b_{{mX%!Y~ zqgHC2Q5lg@8IAE6jZqj=ffYEVoaQF+B(_88CPn2abs`UBrA$B_%RWo?lZ=#=QWn0t z6U4YxWF{mTz@d48zc8r?wdpR&Wc~a1R%86IXE;*9(_%8Lc)MNfK+bmU1JP zawivaF?Sb&QEPXB9a70#6W%9mwnflebsjt(1B|gpu0N3yI91#_7{Kq zcYpa8MglEBn{}k#c4Q?6c4>5Wtnf^_l}qcETt77dA0TIO)`E2x4gt4!2X`8YcX+E7 zguORwz4v)ZvU{;tYf)HyvsZ;DH+)<8g_$>e%Xfvbw|rw*g=ZKThtYh|HyGP@eS7-5-~Us)brc^7V37jD^>ZF!eXQXY0$mxDQ&pBR{dnV6~gb3cI< zn%SA38JeS6nx~nXojItcnHFThYO=YRwV9i_S)0SznYEb}$a$R0xtz&aoMjfd7kB27UY?qKY^K1!4&-Y69QVG1v(QBIulL-p%)sV?fITjAy*+9 zqCWwm9f6`z!4Wdr5mG^;Qy~*Pnxi)weWN#8qf0uYLz<*fnxj#=qfpK5Iu&4g zrDuAhY5Jx&dZt%er&GG7d%6%(L8ynCsEgXDYx<~%8mN`Js2w4wfBLC~+Nq^Fs+*dq zb(*7}da9{9tGn8(ry8t-I;^{Ttjk)g&)TcgdaRE+sH?iFk9w`6TB|uaAOHY6gG +Rem +Rem MODIFIED (MM/DD/YY) +Rem cbarclay 01/24/02 - demo updated +Rem cbarclay 01/15/02 - plsql is of and treat +Rem hyeh 05/01/01 - fix query format +Rem hyeh 04/10/01 - Merged hyeh_inh_tyev_demos +Rem hyeh 04/09/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +COLUMN mysubtype FORMAT A70 +SET ECHO ON + +connect system/manager +drop user inhdemo1 cascade; +drop user inhdemo3 cascade; + +grant connect, resource to inhdemo1 identified by inhdemo1; +grant connect, resource to inhdemo3 identified by inhdemo3; + +connect inhdemo1/inhdemo1 + +Rem +Rem Inheriting Attributes +Rem + +create or replace type Person_t as object +( ssn number, + name varchar2(30), + address varchar2(100), + map member function mapfn return number, + static function check_type (in1 Person_t) return varchar2, + member function whatami return varchar2 +) not final; +/ +show error + +create or replace type Student_t under Person_t +( deptid number, + major varchar2(30) +) not final; +/ +show error + +create or replace type Employee_t under Person_t +( empid number, + mgr varchar2(30), + salary number(10,2), + overriding map member function mapfn return number, + member function raise_salary return Employee_t, + overriding member function whatami return varchar2 +) not final; +/ +show error + +create type PartTimeStudent_t under Student_t +( numhours number, + overriding map member function mapfn return number +); +/ +show error + +create or replace type body PartTimeStudent_t as +overriding map member function mapfn return number as + begin + return self.numhours; + end; +end; +/ +show errors + +create type dup_t as object +(dup student_t); +/ +show errors + +/* create and populate tables depend on types */ +create table person_obj of Person_t + not substitutable at all levels + (constraint pobj_pkey primary key(ssn)); +create table employee_obj of Employee_t + not substitutable at all levels + (constraint eobj_pkey primary key(ssn,empid), + mgr not null); +create table employee_obj2 of Employee_t + not substitutable at all levels; +create table student_obj of Student_t + not substitutable at all levels + (unique (name, deptid)); + +create table all_person (PersRefCol REF Person_t, tabname varchar2(20)); + +create table dup_students (ssn number, p student_t) + column p not substitutable at all levels; + +insert into person_obj values(12345, 'Joe','SF'); +insert into employee_obj values (2345, 'Max','LA',56, 'King',100.20); +insert into employee_obj2 values (2345, 'Max','LA',56, 'King',100.20); +insert into student_obj values (2345, 'Max','LA',300,'PLAY'); + +insert into all_person select REF(p), 'PERSON_OBJ' from person_obj p; +insert into all_person select REF(p), 'EMPLOYEE_OBJ' from employee_obj p; +insert into all_person select REF(p), 'EMPLOYEE_OBJ2' from employee_obj2 p; +insert into all_person select REF(p), 'EMPLOYEE_OBJ2-2' from employee_obj2 p; +insert into all_person select REF(p), 'STUDENT_OBJ' from student_obj p; + +insert into dup_students select ssn, value(p) from student_obj p; + +commit; + +select * from person_obj; +select * from employee_obj; +select * from employee_obj2; +select * from student_obj; +select * from dup_students; + +select deref(p.persrefcol), tabname from all_person p order by p.tabname; + +/* cannot insert subtype to non-substitutable column/table */ +insert into person_obj values + (Employee_t(12345, 'Joe','SF',null,null,null)); +insert into person_obj select treat(value(p) as person_t) from employee_obj p; + +update dup_students set p=PartTimeStudent_t(2345, 'Max','LA',300,'PLAY',0); + +/* create type body */ +create or replace type body Person_t as + map member function mapfn return number as + begin + return self.ssn; + end; + + static function check_type (in1 Person_t) return varchar2 as + n varchar2(40); + begin + n := + case + when in1 is of (ONLY Person_t) then 'PERSON_T' + when in1 is of (ONLY Employee_t) then 'EMPLOYEE_T' + when in1 is of (ONLY Student_t) then 'STUDENT_T' + when in1 is of (ONLY PartTimeStudent_t) then 'PARTTIMESTUDENT_T' + else 'UNKNOWN' end; + return n; + end; + + member function whatami return varchar2 as + begin + return 'PERSON_T'; + end; +end; +/ +show error + +create or replace type body Employee_t as + overriding map member function mapfn return number as + begin + return self.empid; + end; + + member function raise_salary return Employee_t as + e_v1 Employee_t; + begin + update employee_obj e set salary = self.salary + 999.99 + where self.ssn = ssn and self.salary is null + returning value(e) into e_v1; + return e_v1; + end; + + overriding member function whatami return varchar2 as + begin + return 'EMPLOYEE_T'; + end; +end; +/ +show error + +Rem +Rem Assignments +Rem + +Rem Object (REF) assignment + +create table t +( perscol Person_t, + empcol Employee_t, + stucol Student_t) +column perscol not substitutable at all levels, +column empcol not substitutable at all levels, +column stucol not substitutable at all levels +; + +insert into t values +( Person_t(12345, 'Joe','SF'), + Employee_t(9876, 'Bill','SJ',1111,NULL,100), + Student_t(2345, 'Max','LA',300,'PLAY') +); + +commit; + +Rem Widening + +update t set perscol = empcol; +select * from t; + +set serveroutput on +declare + var1 Person_t; + var2 Employee_t; + var3 Employee_t; +begin + select empcol into var2 from t t where t.perscol.ssn=12345; + var1 := var2; + dbms_output.put_line('ssn:'||to_char(var1.ssn)); + var3 := treat(var1 as Employee_t); + dbms_output.put_line('empid:'||to_char(var3.empid)); + insert into t values (Person_t(999,'Boss','KS'), + treat(var1 as Employee_t),null); + select empcol into var3 from t t where t.perscol.ssn=999; + dbms_output.put_line('empid:'||to_char(var3.empid)); +end; +/ + +rollback; + +Rem Narrowing + +update t set empcol = TREAT(perscol AS Employee_t); +select * from t; + +rollback; + +Rem Compile Error + +update t set empcol = perscol; +update t set empcol = stucol; + +declare + var1 Student_t; + var2 Employee_t; +begin + var1 := var2; +end; +/ + +rollback; + +Rem Collection Assignment + +create type PersonSet as table of Person_t; +/ +create type StudentSet as table of Student_t; +/ + +declare + var1 PersonSet; var2 StudentSet; + elem1 Person_t; elem2 Student_t; +begin + var1 := var2; /* ILLEGAL - collections not of same type */ +end; +/ + +declare + var1 PersonSet; var2 StudentSet; + elem1 Person_t; elem2 Student_t; +begin + var1 := PersonSet (elem1, elem2); /* LEGAL : Element is of subtype */ +end; +/ + +Rem +Rem Comparison +Rem + +Rem Object Comparison + +insert into t values +(Person_t(99, 'Joey', 'LA'), + Employee_t(99, 'Joey', 'LA', 1,'Max',90.99), + Student_t(99, 'Joey', 'LA', 2022, 'Minor')); + +select * from t where perscol=empcol or perscol=stucol; +select * from t where perscol=treat(empcol as person_t); +select * from t where treat(stucol as person_t)=treat(empcol as person_t); +select * from t where stucol=empcol; + +Rem REF Comparison + +select count(distinct(persrefcol)) from all_person; +select count(distinct(deref(persrefcol))) from all_person; + +/* valid compare */ +select deref(p.persrefcol), p.tabname + from all_person p where + exists (select p2.persrefcol from all_person p2 where + p.persrefcol = p2.persrefcol and p.tabname != p2.tabname) + order by p.tabname; + +select p.tabname + from all_person p where + (select ref(s) from person_obj s) = (select ref(k) from employee_obj k); + +select p.tabname + from all_person p where + (select ref(s) from student_obj s) = persrefcol; + +select p.tabname + from all_person p where + (select treat(ref(s) as ref person_t) from student_obj s) = + (select ref(k) from employee_obj k); + +/* invalid compare */ +select p.tabname + from all_person p where + (select ref(s) from student_obj s) = (select ref(k) from employee_obj k); + +Rem +Rem SQL Operators +Rem + +create view Person_v of Person_t with object identifier(ssn) as + select * from person_obj p; +create view Student_v of Student_t under Person_v as + select * from student_obj p; + +Rem VALUE + +select VALUE(p) from Person_v p order by p.ssn; +select VALUE(p) from ONLY(Person_v) p order by p.ssn; + +Rem REF + +select REF(p) from Person_v p; + +select REF(p) from Person_v p +minus +select REF(p) from person_obj p +minus +select REF(p) from student_obj p; + +Rem DEREF + +select DEREF(REF(p)) from person_v p order by p.ssn desc; + +/* Do some PL/SQL with VALUE, REF, DEREF of person_v */ + +Rem TREAT + +select TREAT(VALUE(p) as Student_t) from Person_v p order by p.ssn desc; + +select DEREF(a) from + (select TREAT(REF(p) as REF Student_t) a from Person_v p) k + order by k.a.ssn; + +insert into employee_obj values + (Employee_t(2929, 'Billy', 'TX', 9, 'Max', NULL)); + +create global temporary table tmptb1 (a Employee_t) + column a not substitutable at all levels; + +set serveroutput on +declare + var1 Person_t := Employee_t(2929, 'Billy', 'TX', 9, 'Max', NULL); + var2 Person_t; + var3 Employee_t; + v_type varchar2(20); +begin + insert into tmptb1 values(TREAT(var1 as Employee_t)) + returning a into var2; + if var2 is null then + dbms_output.put_line('var2 is null - WRONG'); + else + var3 := TREAT(var2 as Employee_t); + v_type := Person_t.check_type(var3); + if v_type = 'EMPLOYEE_T' then + dbms_output.put_line('row updated, ssn:'||var3.ssn||', salary:'|| + to_char(var3.salary)); + else + dbms_output.put_line('var3 is of type is '||v_type||' - WRONG'); + end if; + end if; +end; +/ + +select * from employee_obj order by ssn; + +rollback; + +Rem IS OF + +select REF(p) from person_v p + where VALUE(p) IS OF (Employee_t, Student_t); + +select VALUE(p) from person_v p + where VALUE(p) IS OF (ONLY Person_t); + +select TREAT(VALUE(p) AS Student_t) + from Person_v p + where VALUE(p) IS OF (ONLY Student_t); + +select * from all_person + where DEREF(PersRefCol) IS OF (Student_t); + +Rem +Rem View Hierarchy +Rem +create table persons ( + ssn number constraint pers_pkey primary key, + name varchar2(30), + address varchar2(100)); + +create table employees ( + ssn number constraint emp_pkey primary key, + name varchar2(30), + address varchar2(100), + empid number, + mgr varchar2(30), + salary number(7,2)); + +create table students ( + ssn number constraint stu_pkey primary key, + name varchar2(30), + address varchar2(100), + deptid number, + major varchar2(30)); + +insert into employees select * from employee_obj; +insert into students select * from student_obj; +insert into persons select * from person_obj; +commit; + +create or replace view person_v of person_t with object id(ssn) as + select ssn, name, address from person_obj; + +create or replace view student_v of student_t under person_v as + select Student_t(ssn, name, address, deptid, major) from students; + +select * from person_v p order by p.ssn; +select value(p) from person_v p order by p.ssn; +select * from ONLY (person_v) order by ssn; +select * from student_v order by ssn; + +Rem Polymorphic Views + +create view Persons_view of Person_t with object id(ssn) as + select Person_t(ssn, name, address) from persons + union all + select TREAT(Employee_t(ssn, name, address, empid, mgr, salary) as Person_t) + from employees; + +select value(p) from Persons_view p order by p.ssn; +select (TREAT(value(p) as Employee_t)).empid, ssn from Persons_view p + where value(p) IS OF (Employee_t) + order by ssn; + +Rem +Rem Substitutable columns/table +Rem + +drop table person_obj; +drop table employee_obj; +drop table employee_obj2; +drop table student_obj; +drop table all_person; +drop table dup_students; + +/* create and populate tables depend on types */ +create table person_obj of Person_t + (constraint pobj_pkey primary key(ssn)); +create table employee_obj of Employee_t + (constraint eobj_pkey primary key(ssn,empid), + mgr not null); +create table student_obj of Student_t + (unique (name, deptid)); + +create table all_person (PersRefCol REF Person_t, tabname varchar2(20)); + +create table dup_students (ssn number, p student_t); + +insert into person_obj values(12345, 'Joe','SF'); +insert into employee_obj values (2345, 'Max','LA',56, 'King',100.20); +insert into student_obj values (2345, 'Max','LA',300,'PLAY'); +insert into student_obj values + (PartTimeStudent_t(90, 'Kay', 'TX', 300, 'PLAY',3)); +insert into person_obj values + (Employee_t(9999, 'Joe','SF',null,null,null)); +insert into person_obj select value(p) from student_obj p; + +insert into all_person select REF(p), 'PERSON_OBJ' from person_obj p; +insert into all_person select REF(p), 'EMPLOYEE_OBJ' from employee_obj p; +insert into all_person select REF(p), 'STUDENT_OBJ' from student_obj p; + +insert into dup_students select ssn, value(p) from student_obj p; +update dup_students set p=PartTimeStudent_t(2345, 'Max','LA',300,'PLAY',0) + where p IS OF (ONLY student_t); + +commit; + +select value(p) from person_obj p order by p.ssn; +select value(p) from employee_obj p order by p.ssn; +select value(p) from student_obj p order by p.ssn; +select d.ssn from dup_students d where p is of (only student_t); +select d.ssn, d.p.ssn, Person_t.check_type(p) + from dup_students d order by d.ssn; + +select deref(p.persrefcol), tabname from all_person p + order by p.tabname, p.persrefcol.ssn; + +delete from person_obj p where value(p) IS OF (Employee_t, PartTimeStudent_t); +select value(p) from person_obj p order by p.ssn; +select deref(p.persrefcol), tabname from all_person p + where persrefcol is not dangling + order by p.tabname, p.persrefcol.ssn; + +rollback; + +select value(p) from person_obj p order by p.ssn; + +select deref(p.persrefcol), tabname from all_person p + order by p.tabname, p.persrefcol.ssn; + +Rem +Rem Overriding Methods +Rem + +create or replace type MyBaseType as object +( a1 number, + final member procedure foo (in1 varchar2), + static function foo1 (in1 number) return number, + static function foo3 (in1 number) return number, + member function foo2 (in1 varchar2) return date +) not instantiable not final; +/ +show error + +Rem can only redefines (override) NOT final method +create or replace type MySubType under MyBaseType +( a2 number, + a3 date, + overriding member procedure foo (in1 varchar2) +) not final; +/ +show error + +/* overloading final method ok */ +create or replace type MySubType under MyBaseType +( a2 number, + a3 date, + member procedure foo (in2 IN OUT varchar2) +) not final; +/ +show error + +create or replace type MySubType under MyBaseType +( a2 number, + a3 date, + static function foo1 (in2 char) return varchar2, + member function foo2 (in1 varchar2, in2 number) return varchar2, + overriding member function foo2 (in1 varchar2) return date +) not final; +/ +show error + +/* can't have not instantiable static method */ +create or replace type MySubType2 under MySubType +(not instantiable static function foo3 (in1 varchar2) return number) +not instantiable not final; +/ +show errors + +create or replace type MySubType2 under MySubType +(not instantiable member function foo3 (in1 varchar2) return number, + not instantiable member function foo5 (in1 varchar2) return number +) +not instantiable not final; +/ +show errors + +Rem +Rem Dynamic Method Dispatch +Rem + +create or replace type body MyBaseType as + final member procedure foo (in1 varchar2) as + begin + dbms_output.put_line('MyBaseType.foo:'||in1); + end; + + static function foo1 (in1 number) return number as + begin + return in1; + end; + + static function foo3 (in1 number) return number as + begin + return in1+3; + end; + + member function foo2 (in1 varchar2) return date as + begin + return to_date(in1,'MM/DD/YYYY'); + end; +end; +/ +show error + +create or replace type body MySubType as + static function foo1 (in2 char) return varchar2 as + begin + return ('MySubType.foo1:'||in2); + end; + + member function foo2 (in1 varchar2, in2 number) return varchar2 as + begin + return ('MySubType.foo2:'||in1||' '||in2); + end; + + overriding member function foo2 (in1 varchar2) return date as + begin + return to_date(in1,'DD/MM/YYYY'); + end; +end; +/ +show error + +/* cannot instantiate type */ +select MyBaseType(1) from dual; + +select treat(MySubType(1,2,to_date('10/20/2000','MM/DD/YYYY')) as MyBaseType) + mysubtype + from dual; +select treat(MySubType2(1,2,to_date('10/20/2000','MM/DD/YYYY')) as MySubType) + from dual; + +/* ok */ +select MySubType(1,2,to_date('10/20/2000','MM/DD/YYYY')) mysubtype from dual; +select MySubType2.foo1(3) from dual; + +set serveroutput on + +declare + v1 MyBaseType; + v2 MySubType; + v3 date; +begin + v3 := to_date('09/30/2000','MM/DD/YYYY'); + v1 := MySubType(1,2,v3); + v2 := MySubType(1,2,v3); + dbms_output.put_line('MySubType.foo1(1):'||MySubType.foo1(1)); + dbms_output.put_line('MySubType.foo1(''1''):'||MySubType.foo1('1')); + dbms_output.put_line('MySubType.foo3(2):'||MySubType.foo3(2)); + dbms_output.put_line('MyBaseType.foo3(3):'||MyBaseType.foo3(3)); + v2.foo('a'); + v1.foo('a'); +end; +/ + +declare + v1 MyBaseType; + v2 MySubType; + v3 date; +begin + v3 := to_date('09/30/2000','MM/DD/YYYY'); + v1 := MySubType(1,2,v3); + dbms_output.put_line('v1.foo2(''11/12/1999''):'||v1.foo2('11/12/1999')); +end; +/ + +Rem +Rem Rights Model +Rem + +create or replace type deftype1 as object +( a1 number, + a2 varchar2(10) +) not final; +/ +show error + +create or replace type subtype1 under deftype1 (a3 date); +/ +show error + +grant execute on deftype1 to inhdemo3; +grant under on deftype1 to inhdemo3; + +connect inhdemo3/inhdemo3 +Rem can't create subtype in different schema +create or replace type inhdemo3.subtype2 under inhdemo1.deftype1 +(a3 number); +/ +show error + +connect inhdemo1/inhdemo1 +Rem create root type with INVOKER RIGHT +create or replace type invtype1 authid current_user as object +( a1 number, + a2 varchar2(10) +) not final; +/ +show error + +grant execute on invtype1 to inhdemo3; +grant under on invtype1 to inhdemo3; + +connect inhdemo3/inhdemo3 +Rem ok to create subtype in different schema +create or replace type inhdemo3.subtype2 under inhdemo1.invtype1 +(a3 varchar2(10)); +/ +show error + +Rem cleanup + +connect system/manager +drop user inhdemo1 cascade; +drop user inhdemo3 cascade; + diff --git a/maporder.sql b/maporder.sql new file mode 100644 index 0000000..ad778b8 --- /dev/null +++ b/maporder.sql @@ -0,0 +1,308 @@ +rem +rem $Header: maporder.sql 12-aug-2004.06:03:09 rsriragh Exp $ +rem +rem maporder.sql +rem +rem Copyright (c) 1996, 2004, Oracle. All rights reserved. +rem +rem NAME +rem maporder.sql - Oracle 8 demo of map and order functions +rem +rem DESCRIPTION +rem This demo features Oracle8's object extensions, specifically map and +rem order functions of abstract data types +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem rsriragh 08/12/04 - fix order by diffs +rem ytsai 05/12/04 - order by +rem hyeh 08/10/99 - use sqlplus syntax +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem yaggarwa 08/06/98 - Add New syntax changes +rem cchau 08/18/97 - enable dictionary protection +rem mchien 05/29/97 - fix type syntax +rem mchien 07/17/96 - +rem mchien 07/16/96 - Created +rem + +REMARK >>>> Set System Variables For Current SQLPlus Session <<<< +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET PAGESIZE 24 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET DEFINE '^' + +set echo on +connect sys/knl_test7 as sysdba; +grant connect, resource to mmo2 identified by mmo2; + +connect mmo2/mmo2 + +REM create type with MAP function with parameters should error! +create type rational AS OBJECT ( + numerator INTEGER, + denominator INTEGER, + MAP MEMBER FUNCTION rat_to_real (x number) RETURN REAL, + PRAGMA RESTRICT_REFERENCES + (rat_to_real, RNDS, WNDS, RNPS, WNPS) +); +/ +show errors + +create or replace type rational AS OBJECT ( + numerator INTEGER, + denominator INTEGER, + MAP MEMBER FUNCTION rat_to_real RETURN REAL, + PRAGMA RESTRICT_REFERENCES + (rat_to_real, RNDS, WNDS, RNPS, WNPS) +); +/ +show errors + +REM create body with missing MAP specification in the body should error +create type body rational AS + MEMBER FUNCTION rat_to_real RETURN REAL IS + BEGIN + IF denominator = 0 THEN + RETURN 0; + ELSE + RETURN numerator/denominator; + END IF; + --Unqualified attributes refer to the "self" object. + END; +END; +/ +show errors + +REM create body with ORDER function instead of MAP as specified in type spec +REM should error +create or replace type body rational AS + ORDER MEMBER FUNCTION rat_to_real RETURN REAL IS + BEGIN + IF denominator = 0 THEN + RETURN 0; + ELSE + RETURN numerator/denominator; + END IF; + --Unqualified attributes refer to the "self" object. + END; +END; +/ +show errors +create or replace type body rational AS + MAP MEMBER FUNCTION rat_to_real RETURN REAL IS + BEGIN + IF denominator = 0 THEN + RETURN 0; + ELSE + RETURN numerator/denominator; + END IF; + --Unqualified attributes refer to the "self" object. + END; +END; +/ +show errors + + +create table tb1( + c1 varchar2(10), + c2 rational, + c3 rational, + c4 real); + +insert into tb1 values('row1', rational(9,10), rational(9,10), .9); +insert into tb1 values('row2', rational(7,8), rational(7,8), .8); +insert into tb1 values('row3', rational(5,6), rational(5,6), .7); +insert into tb1 values('row4', rational(3,4), rational(3,4), .6); +insert into tb1 values('row5', rational(1,2), rational(1,2), .5); +insert into tb1 values('row6', rational(0,1), rational(0,1), .4); +insert into tb1 values('bomb1', rational(1,0), rational(1,0), .3); +insert into tb1 values('bomb2', rational(1,null), rational(1,null), null); +insert into tb1 values('bomb3', rational(null,1), rational(null,1), null); +insert into tb1 + values('bomb4', rational(null,null), rational(null,null), null); +insert into tb1 values('bomb5', null, null, null); +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb1 order by c2, c3, c1; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb1 order by c2, c3 desc, c1; +select c1, sys_op_dump(c3) from tb1 order by c3 desc, c1; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb1 order by c3, c2, c1; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb1 order by c3, c2 desc, c1; +select c1, sys_op_dump(c2) from tb1 order by c2 desc, c1; + +update tb1 p set c4 = p.c2.rat_to_real(); +select sys_op_dump(c2), c4 from tb1 order by 1, c4; +update tb1 p set c4 = p.c3.rat_to_real(); +select sys_op_dump(c3), c4 from tb1 order by c4, c1; + +select c1, sys_op_dump(c2-c3) from tb1 order by c2, c3, c1; +select c1 from tb1 where c2-c3 = 0 order by c1; + +select sys_op_dump(c2) from tb1 where c2 > c3 order by c2, c1; +select sys_op_dump(c2) from tb1 where c2 > rational(20,1) order by c1; +select sys_op_dump(c2) from tb1 where c2 = rational(9,10) order by c1; + +select sys_op_dump(c3) from tb1 where c3 > rational(1,20) order by c3, c1; +select sys_op_dump(c3) from tb1 where c3 = rational(9,10) order by c1; +select sys_op_dump(c3) from tb1 where c3 in (rational(9,10), rational(1,2)) + order by c3, c1; + +REM Now test order function for rational numbers +REM error case where order function does not have arguments! +create type rat AS OBJECT ( + numerator INTEGER, + denominator INTEGER, + ORDER MEMBER FUNCTION order_rat RETURN INTEGER, + PRAGMA RESTRICT_REFERENCES + (order_rat, RNDS, WNDS, RNPS, WNPS) +); +/ + +show errors + +create or replace type rat AS OBJECT ( + numerator INTEGER, + denominator INTEGER, + ORDER MEMBER FUNCTION order_rat (rat1 rat) RETURN INTEGER, + PRAGMA RESTRICT_REFERENCES + (order_rat, RNDS, WNDS, RNPS, WNPS) +); +/ +show errors + +create type body rat AS + ORDER MEMBER FUNCTION order_rat(rat1 rat) RETURN INTEGER IS + den1 INTEGER; + den2 INTEGER; + num1 INTEGER; + num2 INTEGER; + BEGIN + den1 := nvl(self.denominator, 0); + den2 := nvl(rat1.denominator, 0); + num1 := nvl(self.numerator, 0); + num2 := nvl(rat1.numerator, 0); + if den1 = den2 then + return num1 - num2; + elsif (den1=0) then + return 1; + elsif (den2=0) then + return -1; + else + return (num1*den2) - (den1*num2); + END IF; +END; +END; +/ +show errors + + +create table tb2( + c1 varchar2(10), + c2 rat, + c3 rat, + c4 real); + +insert into tb2 values('row1', rat(9,10), rat(9,10), .9); +insert into tb2 values('row2', rat(7,8), rat(7,8), .8); +insert into tb2 values('row3', rat(5,6), rat(5,6), .7); +insert into tb2 values('row4', rat(3,4), rat(3,4), .6); +insert into tb2 values('row5', rat(1,2), rat(1,2), .5); +insert into tb2 values('row6', rat(0,1), rat(0,1), .4); +insert into tb2 values('bomb1', rat(1,0), rat(1,0), .3); +insert into tb2 values('bomb2', rat(1,null), rat(1,null), null); +insert into tb2 values('bomb3', rat(null,1), rat(null,1), null); +insert into tb2 values('bomb4', rat(null,null), rat(null,null), null); +insert into tb2 values('bomb5', null, null, null); +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb2 order by c2, c3, c1; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb2 order by c2, c3 desc, c1; +select c1, sys_op_dump(c3) from tb1 order by c3 desc, c1; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb2 order by c3, c2, c1; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb2 order by c3, c2 desc, c1; +select c1, sys_op_dump(c2) from tb1 order by c2 desc, c1; +update tb2 p set c4 = p.c2.order_rat(rat(3,10)); +select sys_op_dump(c2), c4 from tb2 order by c4, c1; +update tb2 p set c4 = p.c2.order_rat(c3); +select sys_op_dump(c2), sys_op_dump(c3), c4 from tb2 order by c4, c1; +select sys_op_dump(c2) from tb1 minus select sys_op_dump(c2) from tb2; +select sys_op_dump(c2) from tb1 minus select sys_op_dump(c3) from tb2; +select sys_op_dump(c3) from tb1 minus select sys_op_dump(c3) from tb2; + +select sys_op_dump(c2) from tb1 intersect select sys_op_dump(c2) from tb2; +select sys_op_dump(c2) from tb1 intersect select sys_op_dump(c3) from tb2; +select sys_op_dump(c3) from tb1 intersect select sys_op_dump(c3) from tb2; + +select sys_op_dump(c3) from tb2 where c2 in (select c2 from tb2) order by c3; +select sys_op_dump(c3) from tb2 + where c3 between rat(1,100) and rat(99,100) order by c3; +select sys_op_dump(c2) from tb2 + where c2 = ANY (SELECT c2 from tb2 where c3 = rat(9,10)); +select sys_op_dump(c3) from tb2 where c2 >= ALL (rat(1,10), rat(9,10)); +select c1 from tb2 where c2-c3 = 0 order by c1; + +REM #### test a recursive method +REM method is the factorial function + +REM note: pragma for map method is not required! + +create or replace type tfact AS OBJECT (c1 int, +map member function mfact return int, +member function fact(a int) return int , +PRAGMA RESTRICT_REFERENCES(fact,WNDS,RNDS,WNPS,RNPS) ); +/ +show errors + +create or replace type body tfact AS + member function fact(a int) return int is + begin + if a is null then return 0; + elsif a = 0 then return 1; + else return a*fact(a-1); + end if; + end; + map member function mfact return int is + begin + return c1; + end; +END; +/ +show errors + +CREATE TABLE tbfact (a tfact, b int, constraint aci check (a.c1 >= 0), + constraint bci check (b >= 0)); +INSERT INTO tbfact values(tfact(3), 4); +INSERT INTO tbfact values(tfact(-1), 1); +INSERT INTO tbfact values(tfact(1), -1); +INSERT INTO tbfact values(tfact(0), 1); +INSERT INTO tbfact values(tfact(null), 0); +INSERT INTO tbfact values (null,0); +INSERT INTO tbfact values(tfact(2), 3); +SELECT p.a.c1 a, p.a.fact(p.a.c1) afact, b, p.a.fact(b) bfact FROM tbfact p +WHERE a is not null ORDER by a; +SELECT p.a.c1 a, p.a.fact(p.a.c1) afact, b, p.a.fact(b) bfact FROM tbfact p +WHERE a is not null ORDER by a desc; + +drop type body rat; + +create or replace type body rat as + ORDER MEMBER FUNCTION order_rat(rat1 rat) RETURN INTEGER IS + BEGIN + if self.denominator = rat1.denominator then + return self.numerator - rat1.numerator; + else + return (self.numerator * rat1.denominator) - + (self.denominator * rat1.numerator); + END IF; + END; +END; +/ + +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb2 order by c2, c3; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb2 order by c2, c3 desc; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb2 order by c3, c2; + +connect sys/knl_test7 as sysdba +drop user mmo2 cascade; + + diff --git a/mddemo.sql b/mddemo.sql new file mode 100644 index 0000000..94a4f57 --- /dev/null +++ b/mddemo.sql @@ -0,0 +1,271 @@ +rem +rem $Header: mddemo.sql 01-nov-00.16:13:33 gclaborn Exp $ +rem +rem Copyright (c) 1996, 1999, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem mddemo.sql - Oracle 9i demo of the Metadata API +rem +rem DESCRIPTON +rem This demo shows how to programmatically extract database object +rem definitions using the DBMS_METADATA package. +rem +rem MODIFIED (MM/DD/YY) +rem gclaborn 11/01/00 - Created + +-- This script demonstrates how to use the Metadata API. It first +-- establishes a schema (MDDEMO) and some payroll users, then creates three +-- payroll-like tables within it along with associated indexes, triggers +-- and grants. + +-- It then creates a package PAYROLL_DEMO that shows common usage of the +-- Metadata API. The procedure GET_PAYROLL_TABLES retrieves the DDL for the +-- two tables in this schema that start with 'PAYROLL' then for each one, +-- retrieves the DDL for its associate dependent objects; indexes, grants +-- and triggers. All the DDL is written to a table named "MDDEMO"."DDL". + +-- First, Install the demo. cd to rdbms/demo: +-- > sqlplus system/manager +-- SQL> @mddemo + +-- Then, run it. +-- > sqlplus mddemo/mddemo +-- SQL> set long 40000 +-- SQL> set pages 0 +-- SQL> call payroll_demo.get_payroll_tables(); +-- SQL> select ddl from DDL order by seqno; + +Rem Set up schema for demo pkg. PAYROLL_DEMO. + +connect system/manager +drop user mddemo cascade; +drop user mddemo_clerk cascade; +drop user mddemo_mgr cascade; + +create user mddemo identified by mddemo; +GRANT resource, connect, create session + , create table + , create procedure + , create sequence + , create trigger + , create view + , create synonym + , alter session +TO mddemo; + +create user mddemo_clerk identified by clerk; +create user mddemo_mgr identified by mgr; + +connect mddemo/mddemo + +Rem Create some payroll-like tables... + +create table payroll_emps +( lastname varchar2(60) not null, + firstname varchar2(20) not null, + mi varchar2(2), + suffix varchar2(10), + DOB date not null, + badge_no number(6) primary key, + exempt varchar(1) not null, + salary number (9,2), + hourly_rate number (7,2) +) +/ +create table payroll_timecards +( badge_no number(6) references payroll_emps (badge_no), + week number(2), + job_id number(5), + hours_worked number(4,2) +) +/ +-- This is a dummy table used only to show that tables NOT starting with +-- 'PAYROLL' are NOT retrieved by payroll_demo.get_payroll_tables + +create table audit_trail +( action_time DATE, + lastname VARCHAR2(60), + action LONG +) +/ + +Rem Then, create some grants... + +grant update (salary,hourly_rate) on payroll_emps to mddemo_clerk; +grant ALL on payroll_emps to mddemo_mgr with grant option; + +grant insert,update on payroll_timecards to mddemo_clerk; +grant ALL on payroll_timecards to mddemo_mgr with grant option; + +Rem Then, create some indexes... + +create index i_payroll_emps_name on payroll_emps(lastname); +create index i_payroll_emps_dob on payroll_emps(DOB); + +create index i_payroll_timecards_badge on payroll_timecards(badge_no); + +Rem Then, create some triggers (and required procedure)... + +create or replace procedure check_sal( salary in number) as +begin + return; -- Fairly loose security here... +end; +/ + +create or replace trigger salary_trigger before insert or update of salary on payroll_emps +for each row when (new.salary > 150000) +call check_sal(:new.salary) +/ + +create or replace trigger hourly_trigger before update of hourly_rate on payroll_emps +for each row +begin :new.hourly_rate:=:old.hourly_rate;end; +/ + +-- +-- Set up a table to hold the generated DDL +-- +CREATE TABLE ddl (ddl CLOB, seqno NUMBER); + +Rem Finally, create the PAYROLL_DEMO package itself. + +CREATE OR REPLACE PACKAGE payroll_demo AS + + PROCEDURE get_payroll_tables; +END; +/ +CREATE OR REPLACE PACKAGE BODY payroll_demo AS + +-- GET_PAYROLL_TABLES: Fetch DDL for payroll tables and their dependent objects + +PROCEDURE get_payroll_tables IS + +tableOpenHandle NUMBER; +depObjOpenHandle NUMBER; +tableTransHandle NUMBER; +indexTransHandle NUMBER; +schemaName VARCHAR2(30); +tableName VARCHAR2(30); +tableDDLs sys.ku$_ddls; +tableDDL sys.ku$_ddl; +parsedItems sys.ku$_parsed_items; +depObjDDL CLOB; +seqNo NUMBER := 1; + +TYPE obj_array_t IS VARRAY(3) OF VARCHAR2(30); + +-- Load this array with the dependent object classes to be retrieved... +obj_array obj_array_t := obj_array_t('OBJECT_GRANT', 'INDEX', 'TRIGGER'); + +BEGIN + +-- Open a handle for tables in the current schema. + tableOpenHandle := dbms_metadata.open('TABLE'); + +-- Tell mdAPI to retrieve one table at a time. This call is not actually +-- necessary since 1 is the default... just showing the call. + dbms_metadata.set_count(tableOpenHandle, 1); + +-- Retrieve tables whose name starts with 'PAYROLL'. When the filter is +-- 'NAME_EXPR', the filter value string must include the SQL operator. This +-- gives the caller flexibility to use LIKE, IN, NOT IN, subqueries, etc. + dbms_metadata.set_filter(tableOpenHandle, 'NAME_EXPR', 'LIKE ''PAYROLL%'''); + +-- There are no index-organized tables in the MDDEMO schema, so tell the API. +-- This eliminates one of the views it'll need to look in. + dbms_metadata.set_filter(tableOpenHandle, 'IOT', FALSE); + +-- Tell the mdAPI to parse out each table's schema and name separately so we +-- can use them to set up the calls to retrieve its dependent objects. + dbms_metadata.set_parse_item(tableOpenHandle, 'SCHEMA'); + dbms_metadata.set_parse_item(tableOpenHandle, 'NAME'); + +-- Add the DDL transform so we get SQL creation DDL + tableTransHandle := dbms_metadata.add_transform(tableOpenHandle, 'DDL'); + +-- Tell the XSL stylesheet we don't want physical storage information (storage, +-- tablespace, etc), and that we want a SQL terminator on each DDL. Notice that +-- these calls use the transform handle, not the open handle. + dbms_metadata.set_transform_param(tableTransHandle, + 'SEGMENT_ATTRIBUTES', FALSE); + dbms_metadata.set_transform_param(tableTransHandle, + 'SQLTERMINATOR', TRUE); + +-- Ready to start fetching tables. We use the FETCH_DDL interface (rather than +-- FETCH_XML or FETCH_CLOB). This interface returns a SYS.KU$_DDLS; a table of +-- SYS.KU$_DDL objects. This is a table because some object types return +-- multiple DDL statements (like types / pkgs which have create header and +-- body statements). Each KU$_DDL has a CLOB containing the 'CREATE foo' +-- statement plus a nested table of the parse items specified. In our case, +-- we asked for two parse items; Schema and Name. (NOTE: See admin/dbmsmeta.sql +-- for a more detailed description of these types) + + LOOP + tableDDLs := dbms_metadata.fetch_ddl(tableOpenHandle); + EXIT WHEN tableDDLs IS NULL; -- Get out when no more payroll tables + +-- In our case, we know there is only one row in tableDDLs (a KU$_DDLS tbl obj) +-- for the current table. Sometimes tables have multiple DDL statements; +-- eg, if constraints are applied as ALTER TABLE statements, but we didn't ask +-- for that option. So, rather than writing code to loop through tableDDLs, +-- we'll just work with the 1st row. +-- +-- First, write the CREATE TABLE text to our output table then retrieve the +-- parsed schema and table names. + tableDDL := tableDDLs(1); + INSERT INTO ddl VALUES(tableDDL.ddltext, seqNo); + seqNo := seqNo + 1; + parsedItems := tableDDL.parsedItems; + +-- Must check the name of the returned parse items as ordering isn't guaranteed + FOR i IN 1..2 LOOP + IF parsedItems(i).item = 'SCHEMA' + THEN + schemaName := parsedItems(i).value; + ELSE + tableName := parsedItems(i).value; + END IF; + END LOOP; + +-- Now, we want to retrieve all the dependent objects defined on the current +-- table: indexes, triggers and grants. Since all 'dependent' object types +-- have BASE_OBJECT_NAME and BASE_OBJECT_SCHEMA in common as filter criteria, +-- we'll set up a loop to get all objects of the 3 types, just changing the +-- OPEN context in each pass through the loop. Transform parameters are +-- different for each object type, so we'll only use one that's common to all; +-- SQLTERMINATOR. + + FOR i IN 1..3 LOOP + depObjOpenHandle := dbms_metadata.open(obj_array(i)); + dbms_metadata.set_filter(depObjOpenHandle,'BASE_OBJECT_SCHEMA', + schemaName); + dbms_metadata.set_filter(depObjOpenHandle,'BASE_OBJECT_NAME',tableName); + +-- Add the DDL transform and say we want a SQL terminator + indexTransHandle := dbms_metadata.add_transform(depObjOpenHandle, 'DDL'); + dbms_metadata.set_transform_param(indexTransHandle, + 'SQLTERMINATOR', TRUE); + +-- Retrieve dependent object DDLs as CLOBs and write them to table DDL. + LOOP + depObjDDL := dbms_metadata.fetch_clob(depObjOpenHandle); + EXIT WHEN depObjDDL IS NULL; + INSERT INTO ddl VALUES(depObjDDL, seqNo); + seqNo := seqNo + 1; + END LOOP; + +-- Free resources allocated for current dependent object stream. + dbms_metadata.close(depObjOpenHandle); + + END LOOP; -- End of fetch dependent objects loop + + END LOOP; -- End of fetch table loop + +-- Free resources allocated for table stream and close output file. + dbms_metadata.close(tableOpenHandle); + RETURN; + +END; -- of procedure get_payroll_tables + +END payroll_demo; +/ diff --git a/mddemo2.sql b/mddemo2.sql new file mode 100644 index 0000000..00026a4 --- /dev/null +++ b/mddemo2.sql @@ -0,0 +1,470 @@ +Rem +Rem $Header: mddemo2.sql 16-apr-2001.16:44:33 nmeng Exp $ +Rem +Rem mddemo2.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem mddemo2.sql - MetaData API Demo Part II +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem Oracle 9i demo of Metadata API Part II +Rem This script continues to demonstrate how to use the Metadata API. +Rem It first establishes a schema (mddemo) with associated grants. +Rem It then creates various objects for the demo purpose, including +Rem tables, indexes, fuctions and procedures. +Rem +Rem This demo shows the usage of Metadata API's browsing and +Rem programmatic APIs. Instead of writing the retrieved DDLs +Rem to a table, this script creates a procedure PRINT_DDL to +Rem display them. +Rem +Rem To run the demo, first cd to rdbms/demo directory. Then, +Rem % sqlplus /nolog +Rem SQL> @mddemo2 +Rem +Rem MODIFIED (MM/DD/YY) +Rem nmeng 04/16/01 - Merged nmeng_metadata_api_demo_010412 +Rem nmeng 04/13/01 - Created +Rem + +REM +REM initialize environment +REMARK >>>> Set System Variables For Current SQLPlus Session <<<< +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET PAGESIZE 0 +SET LINESIZE 200 +SET TRIMSPOOL ON +SET TAB OFF +SET DEFINE '^' + +set echo on +connect system/manager +drop user mddemo cascade; + +REM create new user: mddemo +grant connect, resource, select_catalog_role to mddemo identified by mddemo; + +REM grant select on scott.emp to mddemo +connect scott/tiger +grant select on emp to mddemo; + +REM start session as new user +connect mddemo/mddemo +set long 200000 +set serveroutput on size 1000000 + +REM create objects for demo +REM TABLE +CREATE TABLE EMP AS SELECT * FROM SCOTT.EMP; + +CREATE TABLE DEPT ( + DEPTNO NUMBER CONSTRAINT dept_pk PRIMARY KEY, + DNAME VARCHAR2(20), + LOCATION VARCHAR2(80) +); + +CREATE TABLE NEWEMP( + ENO NUMBER, + ENAME VARCHAR2(40), + DEPTNO NUMBER CONSTRAINT emp_fk REFERENCES DEPT +); + + +REM COMPOSITE INDEX +CREATE UNIQUE INDEX dept_uk1 ON DEPT(DNAME,LOCATION) +pctfree 40 +initrans 10 +maxtrans 20 +logging +compute statistics +compress 1 +nosort +STORAGE(INITIAL 8K NEXT 12K MINEXTENTS 1 MAXEXTENTS 120 PCTINCREASE 40 +FREELISTS 1 FREELIST GROUPS 4 BUFFER_POOL DEFAULT) TABLESPACE "SYSTEM" +parallel ( degree 5 instances 2); + +REM BITMAP INDEX +CREATE BITMAP INDEX dept_bitmap ON DEPT(LOCATION, DNAME) PARALLEL; + +REM FUNCTION +CREATE OR REPLACE FUNCTION f1( + arg1 NUMBER, + arg2 IN INTEGER, + arg3 OUT NOCOPY FLOAT, + arg4 IN OUT VARCHAR2 +) RETURN BLOB DETERMINISTIC PARALLEL_ENABLE +AUTHID CURRENT_USER IS + BEGIN + /* function body + . + . + . + */ + null; + END; +/ + + +REM PACKAGE +CREATE OR REPLACE PACKAGE MyPkg IS + FUNCTION sqr(x IN NUMBER) RETURN NUMBER; + PROCEDURE hello(name IN VARCHAR2); +END; +/ + +CREATE OR REPLACE PACKAGE BODY MyPkg AS + + FUNCTION sqr(x IN NUMBER) RETURN NUMBER IS + BEGIN + return x*x; + END; + + PROCEDURE hello(name IN VARCHAR2) IS + BEGIN + dbms_output.put_line('Hello ' || name); + END; +END; +/ + +CREATE OR REPLACE PACKAGE emp_mgmt AS + FUNCTION hire(ename VARCHAR2, + job VARCHAR2, + mgr NUMBER, + sal NUMBER, + comm NUMBER, + deptno NUMBER) + RETURN NUMBER; + FUNCTION create_dept(dname VARCHAR2,loc VARCHAR2) + RETURN NUMBER; + PROCEDURE remove_emp(empno NUMBER); + PROCEDURE remove_dept(deptno NUMBER); + PROCEDURE increase_sal(empno NUMBER, sal_incr NUMBER); + PROCEDURE increase_comm(empno NUMBER, comm_incr NUMBER); + no_comm EXCEPTION; + no_sal EXCEPTION; +END emp_mgmt; +/ + +CREATE OR REPLACE PACKAGE BODY emp_mgmt AS + tot_emps NUMBER; + tot_depts NUMBER; + + FUNCTION hire( + ename VARCHAR2, + job VARCHAR2, + mgr NUMBER, + sal NUMBER, + comm NUMBER, + deptno NUMBER) + RETURN NUMBER IS + new_empno NUMBER(4); + BEGIN + new_empno:=1; + RETURN(new_empno); + END; + + FUNCTION create_dept(dname VARCHAR2, loc VARCHAR2) + RETURN NUMBER IS + new_deptno NUMBER(4); + BEGIN + return 101; + END; + + PROCEDURE remove_emp(empno NUMBER) IS + BEGIN + null; + END; + + PROCEDURE remove_dept(deptno NUMBER) IS + BEGIN + null; + END; + + PROCEDURE increase_sal(empno NUMBER, sal_incr NUMBER) IS + curr_sal NUMBER(7,2); + BEGIN + null; + END; + + PROCEDURE increase_comm(empno NUMBER, comm_incr NUMBER) IS + curr_comm NUMBER(7,2); + BEGIN + null; + END; + +END emp_mgmt; +/ + + + + +REM *********** +REM * DEMOS * +REM *********** + +REM CREATE procedure PRINT_DDL to display fetched DDLs +CREATE OR REPLACE PROCEDURE Print_DDL(DDLString IN CLOB) +IS + str varchar2(32767); + tmpstr varchar2(32767); + len integer; + idx integer := 1; + nlidx integer; + newline character := chr(10); + BEGIN + str := substr(DDLString,1,31*1024); + + len := length(str); + loop + exit when idx >len; + nlidx := instr(str,newline,idx); + if (nlidx = 0) then + nlidx := len+1; + end if; + tmpstr := substr(str,idx,nlidx-idx); + + if(length(tmpstr) > 250) then + --print line or 250 bytes per line + tmpstr := '| '||tmpstr; + loop + exit when tmpstr is null; + dbms_output.put_line(substr(tmpstr,1,250)); + tmpstr := substr(tmpstr,251); + end loop; + else + dbms_output.put_line('| '||tmpstr); + end if; + + idx := nlidx+1; + end loop; + END Print_DDL; +/ + +REM create procedure PRINT_XML to print fetched XML +CREATE OR REPLACE PROCEDURE PRINT_XML (XMLString IN CLOB) IS +BEGIN + PRINT_DDL(XMLString); +END PRINT_XML; +/ + +REM BROWSING API: GET_XML, GET_DDL + +REM EXAMPLE 1 +REM Fetch the XML representation of EMP ( object in same schema) +SELECT DBMS_METADATA.GET_XML('TABLE','EMP') FROM DUAL; + +REM EXAMPLE 2 +REM Fetch the DDL of SCOTT.EMP (object in different schema) +-- first, get the complete DDL by not setting session transform parameter +SELECT DBMS_METADATA.GET_DDL('TABLE','EMP','SCOTT') FROM DUAL; + +-- then, get the ddl without the segment attributes. +-- we need to call SET_TRANSFORM_PARAM using SESSION_TRANSFORM to +-- set transform parameters for the whole session. +EXEC DBMS_METADATA.SET_TRANSFORM_PARAM( - + dbms_metadata.SESSION_TRANSFORM, - + 'SEGMENT_ATTRIBUTES', false); +SELECT DBMS_METADATA.GET_DDL('TABLE','EMP','SCOTT') FROM DUAL; +-- we now reset the transform parameters to default +EXEC DBMS_METADATA.SET_TRANSFORM_PARAM( - + dbms_metadata.SESSION_TRANSFORM, - + 'DEFAULT', true); + + +REM PROGRAMMATIC API + +REM EXAMPLE 3 +REM Retrieve all tables in the current schema as XML documents +DECLARE + handle NUMBER; + MyTable SYS.XMLType; + XMLString CLOB; +BEGIN + handle := DBMS_METADATA.OPEN('TABLE'); + LOOP + MyTable := DBMS_METADATA.FETCH_XML(handle); + EXIT WHEN MyTable IS NULL; + -- get the CLOB value of the XML document and print it + XMLString := MyTable.getClobVal; + PRINT_XML(XMLString); + END LOOP; + DBMS_METADATA.CLOSE(handle); +END; +/ + +REM You can also fetch the XML as CLOB directly +REM by using DBMS_METADATA.FETCH_CLOB +DECLARE + handle NUMBER; + XMLString CLOB; +BEGIN + handle := DBMS_METADATA.OPEN('TABLE'); + DBMS_METADATA.SET_FILTER(handle, 'NAME', 'NEWEMP'); + LOOP + XMLString := dbms_metadata.fetch_clob(handle); + EXIT when XmlString is NULL; + PRINT_XML(XMLString); + END LOOP; + DBMS_METADATA.CLOSE(handle); +END; +/ + + + +REM EXAMPLE 4 +REM Retrieve a package and package body as DDL +DECLARE + handle NUMBER; + tHandle NUMBER; + PkgTable SYS.KU$_DDLS; + PkgSpec CLOB; + PkgBody CLOB; +BEGIN + handle := DBMS_METADATA.OPEN('PACKAGE'); + DBMS_METADATA.SET_FILTER(handle,'NAME','MYPKG'); + -- setting SCHEMA filter to MDDEMO is Optional because + -- it is the current Schema + DBMS_METADATA.SET_FILTER(handle,'SCHEMA','MDDEMO'); + tHandle := DBMS_METADATA.ADD_TRANSFORM(handle, 'DDL'); + PkgTable := DBMS_METADATA.FETCH_DDL(Handle); + if (PkgTable is NOT NULL) then + -- Extract DDL text from the PkgTable + -- A package has two parts: specification and body + -- which are stored as two rows in the ddl table PkgTable + -- To retrieve the complete DDL for a package, + -- we need to get both PkgSpec and PkgBody ddls. + PkgSpec := PkgTable(1).ddlText; + PkgBody := PkgTable(2).ddlText; + Print_DDL(PkgSpec); + Print_DDL(PkgBody); + else + dbms_output.put_line('OBJECT NOT FOUND IN SCHEMA'); + end if; + DBMS_METADATA.CLOSE(handle); +END; +/ + +REM EXAMPLE 5 +REM Using dbms_metadata.set_filter to set filters +declare + h1 number; + th1 number; + ddls sys.ku$_ddls; + ddlstring clob; +begin + h1 := dbms_metadata.open('PACKAGE'); + -- Besides providing exact name and schema, we can also using + -- expressions: NAME_EXPR, and SCHEMA_EXPR for more flexiblity + dbms_metadata.set_filter(h1,'NAME_EXPR','IN (''EMP_MGMT'',''MYPKG'')'); + dbms_metadata.set_filter(h1,'SCHEMA_EXPR', 'like ''MDDEMO'' '); + + th1 := dbms_metadata.add_transform(h1, 'DDL'); + -- using default tranformation parameters + dbms_metadata.set_transform_param(th1,'DEFAULT', true); + ddls := dbms_metadata.fetch_ddl(h1); + + -- get all the fetched ddls by using a for loop + for i in ddls.FIRST..ddls.LAST loop + ddlstring :=ddls(i).ddlText; + Print_DDL(ddlstring); + end loop; + + dbms_metadata.close(h1); +end; +/ + +REM EXAMPLE 6 +REM Retrieving DDL for a function is the same as other objects. +REM This example shows how to use dbms_metadata.set_transform_param +declare + h1 number; + th1 number; + functionDDLs sys.ku$_ddls; + ddlstring clob; +begin + h1 := dbms_metadata.open('FUNCTION'); + + dbms_metadata.set_filter(h1,'NAME', 'F1'); + + th1 := dbms_metadata.add_transform(h1, 'DDL'); + + dbms_metadata.set_transform_param(th1,'PRETTY', true); + dbms_metadata.set_transform_param(th1,'SQLTERMINATOR', true); + functionDDLs := dbms_metadata.fetch_ddl(h1); + ddlstring := functionDDLs(1).ddlText; + Print_DDL(ddlstring); + dbms_metadata.close(h1); +end; +/ + +REM EXAMPLE 7 +REM A more complicated example +REM Example: Retrieve all tables in the current schema. For each table +REM return its indexes. This example shows the use of SET_PARSE_ITEM +REM to enable output parsing. + +DECLARE + handle1 NUMBER; + handle2 NUMBER; + tHandle1 NUMBER; + tHandle2 NUMBER; + SchemaName VARCHAR2(30); + TableName VARCHAR2(30); + TableDDLs sys.ku$_ddls; + TableDDL sys.ku$_ddl; + TableDDLtext CLOB; + parsedItems sys.ku$_parsed_items; + IndexDDLtext CLOB; +BEGIN + handle1 := dbms_metadata.open('TABLE'); + tHandle1 := dbms_metadata.add_transform(handle1,'DDL'); + dbms_metadata.set_parse_item(handle1,'NAME'); + dbms_metadata.set_parse_item(handle1,'SCHEMA'); + LOOP + TableDDLs := dbms_metadata.fetch_ddl(handle1); + EXIT WHEN TableDDLs IS NULL; + TableDDL := TableDDLs(1); + TableDDLtext := TableDDL.ddltext; + parsedItems := TableDDL.parsedItems; + + FOR i IN parsedItems.FIRST..parsedItems.LAST LOOP + IF parsedItems(i).item = 'SCHEMA' THEN + SchemaName := parsedItems(i).value; + ELSE + TableName := parsedItems(i).value; + END IF; + END LOOP; + -- open a second stream to fetch the table's indexes. + -- use the parsed schema and table names to construct + -- the filters + handle2 := dbms_metadata.open('INDEX'); + dbms_metadata.set_filter(handle2, 'BASE_OBJECT_SCHEMA', + SchemaName); + dbms_metadata.set_filter(handle2, 'BASE_OBJECT_NAME', + TableName); + tHandle2 := dbms_metadata.add_transform(handle2, 'DDL'); + -- do not fetch segment attributes + dbms_metadata.set_transform_param(tHandle2,'SEGMENT_ATTRIBUTES',false); + LOOP + IndexDDLtext := dbms_metadata.fetch_clob(handle2); + EXIT WHEN IndexDDLtext IS NULL; + -- print fetched DDLs + Print_DDL(IndexDDLtext); + END LOOP; + dbms_metadata.close(handle2); + END LOOP; + dbms_metadata.close(handle1); +END; +/ + + +REM cleanup +connect system/manager +drop user mddemo cascade; diff --git a/mdemo1.cpp b/mdemo1.cpp new file mode 100644 index 0000000..4d4a3ad --- /dev/null +++ b/mdemo1.cpp @@ -0,0 +1,98 @@ +#include "mdemo1.h" +#include "mdemo1m.h" + +// global Oracle variables + +Environment *env; +Connection *conn; +Statement *stmt; +ResultSet *rs; + +void initialize() { + + // Create environment + env = Environment::createEnvironment(Environment::OBJECT); + + // Call the OTT generated function to register the mappings + mdemo1m(env); + + // Create Connection + conn = env->createConnection( USERNAME, PASSWORD ); + + // Create a statement + stmt = conn->createStatement(); +} + +void terminateit() { + + //Terminate statement + conn->terminateStatement(stmt); + + //Terminate connection + env->terminateConnection(conn); + + //Terminate environment + Environment::terminateEnvironment(env); +} + +/* Do the work. + The environment is set up. + A single new entry is created in the Address table. + Then it is committed. +*/ +void dowrite() { + + // Create an Address + ADDRESS_O *addr1 = new(conn, "ADDR_TAB") ADDRESS_O("GE", "1211"); + Ref addr1_ref = (Ref) addr1->getRef(); + + // Create joe black + FullName *name1= new FullName("Joe", "Black"); + + Person *person1 = + new(conn, "PERSON_TAB") Person(1,name1,addr1_ref); + Ref person1_ref = (Ref) person1->getRef(); + + // Display, using reference + cout<<"-------------------"<displayInfo(); + cout<<"-------------------"<commit(); + +} + +void doread() +{ + // Retrieve joe black + string sel_joe = "SELECT REF(p) from person_tab p where \"id\" = 1"; + + rs =stmt->executeQuery (sel_joe); + + // Get reference + rs->next(); + Ref joe_ref = (Ref) rs->getRef(1); + + // Display, using reference + cout<<"-------------------"<displayInfo(); + cout<<"-------------------"<closeResultSet(rs); + +} + +int main() { + + try { + initialize(); + dowrite(); + doread(); + terminateit(); + } + catch (SQLException &e) { + cout << "SQL exception :" << e.getMessage() << endl; + } + + return 0; +} diff --git a/mdemo1.h b/mdemo1.h new file mode 100644 index 0000000..ba7b80f --- /dev/null +++ b/mdemo1.h @@ -0,0 +1,201 @@ +#ifndef MDEMO1_ORACLE +# define MDEMO1_ORACLE + +#ifndef OTT_USERCODE_START +# define OTT_USERCODE_START +#endif + +#ifndef OTT_USERCODE_END +# define OTT_USERCODE_END +#endif + +#ifndef OCCI_ORACLE +# include +#endif + +OTT_USERCODE_START +#include "mymdemo1.h" +OTT_USERCODE_END + + +/************************************************************/ +// generated declarations for the FULL_NAME_O object type. +/************************************************************/ + +class FULL_NAME_O : public oracle::occi::PObject { + +protected: + + OCCI_STD_NAMESPACE::string first_name; + OCCI_STD_NAMESPACE::string last_name; + +public: + + void *operator new(size_t size); + + void *operator new(size_t size, const oracle::occi::Connection * sess, + const OCCI_STD_NAMESPACE::string& table); + + void *operator new(size_t, void *ctxOCCI_); + + void *operator new(size_t size, const oracle::occi::Connection *sess, + const OCCI_STD_NAMESPACE::string &tableName, + const OCCI_STD_NAMESPACE::string &typeName, + const OCCI_STD_NAMESPACE::string &tableSchema, + const OCCI_STD_NAMESPACE::string &typeSchema); + + OCCI_STD_NAMESPACE::string getSQLTypeName() const; + + void getSQLTypeName(oracle::occi::Environment *env, void **schemaName, + unsigned int &schemaNameLen, void **typeName, + unsigned int &typeNameLen) const; + + FULL_NAME_O(); + + FULL_NAME_O(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { }; + + static void *readSQL(void *ctxOCCI_); + + virtual void readSQL(oracle::occi::AnyData& streamOCCI_); + + static void writeSQL(void *objOCCI_, void *ctxOCCI_); + + virtual void writeSQL(oracle::occi::AnyData& streamOCCI_); + + ~FULL_NAME_O(); + +}; + +OTT_USERCODE_START + +class FullName : public FULL_NAME_O { +public: + FullName(void *ctxOCCI_); + FullName(string FirstName, string LastName); + void displayInfo(); + const string getFirstName() const { return first_name;} + ~FullName(); +} ; + +OTT_USERCODE_END + +/************************************************************/ +// generated declarations for the ADDRESS_O object type. +/************************************************************/ + +class ADDRESS_O : public oracle::occi::PObject { + +protected: + + OCCI_STD_NAMESPACE::string state; + OCCI_STD_NAMESPACE::string zip; + +public: + + void *operator new(size_t size); + + void *operator new(size_t size, const oracle::occi::Connection * sess, + const OCCI_STD_NAMESPACE::string& table); + + void *operator new(size_t, void *ctxOCCI_); + + void *operator new(size_t size, const oracle::occi::Connection *sess, + const OCCI_STD_NAMESPACE::string &tableName, + const OCCI_STD_NAMESPACE::string &typeName, + const OCCI_STD_NAMESPACE::string &tableSchema, + const OCCI_STD_NAMESPACE::string &typeSchema); + + OCCI_STD_NAMESPACE::string getSQLTypeName() const; + + void getSQLTypeName(oracle::occi::Environment *env, void **schemaName, + unsigned int &schemaNameLen, void **typeName, + unsigned int &typeNameLen) const; + + ADDRESS_O(); + + ADDRESS_O(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { }; + + static void *readSQL(void *ctxOCCI_); + + virtual void readSQL(oracle::occi::AnyData& streamOCCI_); + + static void writeSQL(void *objOCCI_, void *ctxOCCI_); + + virtual void writeSQL(oracle::occi::AnyData& streamOCCI_); + + ~ADDRESS_O(); + +OTT_USERCODE_START + + ADDRESS_O(string state_i, string zip_i); + void displayInfo(); + +OTT_USERCODE_END + +}; + +/************************************************************/ +// generated declarations for the PERSON_O object type. +/************************************************************/ + +class PERSON_O : public oracle::occi::PObject { + +protected: + + oracle::occi::Number id; + FullName * name; + oracle::occi::Ref< ADDRESS_O > addr; + +public: + + void *operator new(size_t size); + + void *operator new(size_t size, const oracle::occi::Connection * sess, + const OCCI_STD_NAMESPACE::string& table); + + void *operator new(size_t, void *ctxOCCI_); + + void *operator new(size_t size, const oracle::occi::Connection *sess, + const OCCI_STD_NAMESPACE::string &tableName, + const OCCI_STD_NAMESPACE::string &typeName, + const OCCI_STD_NAMESPACE::string &tableSchema, + const OCCI_STD_NAMESPACE::string &typeSchema); + + OCCI_STD_NAMESPACE::string getSQLTypeName() const; + + void getSQLTypeName(oracle::occi::Environment *env, void **schemaName, + unsigned int &schemaNameLen, void **typeName, + unsigned int &typeNameLen) const; + + PERSON_O(); + + PERSON_O(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { }; + + static void *readSQL(void *ctxOCCI_); + + virtual void readSQL(oracle::occi::AnyData& streamOCCI_); + + static void writeSQL(void *objOCCI_, void *ctxOCCI_); + + virtual void writeSQL(oracle::occi::AnyData& streamOCCI_); + + ~PERSON_O(); + +}; + +OTT_USERCODE_START + +class Person : public PERSON_O { +public: + Person(void *ctxOCCI_); + Person(int id_i, + FullName* name_i, + Ref& addr_i); + void move(const Ref& new_addr); + void displayInfo(); + ~Person(); +}; + +OTT_USERCODE_END + +#endif diff --git a/mdemo1.sql b/mdemo1.sql new file mode 100644 index 0000000..5b46b33 --- /dev/null +++ b/mdemo1.sql @@ -0,0 +1,34 @@ +connect scott/tiger; + +DROP TABLE PERSON_TAB; +DROP TABLE ADDR_TAB; +DROP TYPE PERSON_O; +DROP TYPE ADDRESS_O; +DROP TYPE FULL_NAME_O; + + +CREATE TYPE ADDRESS_O AS OBJECT ( + "state" CHAR(20), + "zip" CHAR(20) +) +/ + +CREATE TABLE ADDR_TAB OF ADDRESS_O; + +CREATE TYPE FULL_NAME_O AS OBJECT ( + "first_name" CHAR(20), + "last_name" CHAR(20) +) +/ + +CREATE TYPE PERSON_O AS OBJECT ( + "id" integer, + "name" FULL_NAME_O, + "addr" REF ADDRESS_O +) +/ + + +CREATE TABLE PERSON_TAB OF PERSON_O; + +QUIT; diff --git a/mdemo1.typ b/mdemo1.typ new file mode 100644 index 0000000..88c6ce0 --- /dev/null +++ b/mdemo1.typ @@ -0,0 +1,7 @@ +CASE=SAME +MAPFILE=mdemo1m.cpp +TYPE FULL_NAME_O + GENERATE FULL_NAME_O AS FullName +TYPE ADDRESS_O +TYPE PERSON_O + GENERATE PERSON_O AS Person diff --git a/mdemo1o.cpp b/mdemo1o.cpp new file mode 100644 index 0000000..b47eafc --- /dev/null +++ b/mdemo1o.cpp @@ -0,0 +1,422 @@ +#ifndef OTT_USERCODE_START +# define OTT_USERCODE_START +#endif + +#ifndef OTT_USERCODE_END +# define OTT_USERCODE_END +#endif + +#ifndef MDEMO1_ORACLE +# include "mdemo1.h" +#endif + + +/*****************************************************************/ +// generated method implementations for the FULL_NAME_O object type. +/*****************************************************************/ + +void *FULL_NAME_O::operator new(size_t size) +{ + return oracle::occi::PObject::operator new(size); +} + +void *FULL_NAME_O::operator new(size_t size, const oracle::occi::Connection * sess, + const OCCI_STD_NAMESPACE::string& table) +{ + return oracle::occi::PObject::operator new(size, sess, table, + (char *) "SCOTT.FULL_NAME_O"); +} + +void *FULL_NAME_O::operator new(size_t size, void *ctxOCCI_) +{ + return oracle::occi::PObject::operator new(size, ctxOCCI_); +} + +void *FULL_NAME_O::operator new(size_t size, + const oracle::occi::Connection *sess, + const OCCI_STD_NAMESPACE::string &tableName, + const OCCI_STD_NAMESPACE::string &typeName, + const OCCI_STD_NAMESPACE::string &tableSchema, + const OCCI_STD_NAMESPACE::string &typeSchema) +{ + return oracle::occi::PObject::operator new(size, sess, tableName, + typeName, tableSchema, typeSchema); +} + +OCCI_STD_NAMESPACE::string FULL_NAME_O::getSQLTypeName() const +{ + return OCCI_STD_NAMESPACE::string("SCOTT.FULL_NAME_O"); +} + +void FULL_NAME_O::getSQLTypeName(oracle::occi::Environment *env, void **schemaName, + unsigned int &schemaNameLen, void **typeName, unsigned int &typeNameLen) const +{ + PObject::getSQLTypeName(env, &FULL_NAME_O::readSQL, schemaName, + schemaNameLen, typeName, typeNameLen); +} + +FULL_NAME_O::FULL_NAME_O() +{ +} + +OTT_USERCODE_START + +FullName::FullName(void *ctxOCCI_): FULL_NAME_O(ctxOCCI_) +{ +} + +OTT_USERCODE_END + +void *FULL_NAME_O::readSQL(void *ctxOCCI_) +{ + FullName *objOCCI_ = new(ctxOCCI_) FullName(ctxOCCI_); + oracle::occi::AnyData streamOCCI_(ctxOCCI_); + + try + { + if (streamOCCI_.isNull()) + objOCCI_->setNull(); + else + objOCCI_->readSQL(streamOCCI_); + } + catch (oracle::occi::SQLException& excep) + { + delete objOCCI_; + excep.setErrorCtx(ctxOCCI_); + return (void *)NULL; + } + return (void *)objOCCI_; +} + +void FULL_NAME_O::readSQL(oracle::occi::AnyData& streamOCCI_) +{ + first_name = streamOCCI_.getString(); + last_name = streamOCCI_.getString(); +} + +void FULL_NAME_O::writeSQL(void *objectOCCI_, void *ctxOCCI_) +{ + FULL_NAME_O *objOCCI_ = (FULL_NAME_O *) objectOCCI_; + oracle::occi::AnyData streamOCCI_(ctxOCCI_); + + try + { + if (objOCCI_->isNull()) + streamOCCI_.setNull(); + else + objOCCI_->writeSQL(streamOCCI_); + } + catch (oracle::occi::SQLException& excep) + { + excep.setErrorCtx(ctxOCCI_); + } + return; +} + +void FULL_NAME_O::writeSQL(oracle::occi::AnyData& streamOCCI_) +{ + streamOCCI_.setString(first_name); + streamOCCI_.setString(last_name); +} + +FULL_NAME_O::~FULL_NAME_O() +{ + int i; +} + +OTT_USERCODE_START + +// initialize FullName +FullName::FullName(string FirstName, string LastName) +{ + first_name = FirstName; + last_name = LastName; +} + +// display all the information in FullName +void FullName::displayInfo() +{ + cout << "FIRST NAME is " << first_name << endl; + cout << "LAST NAME is " << last_name << endl; +} + +FullName::~FullName() +{ +} + +OTT_USERCODE_END + +/*****************************************************************/ +// generated method implementations for the ADDRESS_O object type. +/*****************************************************************/ + +void *ADDRESS_O::operator new(size_t size) +{ + return oracle::occi::PObject::operator new(size); +} + +void *ADDRESS_O::operator new(size_t size, const oracle::occi::Connection * sess, + const OCCI_STD_NAMESPACE::string& table) +{ + return oracle::occi::PObject::operator new(size, sess, table, + (char *) "SCOTT.ADDRESS_O"); +} + +void *ADDRESS_O::operator new(size_t size, void *ctxOCCI_) +{ + return oracle::occi::PObject::operator new(size, ctxOCCI_); +} + +void *ADDRESS_O::operator new(size_t size, + const oracle::occi::Connection *sess, + const OCCI_STD_NAMESPACE::string &tableName, + const OCCI_STD_NAMESPACE::string &typeName, + const OCCI_STD_NAMESPACE::string &tableSchema, + const OCCI_STD_NAMESPACE::string &typeSchema) +{ + return oracle::occi::PObject::operator new(size, sess, tableName, + typeName, tableSchema, typeSchema); +} + +OCCI_STD_NAMESPACE::string ADDRESS_O::getSQLTypeName() const +{ + return OCCI_STD_NAMESPACE::string("SCOTT.ADDRESS_O"); +} + +void ADDRESS_O::getSQLTypeName(oracle::occi::Environment *env, void **schemaName, + unsigned int &schemaNameLen, void **typeName, unsigned int &typeNameLen) const +{ + PObject::getSQLTypeName(env, &ADDRESS_O::readSQL, schemaName, + schemaNameLen, typeName, typeNameLen); +} + +ADDRESS_O::ADDRESS_O() +{ +} + +void *ADDRESS_O::readSQL(void *ctxOCCI_) +{ + ADDRESS_O *objOCCI_ = new(ctxOCCI_) ADDRESS_O(ctxOCCI_); + oracle::occi::AnyData streamOCCI_(ctxOCCI_); + + try + { + if (streamOCCI_.isNull()) + objOCCI_->setNull(); + else + objOCCI_->readSQL(streamOCCI_); + } + catch (oracle::occi::SQLException& excep) + { + delete objOCCI_; + excep.setErrorCtx(ctxOCCI_); + return (void *)NULL; + } + return (void *)objOCCI_; +} + +void ADDRESS_O::readSQL(oracle::occi::AnyData& streamOCCI_) +{ + state = streamOCCI_.getString(); + zip = streamOCCI_.getString(); +} + +void ADDRESS_O::writeSQL(void *objectOCCI_, void *ctxOCCI_) +{ + ADDRESS_O *objOCCI_ = (ADDRESS_O *) objectOCCI_; + oracle::occi::AnyData streamOCCI_(ctxOCCI_); + + try + { + if (objOCCI_->isNull()) + streamOCCI_.setNull(); + else + objOCCI_->writeSQL(streamOCCI_); + } + catch (oracle::occi::SQLException& excep) + { + excep.setErrorCtx(ctxOCCI_); + } + return; +} + +void ADDRESS_O::writeSQL(oracle::occi::AnyData& streamOCCI_) +{ + streamOCCI_.setString(state); + streamOCCI_.setString(zip); +} + +ADDRESS_O::~ADDRESS_O() +{ + int i; +} + +OTT_USERCODE_START + +// initialize ADDRESS_O +ADDRESS_O::ADDRESS_O(string state_i, string zip_i) +{ + state = state_i; + zip = zip_i; +} + +// display all the information in ADDRESS_O +void ADDRESS_O::displayInfo() +{ + cout << "STATE is " << state << endl; + cout << "ZIP is " << zip << endl; +} + +OTT_USERCODE_END + +/*****************************************************************/ +// generated method implementations for the PERSON_O object type. +/*****************************************************************/ + +void *PERSON_O::operator new(size_t size) +{ + return oracle::occi::PObject::operator new(size); +} + +void *PERSON_O::operator new(size_t size, const oracle::occi::Connection * sess, + const OCCI_STD_NAMESPACE::string& table) +{ + return oracle::occi::PObject::operator new(size, sess, table, + (char *) "SCOTT.PERSON_O"); +} + +void *PERSON_O::operator new(size_t size, void *ctxOCCI_) +{ + return oracle::occi::PObject::operator new(size, ctxOCCI_); +} + +void *PERSON_O::operator new(size_t size, + const oracle::occi::Connection *sess, + const OCCI_STD_NAMESPACE::string &tableName, + const OCCI_STD_NAMESPACE::string &typeName, + const OCCI_STD_NAMESPACE::string &tableSchema, + const OCCI_STD_NAMESPACE::string &typeSchema) +{ + return oracle::occi::PObject::operator new(size, sess, tableName, + typeName, tableSchema, typeSchema); +} + +OCCI_STD_NAMESPACE::string PERSON_O::getSQLTypeName() const +{ + return OCCI_STD_NAMESPACE::string("SCOTT.PERSON_O"); +} + +void PERSON_O::getSQLTypeName(oracle::occi::Environment *env, void **schemaName, + unsigned int &schemaNameLen, void **typeName, unsigned int &typeNameLen) const +{ + PObject::getSQLTypeName(env, &PERSON_O::readSQL, schemaName, + schemaNameLen, typeName, typeNameLen); +} + +PERSON_O::PERSON_O() +{ + name = (FullName *) 0; +} + +OTT_USERCODE_START + +Person::Person(void *ctxOCCI_): PERSON_O(ctxOCCI_) +{ +} + +OTT_USERCODE_END + +void *PERSON_O::readSQL(void *ctxOCCI_) +{ + Person *objOCCI_ = new(ctxOCCI_) Person(ctxOCCI_); + oracle::occi::AnyData streamOCCI_(ctxOCCI_); + + try + { + if (streamOCCI_.isNull()) + objOCCI_->setNull(); + else + objOCCI_->readSQL(streamOCCI_); + } + catch (oracle::occi::SQLException& excep) + { + delete objOCCI_; + excep.setErrorCtx(ctxOCCI_); + return (void *)NULL; + } + return (void *)objOCCI_; +} + +void PERSON_O::readSQL(oracle::occi::AnyData& streamOCCI_) +{ + id = streamOCCI_.getNumber(); + name = (FullName *) streamOCCI_.getObject(&FullName::readSQL); + addr = streamOCCI_.getRef(); +} + +void PERSON_O::writeSQL(void *objectOCCI_, void *ctxOCCI_) +{ + PERSON_O *objOCCI_ = (PERSON_O *) objectOCCI_; + oracle::occi::AnyData streamOCCI_(ctxOCCI_); + + try + { + if (objOCCI_->isNull()) + streamOCCI_.setNull(); + else + objOCCI_->writeSQL(streamOCCI_); + } + catch (oracle::occi::SQLException& excep) + { + excep.setErrorCtx(ctxOCCI_); + } + return; +} + +void PERSON_O::writeSQL(oracle::occi::AnyData& streamOCCI_) +{ + streamOCCI_.setNumber(id); + streamOCCI_.setObject(name); + streamOCCI_.setRef(addr); +} + +PERSON_O::~PERSON_O() +{ + int i; + delete name; +} + +OTT_USERCODE_START + +// initialize Person +Person::Person(int id_i, + FullName *name_i, + Ref& addr_i) +{ + id = id_i; + name = name_i; + addr =addr_i ; +} + +// Move Person from curr_addr to new_addr +void Person::move(const Ref& new_addr) +{ + addr = new_addr; + this->markModified(); // mark the object as dirty +} + +// Display all the information of Person +void Person::displayInfo() { + cout << "ID is " << (int)id << endl; + name->displayInfo(); + + // de-referencing the Ref attribute using -> operator + addr->displayInfo(); + +} + +Person::~Person() +{ +} + +OTT_USERCODE_END diff --git a/mymdemo1.h b/mymdemo1.h new file mode 100644 index 0000000..f7d0897 --- /dev/null +++ b/mymdemo1.h @@ -0,0 +1,8 @@ +# include + +#define USERNAME "scott" +#define PASSWORD "tiger" + +using namespace oracle::occi; +using namespace std; + diff --git a/nchdemo1.c b/nchdemo1.c new file mode 100644 index 0000000..2b6fd77 --- /dev/null +++ b/nchdemo1.c @@ -0,0 +1,586 @@ +/* Copyright (c) 2001, 2009, Oracle and/or its affiliates. +All rights reserved. */ + +/* + + NAME + nchdemo1.c - show nchar implicit conversion feature and codepoint feature + + DESCRIPTION + * Demo description: + * 1.Implicit conversion: + * the data being inserted into nchar column of this table is in + * zhs16gbk encoding, you don't need specify charsetfm to + * SQLCS_NCHAR in bind/define. implicit conversion will happend + * and automatic convert zhs16gbk data into al16utf16 while + * insert and convert it back while doing select. + * 2.Benefit from codepoint semantics: Client side application + * independent of server character set. + * Since Nchar is always in codepoint semantics, via implict + * describe, you can get the char size of nchar column, the number + * is always in characters, so the client side buffer is allocated + * as number of characters times max char-width of client side + * charset. even server side ncharset is changed from al16utf16 + * to utf8, you don't need re-allocate the client side buffer. + * + * Setup: to show the implicit conversion feature, you need create your + * database with database character set is utf8, otherwise, data loss will + * happened when doing implicit conversion. + * + * Note: the data is in zhs16gbk encoding, other platform can't display the + * chinese character correctly. + * + + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + + + MODIFIED (MM/DD/YY) + wezhu 05/28/09 - remove hard tabs + wezhu 05/21/09 - provide errhp to checkerr function call. + chli 11/04/02 - fix bug2840920 + chli 07/20/01 - fix bug1891086 + chli 06/20/01 - fix compile warning + chli 03/15/01 - Merged chli_fixdiff_0313 + chli 03/15/01 - Creation + +*/ + + +#ifndef STDIO +#include +#endif + +#ifndef CTYPE +#include +#endif + +#ifndef OCI_ORACLE +#include +#endif + +#define OCI_UNICODE_U OCI_UNICODE +#define OCI_UNICODE_D OCI_DEFAULT +#define OCI_UNICODE_N OCI_NON_UNICODE + +OCIEnv *envhp; +OCIServer *srvhp; +OCIError *errhp; +OCISvcCtx *svchp; +OCISession *authp; + + +void main(); +static void checkerr(/*errhp, status*/); +sword init_env(/*_envhp, svchp, errhp, srvhp, authp, env_mode_*/); +sword attach_server(/*_server_mode, srvhp, errhp, svchp_*/); +sword log_on(/*_authp, errhp, svchp, uid, pwd, credt, session_mode_*/); +sword free_handles(); + + +void main() +{ + +ub4 env_mode = OCI_UNICODE_D; +ub4 server_mode = OCI_UNICODE_D; +ub4 session_mode = OCI_UNICODE_D; +ub4 stmt_mode = OCI_UNICODE_D; +ub4 bind_mode = OCI_UNICODE_D; +ub4 def_mode = OCI_UNICODE_D; + +text *uid = (text *)"oe"; +text *pwd = (text *)"oe"; + +static text *stmt=(text *)"INSERT INTO product_descriptions VALUES (:product_id, :language_id, :translated_name, :translated_description)"; +static text *sel_stmt=(text *)"SELECT * FROM product_descriptions where product_id= :id"; +static text *del_stmt=(text *)"DELETE FROM product_descriptions where product_id= :id"; + +OCIStmt *stmt1p; +OCIStmt *stmt2p; +OCIStmt *stmt3p; + +OCIParam *mypard; + +static OCIBind *bnd1p = (OCIBind *)0; +static OCIBind *bnd2p = (OCIBind *)0; +static OCIBind *bnd3p = (OCIBind *)0; +static OCIBind *bnd4p = (OCIBind *)0; +static OCIBind *bnd5p = (OCIBind *)0; + +static OCIDefine *dfn1p,*dfn4p,*dfn2p,*dfn3p; + +static text *colname1 = (text *)":product_id"; +static text *colname2 = (text *)":language_id"; +static text *colname3 = (text *)":translated_name"; +static text *colname4 = (text *)":translated_description"; +static text *colname5 = (text *)":id"; + +ub2 sqltype1 = SQLT_INT; +ub2 sqltype2 = SQLT_DAT; +ub2 sqltype3 = SQLT_STR; +ub2 sqltype4 = SQLT_STR; +ub2 sqltype5 = SQLT_BIN; + + +ub4 credt = OCI_CRED_RDBMS; +char char1_in[4],char2_in[50],char3_in[100]; +sb2 ind=0; +dvoid *tmp; +sword err, status, i; +sword in_id, out_id; + +/*char *char1_outp, *char2_outp, *char3_outp;*/ +char char1_outp[40], char2_outp[40], char3_outp[40]; + +ub4 bmaxsiz = 20; +ub4 cmaxsiz = 20; +ub1 char_semantics; +ub2 col_width2, col_width3, col_width4; +ub2 chrsetid = 852; +ub1 flag2, flag3, flag4; + + + in_id=100081; + strcpy(char1_in,"zhs"); + char1_in[3]='\0'; + strcpy(char2_in,"ÊǸÉ"); + char2_in[8]='\0'; + strcpy(char3_in,"ÒøÁøÊǸɻ¨µÄÒ»ÖÖ£¬·ÅÓÚÊÒÄڿɾ­Ä겻л"); + char3_in[36]='\0'; + +/* + char1_outp=(char *)malloc(40); + char2_outp=(char *)malloc(40); + char3_outp=(char *)malloc(40); +*/ + + for (i=0; i<40; i++) + { + char1_outp[i]='\0'; + char2_outp[i]='\0'; + char3_outp[i]='\0'; + } + + init_env(env_mode); + attach_server(server_mode); + log_on(uid, pwd, credt, session_mode); + +/*---- Insert operation -------*/ + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **)&stmt1p, + (ub4)OCI_HTYPE_STMT,100, (dvoid **) &tmp)); + checkerr(errhp, OCIStmtPrepare(stmt1p, errhp, stmt, (ub4)strlen((char *)stmt), + (ub4)OCI_NTV_SYNTAX, (ub4)stmt_mode)); + + checkerr(errhp, OCIBindByName(stmt1p, &bnd1p, errhp, (text *)colname1, + (sb4)strlen((char*)colname1), + (dvoid *)&in_id, (sb4)sizeof(sword), sqltype1, (dvoid *)&ind, + (ub2 *) 0, (ub2 *) 0, (ub4) 0,(ub4 *)0,bind_mode)); + + checkerr(errhp, OCIBindByName(stmt1p, &bnd2p, errhp, (text *)colname2, + (sb4)strlen((char*)colname2), + (dvoid *)char1_in, (sb4)sizeof(char1_in), sqltype3, + (dvoid *)&ind, + (ub2 *) 0, (ub2 *) 0, (ub4) 0,(ub4 *)0,bind_mode)); + checkerr(errhp, OCIBindByName(stmt1p, &bnd3p, errhp, (text *)colname3, + (sb4)strlen((char*)colname3), + (dvoid *)char2_in, (sb4)sizeof(char2_in), sqltype3, + (dvoid *)&ind,(ub2 *) 0, (ub2 *) 0, + (ub4) 0,(ub4 *)0,bind_mode)); + checkerr(errhp, OCIBindByName(stmt1p, &bnd4p, errhp, (text *)colname4, + (sb4)strlen((char*)colname4), + (dvoid *)char3_in, (sb4)sizeof(char3_in), sqltype3, + (dvoid *)&ind,(ub2 *) 0, (ub2 *) 0, + (ub4) 0,(ub4 *)0,bind_mode)); + +/* set character id 852(zhs16gbk) for varchar2 and nvarchar2 column + you don't need specify charset_form here, since oracle will do the + implicit conversion from char to nchar for you. +*/ + + + checkerr(errhp,OCIAttrSet((dvoid *)bnd2p, (ub4) OCI_HTYPE_BIND, + (dvoid *)&chrsetid, (ub4) 0, + (ub4) OCI_ATTR_CHARSET_ID, errhp)); + checkerr(errhp,OCIAttrSet((dvoid *)bnd3p, (ub4) OCI_HTYPE_BIND, + (dvoid *)&chrsetid, (ub4) 0, + (ub4) OCI_ATTR_CHARSET_ID, errhp)); + checkerr(errhp,OCIAttrSet((dvoid *)bnd4p, (ub4) OCI_HTYPE_BIND, + (dvoid *)&chrsetid, (ub4) 0, + (ub4) OCI_ATTR_CHARSET_ID, errhp)); + + + err=OCIStmtExecute (svchp, stmt1p, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)NULL,(OCISnapshot *)NULL, (ub4)OCI_DEFAULT); + + if (err == OCI_SUCCESS ) + printf("Insert successful\n"); + else + { + checkerr(errhp,err); + return; + } + + OCITransCommit(svchp, errhp, 0); + +/* end: ------ Insert complete -----------------*/ + + +/* begin: ------ get char counts of each column by call OCIParamGet ---- */ + + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **)&stmt2p, + (ub4)OCI_HTYPE_STMT,100, (dvoid **) &tmp)); + checkerr(errhp, OCIStmtPrepare(stmt2p, errhp, sel_stmt, (ub4)strlen((char *)sel_stmt), + (ub4)OCI_NTV_SYNTAX, (ub4)stmt_mode)); + + checkerr(errhp, OCIStmtExecute(svchp,stmt2p,errhp,(ub4)1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, (ub4)OCI_DESCRIBE_ONLY)); + err = OCIParamGet(stmt2p,OCI_HTYPE_STMT,errhp,&mypard, (ub4)2); + if (err == OCI_SUCCESS) + { + checkerr(errhp, OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&char_semantics, (ub4)0, (ub4)OCI_ATTR_CHAR_USED, + (OCIError *)errhp)); + if (char_semantics) { + checkerr(errhp,OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&col_width2,(ub4)0,(ub4)OCI_ATTR_CHAR_SIZE,(OCIError *)errhp)); + flag2=1; + } + else { + checkerr(errhp,OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&col_width2,(ub4)0,(ub4)OCI_ATTR_DATA_SIZE,(OCIError *)errhp)); + flag2=0; + } + } + else + checkerr(errhp,err); + + err = OCIParamGet(stmt2p,OCI_HTYPE_STMT,errhp,&mypard, (ub4)3); + if (err == OCI_SUCCESS) + { + checkerr(errhp, OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&char_semantics, (ub4)0, (ub4)OCI_ATTR_CHAR_USED, + (OCIError *)errhp)); + if (char_semantics) { + checkerr(errhp,OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&col_width3,(ub4)0,(ub4)OCI_ATTR_CHAR_SIZE,(OCIError *)errhp)); + flag3=1; + } + else { + checkerr(errhp,OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&col_width3,(ub4)0,(ub4)OCI_ATTR_DATA_SIZE,(OCIError *)errhp)); + flag3=0; + } + + /* since in codepoint semantics mode, the col_width is always return in + number of characters, the client side buffer size should be the number + of characters tims maximun char-width of client side charset. the max + charwidth for zhs16gbk is 2. */ + /* char2_outp=(char *)malloc(sizeof(char)*col_width3*2); */ + } + else + checkerr(errhp,err); + + /* ---- get char count of second column. ---- */ + err = OCIParamGet(stmt2p,OCI_HTYPE_STMT,errhp,&mypard, (ub4)4); + if (err == OCI_SUCCESS) + { + checkerr(errhp, OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&char_semantics, (ub4)0, (ub4)OCI_ATTR_CHAR_USED, + (OCIError *)errhp)); + if (char_semantics) { + checkerr(errhp,OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&col_width4,(ub4)0,(ub4)OCI_ATTR_CHAR_SIZE,(OCIError *)errhp)); + flag4=1; + } + else { + checkerr(errhp,OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&col_width4,(ub4)0,(ub4)OCI_ATTR_DATA_SIZE,(OCIError *)errhp)); + flag4=0; + } +/* + char3_outp=(char *)malloc(sizeof(char)*col_width4*2); +*/ + } + else + checkerr(errhp,err); + + + /* ---- define the output buffer and do the query ---- */ + checkerr(errhp,OCIDefineByPos(stmt2p, &dfn1p, errhp, 1, (dvoid *)&out_id, + sizeof(out_id), sqltype1, (dvoid *)0, (ub2 *)0, + (ub2 *)0, def_mode)); + checkerr(errhp,OCIDefineByPos(stmt2p, &dfn2p, errhp, 2, (dvoid *)char1_outp, + 9, sqltype3, (dvoid *)0, (ub2 *)0, (ub2 *)0, def_mode)); + checkerr(errhp,OCIDefineByPos(stmt2p, &dfn3p, errhp, 3, (dvoid *)char2_outp, + col_width3, sqltype3, (dvoid *)0, (ub2 *)0, (ub2 *)0, def_mode)); + checkerr(errhp,OCIDefineByPos(stmt2p, &dfn4p, errhp, 4, (dvoid *)char3_outp, + col_width4, sqltype3, (dvoid *)0, (ub2 *)0, (ub2 *)0, def_mode)); + +/* --- set the charset-id to 852 for output buffer ---- */ + + checkerr(errhp,OCIAttrSet((dvoid *)dfn2p, (ub4) OCI_HTYPE_DEFINE, + (dvoid *)&chrsetid, (ub4) 0, + (ub4) OCI_ATTR_CHARSET_ID, errhp)); + + checkerr(errhp,OCIAttrSet((dvoid *)dfn3p, (ub4) OCI_HTYPE_DEFINE, + (dvoid *)&chrsetid, (ub4) 0, + (ub4) OCI_ATTR_CHARSET_ID, errhp)); + + checkerr(errhp,OCIAttrSet((dvoid *)dfn4p, (ub4) OCI_HTYPE_DEFINE, + (dvoid *)&chrsetid, (ub4) 0, + (ub4) OCI_ATTR_CHARSET_ID, errhp)); + + checkerr(errhp, OCIBindByName(stmt2p, &bnd5p, errhp, (text *)colname5, + (sb4)strlen((char*)colname5), + (dvoid *)&in_id, (sb4)sizeof(sword), sqltype1, (dvoid *)&ind, + (ub2 *) 0, (ub2 *) 0, (ub4) 0,(ub4 *)0,bind_mode)); + + err = OCIStmtExecute (svchp, stmt2p, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)NULL,(OCISnapshot *)NULL, (ub4)OCI_DEFAULT); + + checkerr(errhp, err); + if (err == OCI_SUCCESS || err == OCI_SUCCESS_WITH_INFO) + { + do + { + printf("product_id is : %d\n", out_id); + if (flag2==1) + printf("column language id is char semantics and the width is: %d chars\n",col_width2); + else + printf("column language id is byte semantics and the width is: %d bytes\n",col_width2); + printf("language_id is : %s\n\n", char1_outp); + + if (flag3==1) + printf("column translated_name is char semantics and the width is: %d chars\n",col_width3); + else + printf("column translated_name is byte semantics and the width is: %d bytes\n",col_width3); + printf("translated_name is : %s\n\n", char2_outp); + + if (flag4==1) + printf("column product_description is char semantics and the width is: %d chars\n",col_width4); + else + printf("column product_description is byte semantics and the width is: %d bytes\n",col_width4); + printf("product_description is : %s\n\n", char3_outp); + + status = OCIStmtFetch(stmt2p, errhp, (ub4) 1, + (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT); + }while (status == OCI_SUCCESS || status == OCI_SUCCESS_WITH_INFO); + } + +/****** delete temporary data *******/ + + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **)&stmt3p, + (ub4)OCI_HTYPE_STMT,100, (dvoid **) &tmp)); + checkerr(errhp, OCIStmtPrepare(stmt3p, errhp, del_stmt, + (ub4)strlen((char *)del_stmt), + (ub4)OCI_NTV_SYNTAX, (ub4)stmt_mode)); + + checkerr(errhp, OCIBindByName(stmt3p, &bnd5p, errhp, (text *)colname5, + (sb4)strlen((char*)colname5), + (dvoid *)&in_id, (sb4)sizeof(sword), sqltype1, (dvoid *)&ind, + (ub2 *) 0, (ub2 *) 0, (ub4) 0,(ub4 *)0,bind_mode)); + + checkerr(errhp, OCIStmtExecute(svchp,stmt3p,errhp,(ub4)1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, (ub4)OCI_DEFAULT)); + + /*free(char1_outp); + free(char2_outp); + free(char3_outp); */ + OCIHandleFree((dvoid *) stmt1p, (ub4) OCI_HTYPE_STMT); + OCIHandleFree((dvoid *) stmt2p, (ub4) OCI_HTYPE_STMT); + OCIHandleFree((dvoid *) stmt3p, (ub4) OCI_HTYPE_STMT); + free_handles(); + +} + +static void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + ub4 buflen; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + fprintf(stdout, "Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + fprintf(stdout, "Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + fprintf(stdout, "Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + fprintf(stdout, "Error - %s\n", errbuf); + break; + case OCI_INVALID_HANDLE: + fprintf(stdout, "Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + fprintf(stdout, "Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + fprintf(stdout, "Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +/* ----------------------------------------------------------------- */ +/* initialize environment, allocate handles */ +/* ----------------------------------------------------------------- */ + +sword init_env(env_mode) +ub4 env_mode; +{ + + if (OCIEnvCreate((OCIEnv **) &envhp, env_mode, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0, + (size_t) 0, (dvoid **) 0 )) + { + printf("FAILED: OCIEnvCreate()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on svchp\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on errhp\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on srvhp\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on authp\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/* ----------------------------------------------------------------- */ +/* attach to server with a given mode. */ +/* ----------------------------------------------------------------- */ + +sword attach_server(server_mode) +ub4 server_mode; +{ + + if (OCIServerAttach(srvhp, errhp, (text *) "", + (sb4) strlen(""), (ub4) server_mode)) + { + printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + printf("FAILED: OCIAttrSet() server attribute\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} +sword log_on(uid, pwd, credt, session_mode) +text *uid; +text *pwd; +ub4 credt; +ub4 session_mode; +{ + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *) uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + printf("FAILED: OCIAttrSet() userid\n"); + return OCI_ERROR; + } + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *) pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + + printf("Logging on as %s ....\n", uid); + + if (OCISessionBegin(svchp, errhp, authp, credt, session_mode)) + { + printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + printf("%s logged on.\n", uid); + + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + printf("FAILED: OCIAttrSet() session\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +sword free_handles() +{ + OCISessionEnd(svchp, errhp, authp, (ub4)OCI_DEFAULT); + OCIServerDetach( srvhp, errhp, (ub4) OCI_DEFAULT ); + OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + OCIHandleFree((dvoid *) authp, (ub4) OCI_HTYPE_SESSION); + OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + return OCI_SUCCESS; + +} + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ + + +/* end of file nchdemo1.c */ + diff --git a/nlsdemo0.sql b/nlsdemo0.sql new file mode 100644 index 0000000..403af32 --- /dev/null +++ b/nlsdemo0.sql @@ -0,0 +1,133 @@ +Rem +Rem $Header: nlsdemo0.sql 23-jul-2003.12:21:16 chli Exp $ +Rem +Rem nlsdemo0.sql +Rem +Rem Copyright (c) 2001, 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem nlsdemo0.sql - +Rem +Rem DESCRIPTION +Rem This is the first sql that must be run before run NLS demo +Rem Insert extra multibyte data for nls linguistic index test +Rem create 3 linguistic index, plustrace role and plan_table +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem tnallath 05/09/02 - bug 2368367:. +Rem huwang 02/22/01 - Merged huwang_nlsdemo +Rem huwang 02/22/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +CONNECT OE/OE + +insert into product_information(product_id) values(2728); +insert into product_information(product_id) values(2729); +insert into product_information(product_id) values(2730); +insert into product_information(product_id) values(2731); +insert into product_information(product_id) values(2732); +insert into product_information(product_id) values(2734); + +insert into product_descriptions values (2728,'D','abcd','abcd'); +insert into product_descriptions values (2729,'D','Abcd','Abcd'); +insert into product_descriptions values (2730,'D',Unistr('\00e4bcd'),'bcd'); +insert into product_descriptions values (2731,'D',Unistr('\00c4bcd'),'bcd'); + + +insert into product_descriptions values (2728 +, 'ZHS' +, UNISTR('\6db2\6676\663e\793a\5668') +, 'LED DISPLAYER' +); + +insert into product_descriptions values (2729 +, 'ZHS' +, UNISTR('\7535\89c6\673a') +, 'TV set' +); + +insert into product_descriptions values(2730 +,'ZHS' +,UNISTR('\6fc0\5149\5531\76d8') +,'Laser CD' +); + +insert into product_descriptions values(2731 +,'ZHS' +,UNISTR('\79fb\52a8\7535\8bdd') +,'Celluar phone' +); + +insert into product_descriptions values(2732 +,'ZHS' +,UNISTR('\7535\51b0\7bb1') +,'Refrigerator'); + +Commit; + + +REM Create Linguistic Index on Product_Descriptions Table's Translated_Description + +CONNECT OE/OE + +ALTER SESSION SET NLS_COMP=ANSI; + +ALTER SESSION SET QUERY_REWRITE_ENABLED=TRUE; + +rem pause Create Generic_M Index on Translated_name NVARCHAR2 Column, Please Press < Enter> to continue... + +ALTER SESSION SET NLS_SORT=GENERIC_M; + +DROP INDEX NLS_GENERIC; + +CREATE INDEX NLS_GENERIC ON product_descriptions( NLSSORT(translated_name, 'NLS_SORT=GENERIC_M')); + +rem pause Create Simplified Chinese Storke sorting Index on Translated_name NVARCHAR2 Column, Please Press to continue + +ALTER SESSION SET NLS_SORT=SCHINESE_STROKE_M; + +DROP INDEX NLS_ZHSSTROKE; + +CREATE INDEX NLS_ZHSSTROKE ON product_descriptions( NLSSORT(translated_name, 'NLS_SORT=SCHINESE_STROKE_M')); + +rem pause Create Simplified Chinese Pinyin sorting Index on Translated_name NVARCHAR2 Column, Please Press to continue + +ALTER SESSION SET NLS_SORT=SCHINESE_PINYIN_M; + +DROP INDEX NLS_ZHSPINYIN; + +CREATE INDEX NLS_ZHSPINYIN ON product_descriptions( NLSSORT(translated_name, 'NLS_SORT=SCHINESE_PINYIN_M')); + +ANALYZE TABLE Product_descriptions COMPUTE STATISTICS; + +Rem Set Autotrace On to see the execution plan + +Prompt Please Input the password for User sys + +CONNECT SYS/change_on_install AS SYSDBA + +Rem Run ?/sqlplus/admin/plustrce.sql to Create role + +@?/sqlplus/admin/plustrce.sql + +GRANT plustrace To OE; + +CONNECT OE/OE + +Rem Run ?/rdbms/admin/utlxplan.sql to Create PLAN_TABLE + +DROP TABLE PLAN_TABLE; + +@?/rdbms/admin/utlxplan.sql + diff --git a/nlsdemo1.sql b/nlsdemo1.sql new file mode 100644 index 0000000..b3046c0 --- /dev/null +++ b/nlsdemo1.sql @@ -0,0 +1,60 @@ +Rem +Rem $Header: nlsdemo1.sql 23-jul-2003.11:27:27 chli Exp $ +Rem +Rem nlsdemo1.sql +Rem +Rem Copyright (c) 2001, 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem nlsdemo1.sql - +Rem +Rem DESCRIPTION +Rem to continue +SELECT * FROM PRODUCT_DESCRIPTIONS +ORDER BY TRANSLATED_NAME; + +rem pause The following three ALTER statements change the sort setting to Generic_M linguistic sort + +ALTER SESSION SET NLS_COMP=ANSI; + +ALTER SESSION SET NLS_SORT='GENERIC_M'; + +ALTER SESSION SET QUERY_REWRITE_ENABLED=TRUE; + +rem pause Now you will see the generic_m sorting result for Translated_name NVARCHAR2 Column, Please press to continue + +SELECT * FROM PRODUCT_DESCRIPTIONS +WHERE TRANSLATED_NAME > UNISTR('\0000') +ORDER BY TRANSLATED_NAME; + + + + + diff --git a/nlsdemo2.sql b/nlsdemo2.sql new file mode 100644 index 0000000..1c2b256 --- /dev/null +++ b/nlsdemo2.sql @@ -0,0 +1,60 @@ +Rem +Rem $Header: nlsdemo2.sql 23-jul-2003.11:28:40 chli Exp $ +Rem +Rem nlsdemo2.sql +Rem +Rem Copyright (c) 2001, 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem nlsdemo2.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem chli 07/23/03 - +Rem huwang 02/22/01 - Merged huwang_nlsdemo +Rem huwang 02/22/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +REM Create Policy Function + +CONNECT OE/OE + +DROP FUNCTION secure_person; + +CREATE OR REPLACE FUNCTION secure_person ( object_schema IN VARCHAR2, object_name IN VARCHAR2) return VARCHAR2 IS +BEGIN + RETURN( 'language_id=SYS_CONTEXT(''USERENV'',''LANG'')'); +END; +/ + +SHOW ERRORS + +REM Add and Enable The Policy + +Prompt Please enter the password for User SYS + +connect sys/change_on_install as sysdba + +BEGIN + DBMS_RLS.DROP_POLICY('OE','PRODUCT_DESCRIPTIONS','NCHARFEATURE'); +END; +/ + +BEGIN + DBMS_RLS.ADD_POLICY('OE','PRODUCT_DESCRIPTIONS','NCHARFEATURE','OE','SECURE_PERSON','SELECT'); +END; +/ + diff --git a/nlsdemo3.sql b/nlsdemo3.sql new file mode 100644 index 0000000..b360d38 --- /dev/null +++ b/nlsdemo3.sql @@ -0,0 +1,68 @@ +Rem +Rem $Header: nlsdemo3.sql 23-jul-2003.11:29:13 chli Exp $ +Rem +Rem nlsdemo3.sql +Rem +Rem Copyright (c) 2001, 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem nlsdemo3.sql - +Rem +Rem DESCRIPTION +Rem Using fine gained access control to show only chinese data in 3 different sorting mode: Generic_m, stroke and Pinyin +Rem NOTES +Rem We suppose to show chinese data , please set NLS_LANG to 'Simplified Chinese_China.zhs16gbk' +Rem Before you run this sql file, please run nlsdemo2.sql so that you can see the fine gained access control demo +Rem +Rem MODIFIED (MM/DD/YY) +Rem chli 07/23/03 - +Rem huwang 02/22/01 - Merged huwang_nlsdemo +Rem huwang 02/22/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + + +REM +REM Before you run the sql file, you must run nlsdemo2.sql +REM Please don't Forget to set NLS_LANG to 'Simplified Chinese_China.zhs16gbk' +REM + +CONNECT OE/OE + +COL LANGUANE_ID FORMAT A3 +COL TRANSLATED_NAME FORMAT A20 +COL TRANSLATED_DESCRIPTION FORMAT A20 + +SET AUTOTRACE ON EXPLAIN + +ALTER SESSION SET NLS_COMP=ANSI; + +ALTER SESSION SET QUERY_REWRITE_ENABLED=TRUE; + +rem pause You will see the Generic_M sorting result for only Chinese translated name + +ALTER SESSION SET NLS_SORT=GENERIC_M; + +SELECT * FROM Product_descriptions WHERE translated_name > UNISTR('\0000') ORDER BY translated_name; + +rem pause You will see the Storke sorting result for only Chinese translated name + +ALTER SESSION SET NLS_SORT=SCHINESE_STROKE_M; + +SELECT * FROM Product_descriptions WHERE translated_name > UNISTR('\0000') ORDER BY translated_name; + +rem pause You will see the Pinyin sorting result for only Chinese translated name + +ALTER SESSION SET NLS_SORT=SCHINESE_PINYIN_M; + +SELECT * FROM Product_descriptions WHERE translated_name > UNISTR('\0000') ORDER BY translated_name; + + + diff --git a/nlsdemo4.sql b/nlsdemo4.sql new file mode 100644 index 0000000..2f0bd09 --- /dev/null +++ b/nlsdemo4.sql @@ -0,0 +1,49 @@ +Rem +Rem $Header: nlsdemo4.sql 23-jul-2003.11:29:59 chli Exp $ +Rem +Rem nlsdemo4.sql +Rem +Rem Copyright (c) 2001, 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem nlsdemo3.sql - +Rem +Rem DESCRIPTION +Rem Using fine gained access control to show only one language data which is depending on your NLS_LANG setting +Rem Say, if you set NLS_LANG to japanese_japan.ja16sjis, only japanese data is shown, if you set NLS_LANG to 'Simplified Chinese +Rem _china.zhs16cgb231280', only chinese data is shown +Rem NOTES +Rem Before you run this sql file, please run nlsdemo2.sql so that you can see the fine gained access control demo +Rem +Rem MODIFIED (MM/DD/YY) +Rem chli 07/23/03 - +Rem huwang 02/22/01 - Merged huwang_nlsdemo +Rem huwang 02/22/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + + +REM +REM Before you run the sql file, you must run nlsdemo2.sql +REM Please don't Forget to set NLS_LANG to what you want +REM + +CONNECT OE/OE + +COL LANGUANE_ID FORMAT A3 +COL TRANSLATED_NAME FORMAT A20 +COL TRANSLATED_DESCRIPTION FORMAT A20 + +SET AUTOTRACE ON EXPLAIN + +rem pause You will see only one language data + +SELECT * FROM Product_descriptions; + diff --git a/nlsdemo5.sql b/nlsdemo5.sql new file mode 100644 index 0000000..04637e8 --- /dev/null +++ b/nlsdemo5.sql @@ -0,0 +1,57 @@ +Rem +Rem $Header: nlsdemo5.sql 23-jul-2003.11:34:27 chli Exp $ +Rem +Rem nlsdemo5.sql +Rem +Rem Copyright (c) 2001, 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem nlsdemo5.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem huwang 02/22/01 - Merged huwang_nlsdemo +Rem huwang 02/22/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +REM Clean the indexes and Policy for the demo + +Prompt Please enter the password for User SYS + +connect sys/change_on_install as sysdba + +BEGIN + DBMS_RLS.DROP_POLICY('OE','PRODUCT_DESCRIPTIONS','NCHARFEATURE'); +END; +/ + +CONNECT OE/OE + +DROP FUNCTION secure_person; + +Delete from product_descriptions where language_id in ('D','ZHS') and product_id in (2728,2729,2730,2731,2732); + +Delete from product_information where product_id in (2728,2729,2730,2731,2732); + +DROP INDEX NLS_GENERIC; + +DROP INDEX NLS_ZHSSTROKE; + +DROP INDEX NLS_ZHSPINYIN; + +DROP TABLE PLAN_TABLE; + + diff --git a/o8demo.sql b/o8demo.sql new file mode 100644 index 0000000..ee1c416 --- /dev/null +++ b/o8demo.sql @@ -0,0 +1,317 @@ +rem +rem $Header: o8demo.sql 30-jan-2003.13:53:32 hyeh Exp $ +rem +rem o8demo.sql +rem +rem Copyright (c) 1996, 2003, Oracle Corporation. All rights reserved. +rem +rem NAME +rem o8demo.sql - Oracle8 demo +rem +rem DESCRIPTION +rem This demo features Oracle8's object extensions, such as, abstract +rem data types (ADTs) and methods. +rem +rem NOTES +rem Schema - +rem A standalone instance of the typed table Orders contains REFs to +rem instances of Companies and SalesReps., and an embedded instance of an +rem order Status. An Order also contains two methods, "totalCost" and +rem "statusSummary". +rem +rem MODIFIED (MM/DD/YY) +rem hyeh 01/30/03 - add ORDER BY to all select +rem hyeh 08/10/99 - use sqlplus syntax +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem yaggarwa 08/06/98 - Add select statements +rem mchien 01/22/98 - name resolution +rem cchau 08/18/97 - enable dictionary protection +rem mchien 05/29/97 - fix type syntax +rem mchien 07/16/96 - Created (adopted from kschultz & dherkime) +rem + +REMARK >>>> Set System Variables For Current SQLPlus Session <<<< +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET PAGESIZE 24 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET DEFINE '^' + +set echo on +connect system/manager + +grant connect,resource, unlimited tablespace to demo8 identified by demo8; +connect demo8/demo8 + +create or replace type product_t AS OBJECT ( + productId number, + productName varchar2(64), + cost number(9,2)); +/ + +create table products of product_t; + +create or replace type salesrep_t AS OBJECT ( + repId number, + repName varchar2(64)); +/ + +create table salesreps of salesrep_t; + +create or replace type company_t AS OBJECT ( + companyId number, + companyName varchar2(64)); +/ + +create table companies of company_t; + +CREATE TABLE tempTot ( + total number, orderID number); + +create table tempResult (result number); + +create table tempStat (status varchar2(64)); + +create or replace type status_t AS OBJECT ( + status varchar2(16), + statusDate date, + comments varchar2(32)); +/ + +create OR REPLACE type order_t AS OBJECT ( + orderId number, + orderDate date, + salesRep ref salesrep_t, + company ref company_t, + status status_t, + MEMBER FUNCTION totalCost RETURN NUMBER, + MEMBER FUNCTION statusSummary RETURN VARCHAR2 + ); +/ + +create table orders of order_t; + +CREATE OR REPLACE TYPE BODY Order_t AS + MEMBER FUNCTION totalCost RETURN NUMBER IS + tot NUMBER; + BEGIN + SELECT total INTO tot + FROM tempTot + WHERE tempTot.orderID = SELF.orderID; + RETURN tot; + END; + MEMBER FUNCTION statusSummary RETURN VARCHAR2 IS + st VARCHAR2(64); + BEGIN + SELECT status INTO st + FROM tempStat; + RETURN st; + END; +END; +/ +show errors +/ + + +create or replace type item_t AS OBJECT ( + itemId number, + quantity number, + product REF product_t, + orderRef ref order_t); +/ + +create table items of item_t; + +insert into products values (101,'ISDN Phone',50.00); +insert into products values (201,'ISDN Switch',5000.00); +insert into products values (301,'100 Yd. Cable',25.00); +insert into products values (401,'Installation Guide',29.95); + +select * from products order by productId; + +insert into salesReps values (16473,'Karl J. Schultz'); +insert into salesReps values (10000,'Don J. Herkimer'); +insert into salesReps values (20000,'Robin A. Wada'); + +select * from salesReps order by repId; + +insert into companies values (1111, 'ABC Graphics, Inc'); +insert into companies values (2222, 'First National Bank'); +insert into companies values (3333, 'United Carbonation, Ltd'); + +select * from companies order by companyId; + +insert into orders values(11,sysdate,NULL,NULL, + status_t('Shipped',TO_DATE('01-JUN-96'),'UPS Ground')); +insert into orders values(12,sysdate,NULL,NULL, + status_t('Pending',TO_DATE('02-JUN-96'),'BO ISDN Switch')); +insert into orders values(13,sysdate,NULL,NULL, + status_t('Shipped',TO_DATE('03-JUN-96'),'UPS Ground')); +insert into orders values(21,sysdate,NULL,NULL, + status_t('On Hold',TO_DATE('04-JUN-96'),'Waiting for PO')); +insert into orders values(22,sysdate,NULL,NULL, + status_t('Pending',TO_DATE('05-JUN-96'),'BO Cable')); +insert into orders values(23,sysdate,NULL,NULL, + status_t('Shipped',TO_DATE('06-JUN-96'),'UPS Ground')); +insert into orders values(31,sysdate,NULL,NULL, + status_t('Shipped',TO_DATE('07-JUN-96'),'UPS Ground')); +insert into orders values(32,sysdate,NULL,NULL, + status_t('Shipped',TO_DATE('08-JUN-96'),'UPS Ground')); +insert into orders values(33,sysdate,NULL,NULL, + status_t('On Hold',TO_DATE('09-JUN-96'),'Waiting for PO')); + +select o.orderId, o.orderDate, + o.status.status, o.status.statusDate, o.status.comments + from orders o order by orderId; + +update orders + set salesrep = (select ref(s) from salesreps s where repId = 16473) + where orderId between 10 and 20; + +update orders + set salesrep = (select ref(s) from salesreps s where repId = 20000) + where orderId between 20 and 30; + +update orders + set salesrep = (select ref(s) from salesreps s where repId = 10000) + where orderId between 30 and 40; + +update orders + set company = (select ref(c) from companies c where companyId = 1111) + where orderId in (11,21,31); + +update orders + set company = (select ref(c) from companies c where companyId = 2222) + where orderId in (12,22,32); + +update orders + set company = (select ref(c) from companies c where companyId = 3333) + where orderId in (13,23,33); + +select o.orderId, o.orderDate, + o.status.status, o.status.statusDate, o.status.comments + from orders o order by orderId; + +select o.orderId, o.orderDate, o.status.status, + o.status.statusDate, o.status.comments, + o.salesRep.repId, o.salesRep.repName, + o.company.companyId, o.company.companyName + from orders o order by orderId; + + +insert into items values(1,100,NULL,NULL); +insert into items values(2,1,NULL,NULL); +insert into items values(3,2,NULL,NULL); +insert into items values(4,3,NULL,NULL); + +insert into items values(5,200,NULL,NULL); +insert into iteMs values(6,2,NULL,NULL); +insert into items values(7,4,NULL,NULL); + +update items + set product = (select ref(p) from products p where productId = 101) + where itemId = 1; + +update items + set product = (select ref(p) from products p where productId = 201) + where itemId = 2; + +update items + set product = (select ref(p) from products p where productId = 301) + where itemId = 3; + +update items + set product = (select ref(p) from products p where productId = 401) + where itemId = 4; + +update items + set product = (select ref(p) from products p where productId = 101) + where itemId = 5; + +update items + set product = (select ref(p) from products p where productId = 201) + where itemId = 6; + +update items + set product = (select ref(p) from products p where productId = 301) + where itemId = 7; + +update items + set orderRef = (select ref(o) from orders o where orderId = 11) + where itemId = 1; + +update items + set orderRef = (select ref(o) from orders o where orderId = 11) + where itemId = 2; + +update items + set orderRef = (select ref(o) from orders o where orderId = 11) + where itemId = 3; + +update items + set orderRef = (select ref(o) from orders o where orderId = 11) + where itemId = 4; + +update items + set orderRef = (select ref(o) from orders o where orderId = 12) + where itemId = 5; + +update items + set orderRef = (select ref(o) from orders o where orderId = 12) + where itemId = 6; + +update items + set orderRef = (select ref(o) from orders o where orderId = 12) + where itemId = 7; + +select i.itemId, i.quantity, + i.product.productId, i.product.productName, i.product.cost, + i.orderRef.orderId, i.orderRef.orderDate, + i.orderRef.status.status, i.orderRef.status.comments, + i.orderRef.salesRep.repId, i.orderRef.salesRep.repName, + i.orderRef.company.companyId, i.orderRef.company.companyName + from items i order by itemId; + +CREATE OR REPLACE PACKAGE utils AS +FUNCTION computeTotalForOrder(ordID NUMBER) RETURN NUMBER; +FUNCTION getStatusForOrder(ordID NUMBER) RETURN VARCHAR2; +END; +/ + +CREATE OR REPLACE PACKAGE BODY utils AS +FUNCTION computeTotalForOrder(ordID NUMBER) RETURN NUMBER IS + anOrder order_t; +BEGIN + anOrder.OrderID := ordID; + RETURN anOrder.totalCost; +End; +FUNCTION getStatusForOrder(ordID NUMBER) RETURN VARCHAR2 IS + anOrder order_t; +BEGIN + anOrder.OrderID := ordID; + RETURN anOrder.statusSummary; +End; +END; +/ +show errors + +commit; + +-- Three-way join required in Oracle7 to do a simple select in Oracle8 +--. +-- SELECT OrderID, SalesReps.repName, Company.companyName, +-- FROM Orders o, SalesReps reps, Companies c, OrderStatuses st +-- WHERE o.ID = 11 AND +-- o.ID = st.OrderID AND +-- o.RepID = reps.ID AND +-- o.CompanyID = c.ID; + +SELECT orderId, o.salesRep.repName, o.company.companyName, o.status.status + FROM Orders o + WHERE o.orderID = 11 order by orderId; + +connect sys/knl_test7 as sysdba; +drop user demo8 cascade; +set echo off diff --git a/o8idemo.sql b/o8idemo.sql new file mode 100644 index 0000000..237ad90 --- /dev/null +++ b/o8idemo.sql @@ -0,0 +1,988 @@ +rem +rem $Header: o8idemo.sql 31-oct-2006.13:40:56 ytsai Exp $ +rem +rem o8idemo.sql +rem +rem Copyright (c) 1998, 2006, Oracle. All rights reserved. +rem +rem NAME +rem o8idemo.sql - Purchase Order example and DDL sample on object view +rem +rem DESCRIPTION +rem This demonstrate the Purchase Order example described in manual +rem Application Developer's Guide +rem and some extra examples on object view DDL +rem +rem NOTES +rem In order to run this sample, the database must be started up with +rem option compatible=8.1.0.0.0 (or a higher compatible value) +rem +rem MODIFIED (MM/DD/YY) +rem ytsai 10/31/06 - fix connect +rem hyeh 01/30/03 - add ORDER BY to all SELECT +rem mchien 11/04/99 - 8.1.6 additions from KOSINSKI +rem hyeh 08/11/99 - set session format +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem hyeh 01/06/99 - use compressed nested iot +rem hyeh 12/22/98 - do not use compressed index - bug 785326, 785403 +rem mkrishna 10/22/98 - add FORCE option for MAKE_REF +rem mchien 10/21/98 - do not use compressed index for now - bug 740405 +rem yaggarwa 10/13/98 - +rem yaggarwa 10/13/98 - Created +rem + +REMARK >>>> Set System Variables For Current SQLPlus Session <<<< +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET PAGESIZE 24 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET DEFINE '^' + +SET ECHO ON +CONNECT system/manager; +DROP USER po CASCADE +/ +GRANT RESOURCE,DBA TO po IDENTIFIED BY po +/ +CONNECT po/po + +CREATE TABLE Customer_reltab ( + Custno NUMBER, -- Customer NUMBER + Custname VARCHAR2(200), -- Customer name + Street VARCHAR2(200), -- Customer Street + City VARCHAR2(200), -- Customer City + State CHAR(2), + Zip VARCHAR2(20), -- Customer Zip + Phone1 VARCHAR2(20), + Phone2 VARCHAR2(20), + Phone3 VARCHAR2(20), + PRIMARY KEY (Custno) + ) +/ +CREATE TABLE PurchaseOrder_reltab ( + PONo NUMBER, -- purchase order no + Custno NUMBER references Customer_reltab , + -- foreign KEY referencing customer + OrderDate DATE, -- Date OF order + ShipDate DATE, -- Date to be shipped + ToStreet VARCHAR2(200), -- shipto Address + ToCity VARCHAR2(200), + ToState CHAR(2), + ToZip VARCHAR2(20), + PRIMARY KEY(PONo) + ) +/ +CREATE TABLE Stock_reltab ( + StockNo NUMBER PRIMARY KEY, + Price NUMBER, + TaxRate NUMBER + ) +/ +CREATE TABLE LineItems_reltab ( + LineItemNo NUMBER, + PONo NUMBER references PurchaseOrder_reltab, + StockNo NUMBER references Stock_reltab, + Quantity NUMBER, + Discount NUMBER, + PRIMARY KEY (PONo,LineItemNo) + ); + + +-- 2. Values Inserted + +INSERT INTO Customer_reltab + VALUES(1,'Jean Nance','2, Avocet Drive','Redwood Shores','CA','95054', + '801-010-0090',NULL,NULL); +INSERT INTO Customer_reltab + VALUES(2,'John Nike','323, College Drive','Edison','NJ','08820', + '901-090-0000','908-201-1002',NULL); +INSERT INTO PurchaseOrder_reltab + VALUES(1001,1,SYSDATE,'10-MAY-1997',NULL,NULL,NULL,NULL); +INSERT INTO PurchaseOrder_reltab + VALUES(2001,2,SYSDATE,'20-MAY-1997','55, Madison Ave','Madison','WI', + '53715'); + +INSERT INTO Stock_reltab VALUES(1004,6750.00,2); +INSERT INTO Stock_reltab VALUES(1011,4500.23,2); +INSERT INTO Stock_reltab VALUES(1534,2234.00,2); +INSERT INTO Stock_reltab VALUES(1535,3456.23,2); + +INSERT INTO LineItems_reltab VALUES(01,1001,1534,12,0) +/ +INSERT INTO LineItems_reltab VALUES(02,1001,1535,10,10) +/ +INSERT INTO LineItems_reltab VALUES(10,2001,1004,1,0) +/ +INSERT INTO LineItems_reltab VALUES(11,2001,1011,2,1) +/ +-- 3. Selection :- + +-- List Customer and Lineitems FOR a given Purchase Order + +SELECT c.Custno, c.Custname, c.Street, c.City, c.State, c.Zip, c.Phone1, + c.Phone2, c.Phone3, + p.PONo, p.OrderDate, + l.StockNo, l.LineItemNo, l.Quantity, l.Discount +FROM Customer_reltab c, PurchaseOrder_reltab p, LineItems_reltab l +WHERE c.Custno = p.Custno AND p.PONo = l.PONo +AND p.PONo = 1001 ORDER BY c.Custno, l.LineItemNo; + +-- List the Total value OF Purchase Orders + +SELECT p.PONo, SUM(s.Price * l.Quantity) +FROM PurchaseOrder_reltab p, LineItems_reltab l, Stock_reltab s +WHERE p.PONo = l.PONo AND l.StockNo = s.StockNo +GROUP BY p.PONo ORDER BY p.PONo; + +-- List all the Purchase Order information and the Line Item information +-- FOR those LineItems_tab that use the stock WITH StockNo 1004 + +SELECT p.PONo, p.Custno, + l.StockNo, l.LineItemNo, l.Quantity, l.Discount +FROM PurchaseOrder_reltab p, LineItems_reltab l +WHERE p.PONo = l.PONo (+) AND + l.StockNo = 1004 +ORDER BY p.PONo, l.LineItemNo; + + +-- ======================================================================== +-- THE OBJECT-RELATIONAL SYSTEM (Oracle 8.0.3) + + +CREATE TYPE StockItem_objtyp +/ + +CREATE TYPE LineItem_objtyp +/ + +CREATE TYPE PurchaseOrder_objtyp +/ + +CREATE TYPE PhoneList_vartyp AS VARRAY(10) OF VARCHAR2(20) +/ + +CREATE TYPE Address_objtyp AS OBJECT ( + Street VARCHAR2(200), + City VARCHAR2(200), + State CHAR(2), + Zip VARCHAR2(20), + + MEMBER PROCEDURE + display + ) +/ + + +CREATE OR REPLACE TYPE Customer_objtyp AS OBJECT ( + Custno NUMBER, + Custname VARCHAR2(200), + Address_obj Address_objtyp, + PhoneList_var PhoneList_vartyp, + + ORDER MEMBER FUNCTION + compareCustOrders(x IN Customer_objtyp) RETURN INTEGER, + + MEMBER PROCEDURE + display + ) +/ + +CREATE TYPE LineItem_objtyp AS OBJECT ( + LineItemNo NUMBER, + Stock_ref REF StockItem_objtyp, + Quantity NUMBER, + Discount NUMBER, + + MEMBER PROCEDURE + display + ) +/ +CREATE TYPE LineItemList_ntabtyp AS TABLE OF LineItem_objtyp +/ +CREATE TYPE PurchaseOrder_objtyp AS OBJECT ( + PONo NUMBER, + Cust_ref REF Customer_objtyp, + OrderDate DATE, + ShipDate DATE, + LineItemList_ntab LineItemList_ntabtyp, + ShipToAddr_obj Address_objtyp, + + MAP MEMBER FUNCTION + getPONo RETURN NUMBER, + + MEMBER FUNCTION + sumLineItems RETURN NUMBER, + + MEMBER PROCEDURE + purchase_item (item NUMBER, + qty NUMBER, + discount NUMBER), + + MEMBER PROCEDURE + update_item (lineno NUMBER, + item NUMBER, + qty NUMBER, + discount NUMBER), + + MEMBER PROCEDURE + display + ) +/ + +CREATE TYPE StockItem_objtyp AS OBJECT ( + StockNo NUMBER, + Price NUMBER, + TaxRate NUMBER + ) +/ + +-- If no relational data exist, and tables need to be created, then create the + +-- following object tables + +CREATE TABLE Customer_objtab OF Customer_objtyp (Custno PRIMARY KEY) + OBJECT ID PRIMARY KEY +/ + +CREATE TABLE Stock_objtab OF StockItem_objtyp (StockNo PRIMARY KEY) + OBJECT ID PRIMARY KEY +/ + +CREATE TABLE PurchaseOrder_objtab OF PurchaseOrder_objtyp + (PRIMARY KEY (PONo), + FOREIGN KEY (Cust_ref) REFERENCES Customer_objtab) + OBJECT ID PRIMARY KEY + NESTED TABLE LineItemList_ntab STORE AS PoLine_ntab( + (PRIMARY KEY(NESTED_TABLE_ID, LineItemNo)) + ORGANIZATION INDEX COMPRESS + ) RETURN AS LOCATOR +/ + +ALTER TABLE PoLine_ntab ADD (SCOPE FOR (Stock_ref) IS stock_objtab); + +-- Following statement creates an INDEX on the internal column +-- "NESTED_TABLE_ID" OF a storage TABLE. +CREATE INDEX Po_nidx on PoLine_ntab (NESTED_TABLE_ID) +/ +-- Insertion OF VALUES -- + +INSERT INTO Stock_objtab VALUES(StockItem_objtyp(1004,6750.00,2)); +INSERT INTO Stock_objtab VALUES(StockItem_objtyp(1011,4500.23,2)); +INSERT INTO Stock_objtab VALUES(StockItem_objtyp(1534,2234.00,2)); +INSERT INTO Stock_objtab VALUES(1535,3456.23,2) +/ +INSERT INTO Customer_objtab + VALUES(1,'Jean Nance', + Address_objtyp('2 Avocet Drive','Redwood Shores','CA','95054'), + PhoneList_vartyp('415-904-0940','408-506-2020')); +INSERT INTO Customer_objtab + VALUES(2,'John Nike', + Address_objtyp('323 College Drive','Edison','NJ','08820'), + PhoneList_vartyp('908-904-0940')); + +INSERT INTO PurchaseOrder_objtab + SELECT 1001,REF(C),SYSDATE,'10-MAY-1997',LineItemList_ntabtyp(),NULL + FROM Customer_objtab C + WHERE C.Custno = 1; + +INSERT INTO PurchaseOrder_objtab + SELECT 2001,REF(C),SYSDATE,'20-MAY-1997', + CAST(MULTISET(SELECT 01, + REF(S), + 12, + 0 + FROM Stock_objtab S + WHERE S.StockNo = 1534) AS LineItemList_ntabtyp), + Address_objtyp('55, Madison Ave','Madison','WI','53715') + FROM Customer_objtab C + WHERE C.Custno = 2; + +INSERT INTO TABLE(SELECT P.LineItemList_ntab + FROM PurchaseOrder_objtab P WHERE P.PONo = 1001) + SELECT 01,REF(S),10,10 FROM Stock_objtab S WHERE S.StockNo = 1535; + +INSERT INTO TABLE(SELECT P.LineItemList_ntab + FROM PurchaseOrder_objtab P WHERE P.PONo = 2001) + SELECT 10,REF(S), 1,0 FROM Stock_objtab S WHERE S.StockNo = 1004; + +INSERT INTO TABLE(SELECT P.LineItemList_ntab + FROM PurchaseOrder_objtab P WHERE P.PONo = 2001 ) + VALUES(LineItem_objtyp( 11,NULL,2,1)) +/ +UPDATE TABLE(SELECT P.LineItemList_ntab + FROM PurchaseOrder_objtab P WHERE P.PONo = 2001) plist + SET plist.Stock_ref = (SELECT REF(S) + FROM Stock_objtab S WHERE S.StockNo = 1011) + WHERE plist.LineItemNo = 11 +/ + + -- Functional definitions +CREATE OR REPLACE TYPE BODY PurchaseOrder_objtyp AS + MEMBER FUNCTION sumLineItems RETURN NUMBER IS + i INTEGER; + StockVal StockItem_objtyp; + LineItem LineItem_objtyp; + Total NUMBER := 0; + + BEGIN + IF (UTL_COLL.IS_LOCATOR(LineItemList_ntab)) + THEN + SELECT SUM(L.Quantity * L.Stock_ref.Price) INTO Total + FROM TABLE(CAST(LineItemList_ntab AS LineItemList_ntabtyp)) L; + ELSE + FOR i IN 1..SELF.LineItemList_ntab.COUNT LOOP + LineItem := SELF.LineItemList_ntab(i); + UTL_REF.SELECT_OBJECT(LineItem.Stock_ref, StockVal); + Total := Total + LineItem.Quantity * StockVal.Price * + (1 - LineItem.Discount/100); + END LOOP; + END IF; + RETURN Total; + END; + + MAP MEMBER FUNCTION getPONo RETURN NUMBER is + BEGIN + RETURN PONo; + END; + + MEMBER PROCEDURE purchase_item (item NUMBER, + qty NUMBER, + discount NUMBER) IS + StockRef REF StockItem_objtyp; + BEGIN + SELECT REF(s) INTO StockRef + FROM Stock_objtab s + WHERE s.StockNo = item; + + LineItemList_ntab.EXTEND; + LineItemList_ntab(LineItemList_ntab.LAST) := + lineitem_objtyp(LineItemList_ntab.LAST, StockRef, qty, discount); + END; + + MEMBER PROCEDURE update_item (lineno NUMBER, + item NUMBER, + qty NUMBER, + discount NUMBER) IS + StockRef REF StockItem_objtyp; + BEGIN + SELECT REF(s) INTO StockRef + FROM Stock_objtab s + WHERE s.StockNo = item; + + LineItemList_ntab(lineno).Stock_ref := StockRef; + LineItemList_ntab(lineno).Quantity := qty; + LineItemList_ntab(lineno).Discount := discount; + END; + + MEMBER PROCEDURE display IS + cust Customer_objtyp; + BEGIN + dbms_output.put_line('Purchase Order ' || pono); + dbms_output.put_line(' '); + SELECT DEREF(Cust_ref) INTO cust FROM DUAL; + cust.display; + IF (ShipToAddr_obj IS NOT NULL) THEN + dbms_output.put_line('Shipping address:'); + ShipToAddr_obj.display; + END IF; + dbms_output.put_line(' '); + dbms_output.put_line('Order date: ' || OrderDate); + dbms_output.put_line('Ship date: ' || ShipDate); + dbms_output.put_line(' '); + dbms_output.put_line('Line Item Quantity Price ' || + 'Discount Extension'); + FOR i IN 1 .. LineItemList_ntab.COUNT LOOP + LineItemList_ntab(i).display; + END LOOP; + dbms_output.put_line(' '); + dbms_output.put_line('Total cost: ' || + to_char(sumLineItems, '$999,999,990.99')); + END; +END; +/ + +CREATE OR REPLACE TYPE BODY Customer_objtyp AS + ORDER MEMBER FUNCTION compareCustOrders (x IN Customer_objtyp) + RETURN INTEGER IS + BEGIN + RETURN Custno - x.Custno; + END; + + MEMBER PROCEDURE display IS + BEGIN + dbms_output.put_line(CustName); + Address_obj.display; + FOR i IN 1 .. PhoneList_var.COUNT LOOP + dbms_output.put_line(PhoneList_var(i)); + END LOOP; + END; +END; +/ + +CREATE OR REPLACE TYPE BODY Address_objtyp AS + MEMBER PROCEDURE display IS + BEGIN + dbms_output.put_line(Street); + dbms_output.put_line(City || ', ' || State || ' ' || Zip); + END; +END; +/ + +CREATE OR REPLACE TYPE BODY LineItem_objtyp AS + MEMBER PROCEDURE display IS + item StockItem_objtyp; + ext NUMBER; + textline VARCHAR2(255); + BEGIN + SELECT DEREF(Stock_Ref) INTO item FROM DUAL; + ext := Quantity * item.Price * (1 - Discount/100); + + textline := to_char(LineItemNo, '999') || ' ' || + to_char(item.StockNo, '0999') || ' ' || + to_char(Quantity, '9999999') || ' ' || + to_char(item.Price, '$99,999.99') || ' ' || + to_char(Discount, '90.99') || '% ' || + to_char(ext, '$999,999.99'); + dbms_output.put_line(textline); + END; +END; +/ + +-- Select the line item list and the Custname FOR each purchase order +SELECT DEREF(p.Cust_ref) CUSTOMER_INFO, + p.ShipToAddr_obj DESTINATION, + p.PONo PURCHASE_ORDER_NUMBER, + p.OrderDate ORDER_DATE, + CURSOR(SELECT LineItemNo, + Quantity, Discount + FROM TABLE(p.LineItemList_ntab) li + ORDER BY LineItemNo) +FROM PurchaseOrder_objtab p +WHERE p.PONo = 1001 +/ + +-- Select the line item list and the Custname FOR each purchase order. +-- Please note this is the same query as above but unnesting feature +-- of Oracle8i has been used using TABLE() operator. +SELECT DEREF(p.Cust_ref) CUSTOMER_INFO, + p.ShipToAddr_obj DESTINATION, + p.PONo PURCHASE_ORDER_NUMBER, + p.OrderDate ORDER_DATE, li.LineItemNo, li.Quantity, li.Discount +FROM PurchaseOrder_objtab p, TABLE(p.LineItemList_ntab) li +WHERE p.PONo = 1001 +ORDER BY p.PONo, li.LineItemNo +/ + +-- Select the Total value FOR each purchse_order +SELECT p.PONo PURCHASE_ORDER_NUMBER, + p.sumLineItems() SUM_LINE_ITEMS +FROM PurchaseOrder_objtab p +ORDER BY p.PONo +/ + +-- Select the line items and the purchase numbers FOR all those poUs having +-- a StockNo 1535 + +SELECT po.PONo PURCHASE_ORDER_NUMBER, + po.Cust_ref.Custno CUSTOMER_NUMBER, + li.LineItemNo LINE_ITEM_NO, + li.Stock_ref.StockNo STOCK_NO, + li.Quantity QUANTITY, + li.Discount DISCOUNT +FROM PurchaseOrder_objtab po, TABLE(po.LineItemList_ntab) li +WHERE li.Stock_ref.StockNo = 1535 +ORDER BY po.PONo, li.LineItemNo +/ + +-- Example of how Varray column can be unnested/flattened in +-- Oracle8i using TABLE() operator. +SELECT p1.custno, p2.* +FROM Customer_objtab p1, TABLE( p1.PhoneList_var)p2 +ORDER BY 1, 2 +/ + +-- USING PL/SQL TO CALL TYPE METHODS -- + +-- Required for DBMS_OUTPUT +SET SERVEROUTPUT ON FORMAT WRAPPED + +-- Display all customer info + +DECLARE + cref REF Customer_objtyp; + cust Customer_objtyp; + CURSOR cr IS SELECT REF(c) FROM Customer_objtab c ORDER BY Custname; +BEGIN + OPEN cr; + LOOP + FETCH cr INTO cref; + EXIT WHEN cr%NOTFOUND; + UTL_REF.SELECT_OBJECT(cref, cust); + cust.display; + dbms_output.put_line(' '); + END LOOP; + CLOSE cr; +END; +/ + +-- Display purchase order + +CREATE OR REPLACE PROCEDURE display_order (ponum NUMBER) IS + poref REF PurchaseOrder_objtyp; + po PurchaseOrder_objtyp; +BEGIN + SELECT REF(p) INTO poref FROM PurchaseOrder_objtab p WHERE p.pono = ponum; + UTL_REF.SELECT_OBJECT(poref, po); + po.display; +END; +/ + +BEGIN + display_order(1001); +END; +/ + +-- Add to purchase order +-- This procedure uses the LOCK_OBJECT and UPDATE_OBJECT procedures in +-- package UTL_REF to modify the nested table of line items + +CREATE OR REPLACE PROCEDURE add_item (ponum NUMBER, stockno NUMBER, + qty NUMBER, discount NUMBER) IS + poref REF PurchaseOrder_objtyp; + po PurchaseOrder_objtyp; +BEGIN + SELECT REF(p) INTO poref + FROM PurchaseOrder_objtab p + WHERE p.pono = ponum; + + UTL_REF.LOCK_OBJECT(poref, po); + po.purchase_item(stockno, qty, discount); + UTL_REF.UPDATE_OBJECT(poref, po); +END; +/ + +BEGIN + add_item(1001, 1534, 6, 20); + display_order(1001); +END; +/ + +-- Change a line item +-- This procedure updates the line items list using SQL instead of UTL_REF. + +CREATE OR REPLACE PROCEDURE change_item (ponum NUMBER, lineno NUMBER, + stockno NUMBER, qty NUMBER, + discount NUMBER) IS + poref REF PurchaseOrder_objtyp; + po PurchaseOrder_objtyp; +BEGIN + SELECT REF(p) INTO poref + FROM PurchaseOrder_objtab p + WHERE p.pono = ponum + FOR UPDATE OF p.LineItemList_ntab; + + UTL_REF.SELECT_OBJECT(poref, po); + po.update_item(lineno, stockno, qty, discount); + + UPDATE PurchaseOrder_objtab p + SET p.LineItemList_ntab = po.LineItemList_ntab + WHERE p.pono = ponum; +END; +/ + +BEGIN + change_item(1001, 1, 1011, 7, 35); + display_order(1001); +END; +/ + +-- Object Views +-- If relational schema exists WITH relational tables containing the +-- purchase order, lineitem and customer data, then objects may be +-- materialized from the relational data WITH the help of object views. + +CREATE OR REPLACE VIEW Customer_objview OF Customer_objtyp + WITH OBJECT OID(Custno) + AS SELECT C.Custno, + C.Custname, + Address_objtyp(C.Street,C.City,C.State,C.Zip), + PhoneList_vartyp(Phone1,Phone2,Phone3) + FROM Customer_reltab C +/ +CREATE OR REPLACE VIEW Stock_objview OF StockItem_objtyp + WITH OBJECT OID(StockNo) + AS SELECT * + FROM Stock_reltab +/ +CREATE OR REPLACE VIEW PurchaseOrder_objview OF PurchaseOrder_objtyp + WITH OBJECT OID (PONo) + AS SELECT P.PONo, + MAKE_REF(Customer_objview,P.Custno), + P.OrderDate, + P.ShipDate, + CAST( + MULTISET(SELECT LineItem_objtyp(L.LineItemNo, + MAKE_REF(Stock_objview,L.StockNo), + L.Quantity, + L.Discount) + FROM LineItems_reltab L + WHERE L.PONo= P.PONo) + AS LineItemList_ntabtyp), + Address_objtyp(P.ToStreet,P.ToCity,P.ToState,P.ToZip) + FROM PurchaseOrder_reltab P +/ +------- +-- Since OBJECT views queries are complex making them inherently non-updatable, +-- Instead-OF triggers may be specified FOR them to make them updatable. +-- For example, the following creates an INSTEAD-OF TRIGGER on the +-- PurchaseOrder_tab VIEW +-- which encapsulates the semantics of inserting into that view. +CREATE OR REPLACE TRIGGER POView_instdinserttr + INSTEAD OF INSERT on PurchaseOrder_objview +DECLARE + LineItems_ntab LineItemList_ntabtyp; + i INTEGER; + CustVar_obj Customer_objtyp; + StockVar_obj StockItem_objtyp; + StockVarTemp_ref REF StockItem_objtyp; + +BEGIN + LineItems_ntab := :new.LineItemList_ntab; + UTL_REF.SELECT_OBJECT(:new.Cust_ref, CustVar_obj); + INSERT INTO PurchaseOrder_reltab + VALUES(:new.PONo,CustVar_obj.Custno,:new.OrderDate,:new.ShipDate, + :new.ShipToAddr_obj.Street,:new.ShipToAddr_obj.City, + :new.ShipToAddr_obj.State,:new.ShipToAddr_obj.Zip) ; + + FOR i in 1..LineItems_ntab.count LOOP + UTL_REF.SELECT_OBJECT(LineItems_ntab(i).Stock_ref, StockVar_obj); + INSERT INTO LineItems_reltab + VALUES(LineItems_ntab(i).LineItemNo,:new.PONo,StockVar_obj.StockNo, + LineItems_ntab(i).Quantity,LineItems_ntab(i).Discount); + END LOOP; +END; +/ + +CREATE OR REPLACE TRIGGER POLineItems_instdinsertr + INSTEAD OF INSERT ON NESTED TABLE LineItemList_ntab OF PurchaseOrder_objview +DECLARE + StockVar StockItem_objtyp; +BEGIN + UTL_REF.SELECT_OBJECT(:NEW.Stock_ref, StockVar); + INSERT INTO LineItems_reltab + VALUES (:NEW.LineItemNo, :PARENT.PONo, StockVar.StockNo, :NEW.Quantity, + :NEW.Discount); +END; +/ +CREATE OR REPLACE TRIGGER POLineItems_instddeltr + INSTEAD OF DELETE ON NESTED TABLE LineItemList_ntab OF PurchaseOrder_objview +BEGIN + DELETE FROM LineItems_reltab + WHERE LineItemNo = :OLD.LineItemNo AND PONo = :PARENT.PONo; +END; +/ + + +CREATE OR REPLACE TRIGGER CustView_instdinserttr + INSTEAD OF INSERT on Customer_objview +DECLARE + Phones_var PhoneList_vartyp; + TPhone1 Customer_reltab.Phone1%TYPE := NULL; + TPhone2 Customer_reltab.Phone2%TYPE := NULL; + TPhone3 Customer_reltab.Phone3%TYPE := NULL; +BEGIN + Phones_var := :new.PhoneList_var; + IF Phones_var.COUNT > 2 then + TPhone3 := Phones_var(3); + END IF; + IF Phones_var.COUNT > 1 then + TPhone2 := Phones_var(2); + END IF; + IF Phones_var.COUNT > 0 then + TPhone1 := Phones_var(1); + END IF; + INSERT INTO Customer_reltab + VALUES(:new.Custno,:new.Custname,:new.Address_obj.Street, + :new.Address_obj.City,:new.Address_obj.State, + :new.Address_obj.Zip, + TPhone1,TPhone2,TPhone3); +END; +/ + +CREATE OR REPLACE TRIGGER StockView_instdinsertr + INSTEAD OF INSERT on Stock_objview +BEGIN + INSERT INTO Stock_reltab + VALUES(:new.StockNo,:new.Price,:new.TaxRate); +END; +/ + +INSERT INTO Customer_objview + VALUES (13,'Ellan White', + Address_objtyp('25, I Street','memphis','TN','05456'), + PhoneList_vartyp('901-000-0000')); +COMMIT +/ + +INSERT INTO PurchaseOrder_objview + SELECT 3001, REF(c),SYSDATE,SYSDATE, + CAST(MULTISET(SELECT LineItem_objtyp(41, REF(S),20,1) + FROM Stock_objview S WHERE S.StockNo = 1535) + AS LineItemList_ntabtyp), + Address_objtyp('22 Nothingame Ave','Cockstown','AZ','44045') + FROM Customer_objview c + WHERE c.Custno = 1 +/ + +DELETE FROM TABLE(SELECT p.LineItemList_ntab + FROM PurchaseOrder_objview p + WHERE p.PONo = 3001) L +WHERE L.LineItemNo = 41 +/ +INSERT INTO TABLE(SELECT p.LineItemList_ntab + FROM PurchaseOrder_objview p + WHERE p.PONo = 3001) + SELECT LineItem_objtyp(41, REF(S),20,1) + FROM Stock_objview S WHERE S.StockNo = 1535 +/ + +SELECT DEREF(p.Cust_ref) CUSTOMER_INFO, + p.ShipToAddr_obj DESTINATION, + p.PONo PURCHASE_ORDER_NUMBER, + p.OrderDate ORDER_DATE, + CURSOR(SELECT LineItemNo, + Quantity, Discount + FROM TABLE(p.LineItemList_ntab) li + ORDER BY LineItemNo) +FROM PurchaseOrder_objview p +WHERE p.PONo = 1001 +/ + +-- Please note this is the same query as above but unnesting feature +-- of Oracle8i has been used using TABLE() operator. +SELECT DEREF(p.Cust_ref) CUSTOMER_INFO, + p.ShipToAddr_obj DESTINATION, + p.PONo PURCHASE_ORDER_NUMBER, + p.OrderDate ORDER_DATE, li.LineItemNo, li.Quantity, li.Discount +FROM PurchaseOrder_objview p, TABLE(p.LineItemList_ntab) li +WHERE p.PONo = 1001 +ORDER BY li.LineItemNo +/ + +-- Select the TotalSELF value FOR each purchse_order +SELECT p.PONo,p.sumLineItems () FROM PurchaseOrder_objview p +ORDER BY p.PONo +/ + +-- SELECT the lineitems and the purchase order numbers +-- returning the linitems as a nested cursor +SELECT po.PONo PURCHASE_ORDER_NUMBER, + po.Cust_ref.Custno CUSTOMER_NUMBER, + CURSOR(SELECT * + FROM TABLE(po.LineItemList_ntab) li + WHERE li.Stock_ref.StockNo = 1535 + ORDER BY LineItemNo) +FROM PurchaseOrder_objview po +ORDER BY PONo +/ + +-- Please note this is the same query as above but unnesting feature +-- of Oracle8i has been used using TABLE() operator. +SELECT po.PONo PURCHASE_ORDER_NUMBER, + po.Cust_ref.Custno CUSTOMER_NUMBER, li.* +FROM PurchaseOrder_objview po, TABLE(po.LineItemList_ntab) li +WHERE li.Stock_ref.StockNo = 1535 +ORDER BY po.PONo, li.LineItemNo; + +-- Select the line items and the purchase numbers FOR all those poUs having +-- a StockNo 1535 + +SELECT po.PONo PURCHASE_ORDER_NUMBER, + po.Cust_ref.Custno CUSTOMER_NUMBER, + li.LineItemNo LINEITEM_NUMBER, + li.Quantity QUANTITY +FROM PurchaseOrder_objview po, TABLE(po.LineItemList_ntab) li +WHERE li.Stock_ref.StockNo = 1535 +ORDER BY po.PONo, li.LineItemNo +/ + +-- Select the Total value FOR each purchse_order +SELECT p.PONo PURCHASE_ORDER_NUMBER, + p.sumLineItems() SUM_LINE_ITEMS +FROM PurchaseOrder_objtab p +ORDER BY PONo +/ + +COMMIT +/ + +CONNECT system/manager +DROP USER po CASCADE +/ + +/* demonstrate creating object views using MAKE_REF and also self-referencing + view */ + +CONNECT system/manager +DROP USER fnd CASCADE; + +GRANT CONNECT, RESOURCE TO fnd IDENTIFIED BY fnd; + +CONNECT fnd/fnd + +CREATE TABLE fnd_application ( + application_id NUMBER PRIMARY KEY, + application_short_name VARCHAR2(50) NOT NULL, + application_name VARCHAR2(240) +); + +CREATE TABLE fnd_form_functions( + function_id NUMBER PRIMARY KEY, + function_name VARCHAR2(30) NOT NULL, + application_id NUMBER, + form_id NUMBER, + parameters VARCHAR2(2000) +); + +CREATE TABLE fnd_menus ( + menu_id NUMBER PRIMARY KEY, + menu_name VARCHAR2(30) NOT NULL +); + +CREATE TABLE fnd_form_vl ( + application_id NUMBER PRIMARY KEY, + form_id NUMBER NOT NULL, + form_name VARCHAR2(30) NOT NULL, + AUDIT_ENABLED_FLAG VARCHAR2(1) NOT NULL, + user_form_name VARCHAR2(80) NOT NULL, + description VARCHAR2(240) +); + +CREATE TABLE fnd_form_functions_vl ( + function_id NUMBER PRIMARY KEY, + function_name VARCHAR2(30) NOT NULL, + application_id NUMBER, + form_id NUMBER, + parameters VARCHAR2(2000), + type VARCHAR2(30), + user_function_name VARCHAR2(80) NOT NULL, + description VARCHAR2(240) +); + + +CREATE TABLE fnd_menu_entries_vl ( + menu_id NUMBER PRIMARY KEY, + entry_sequence NUMBER NOT NULL, + sub_menu_id NUMBER, + function_id NUMBER, + prompt VARCHAR2(30), + description VARCHAR2(240) +); + + +CREATE TABLE fnd_menus_vl ( + menu_id NUMBER PRIMARY KEY, + menu_name VARCHAR2(30) NOT NULL, + user_menu_name VARCHAR2(80) NOT NULL, + description VARCHAR2(240) +); + + +CREATE TYPE fnd_application_t AS OBJECT +( + application_short_name varchar2(50), + application_name varchar2(240) +) +/ + +CREATE OR REPLACE VIEW + fnd_application_object_view OF fnd_application_t + WITH OBJECT OID(application_short_name) AS + SELECT application_short_name, application_name + FROM fnd_application; + +CREATE TYPE fnd_form_t AS OBJECT +( + form_name VARCHAR2(30), + application REF fnd_application_t, + user_form_name varchar2(80), + description varchar2(240) +) +/ + +CREATE OR REPLACE VIEW + fnd_form_view OF fnd_form_t + WITH OBJECT OID(form_name) AS + SELECT F.form_name, + MAKE_REF(fnd_application_object_view, A.application_short_name), + F.user_form_name, F.description + FROM fnd_form_vl F, fnd_application A + WHERE F.application_id = A.application_id; + +CREATE TYPE fnd_function_t AS OBJECT +( + function_name varchar2(30), + form REF fnd_form_t, + type varchar2(30), + parameters varchar2(2000), + user_function_name varchar2(80), + description varchar2(240) +) +/ + +CREATE OR REPLACE VIEW + fnd_function_object_view OF fnd_function_t + WITH OBJECT OID(function_name) AS + SELECT N.function_name, + MAKE_REF(fnd_form_view, F.form_name), + N.type, N.parameters, N.user_function_name, N.description + FROM fnd_form_functions_vl N, fnd_form_vl F + WHERE N.form_id = F.form_id; + +CREATE TYPE fnd_menu_t +/ + +CREATE TYPE fnd_menu_entry_t AS OBJECT +( + entry_sequence number, + prompt varchar2(30), + description varchar2(240), + submenu REF fnd_menu_t, + function REF fnd_function_t +) +/ + +CREATE TYPE fnd_menu_entry_list_t AS TABLE OF fnd_menu_entry_t +/ + +CREATE TYPE fnd_menu_t AS OBJECT +( + menu_name varchar2(30), + user_menu_name varchar2(80), + description varchar2(240), + entries fnd_menu_entry_list_t +) +/ + +/* create self-reference view */ +CREATE OR REPLACE FORCE VIEW + fnd_menu_object_view OF fnd_menu_t + WITH OBJECT OID(menu_name) AS + SELECT M.menu_name, M.user_menu_name, M.description, + CAST( + MULTISET( + SELECT fnd_menu_entry_t( + Q.entry_sequence, Q.prompt, Q.description, + MAKE_REF(fnd_menu_object_view, S.menu_name), NULL) + FROM fnd_menu_entries_vl Q, fnd_menus S + WHERE Q.menu_id = M.menu_id AND Q.sub_menu_id = S.menu_id + ) + AS fnd_menu_entry_list_t) + FROM fnd_menus_vl M; + +CONNECT system/manager; +DROP USER fnd CASCADE +/ +SET ECHO OFF diff --git a/obndra.c b/obndra.c new file mode 100644 index 0000000..0d4cad8 --- /dev/null +++ b/obndra.c @@ -0,0 +1,218 @@ +#ifdef RCSID +static char *RCSid = + "$Header: obndra.c 04-apr-2005.17:13:10 lzhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1991, 2005, Oracle. All rights reserved. +*/ + +/* + NAME + obndra.c - + DESCRIPTION + + PUBLIC FUNCTION(S) + + PRIVATE FUNCTION(S) + + RETURNS + + NOTES + + MODIFIED (MM/DD/YY) + lzhao 04/04/05 - bug4184457 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 03/21/97 - drop table part_nos at the end + rkooi2 11/28/92 - Creation +*/ + +/* Example program demonstrating an array insert using the obndra + example from Chapter 4 of the OCI Programmer's Guide. */ + +#include +#include +#include +#include +#include + +Cda_Def cda; +Lda_Def lda; + + +/* set up the table */ +text *dt = (text *) "DROP TABLE part_nos"; +text *ct = (text *) "CREATE TABLE part_nos (partno NUMBER, description\ + VARCHAR2(20))"; + +text *cp = (text *) "\ + CREATE OR REPLACE PACKAGE update_parts AS\ + TYPE part_number IS TABLE OF part_nos.partno%TYPE\ + INDEX BY BINARY_INTEGER;\ + TYPE part_description IS TABLE OF part_nos.description%TYPE\ + INDEX BY BINARY_INTEGER;\ + PROCEDURE add_parts (n IN INTEGER,\ + descrip IN part_description,\ + partno IN part_number);\ + END update_parts;"; + +text *cb = (text *) "\ + CREATE OR REPLACE PACKAGE BODY update_parts AS\ + PROCEDURE add_parts (n IN INTEGER,\ + descrip IN part_description,\ + partno IN part_number) is\ + BEGIN\ + FOR i IN 1..n LOOP\ + INSERT INTO part_nos\ + VALUES (partno(i), descrip(i));\ + END LOOP;\ + END add_parts;\ + END update_parts;"; + + +#define DESC_LEN 20 +#define MAX_TABLE_SIZE 1200 + +text *pl_sql_block = (text *) "\ + BEGIN\ + update_parts.add_parts(3, :description, :partno);\ + END;"; + +text descrip[3][20] = {"Frammis", "Widget", "Thingie"}; +sword numbers[] = {12125, 23169, 12126}; + +ub2 descrip_alen[3] = {DESC_LEN, DESC_LEN, DESC_LEN}; +ub2 descrip_rc[3]; +ub4 descrip_cs = (ub4) 3; +ub2 descrip_indp[3]; + +ub2 num_alen[3] = {(ub2) sizeof (sword), + (ub2) sizeof (sword), + (ub2) sizeof (sword)}; +ub2 num_rc[3]; +ub4 num_cs = (ub4) 3; +ub2 num_indp[3]; + +dvoid oci_error(void); + +main() +{ + printf("Connecting to ORACLE..."); + if (olon(&lda, (oratext *)"scott/tiger", -1, NULL, -1, -1)) { + printf("Cannot logon as scott/tiger. Exiting...\n"); + exit(1); + } + + if (oopen(&cda, &lda, NULL, -1, -1, NULL, -1)) { + printf("Cannot open cursor, exiting...\n"); + + exit(1); + } + + /* Drop the table. */ + printf("\nDropping table..."); + if (oparse(&cda, dt, -1, 0, 2)) + if (cda.rc != 942) + oci_error(); + printf("\nCreating table..."); + if (oparse(&cda, ct, -1, 0, 2)) + oci_error(); + + /* Parse and execute the create + package statement. */ + printf("\nCreating package..."); + if (oparse(&cda, cp, -1, 0, 2)) + oci_error(); + if (oexec(&cda)) + oci_error(); + + /* Parse and execute the create + package body statement. */ + printf("\nCreating package body..."); + if (oparse(&cda, cb, -1, 0, 2)) + oci_error(); + if (oexec(&cda)) + oci_error(); + + /* Parse the anonymous PL/SQL block + that calls the stored procedure. */ + printf("\nParsing PL/SQL block..."); + if (oparse(&cda, pl_sql_block, -1, 0, 2)) + oci_error(); + + /* Bind the C arrays to the PL/SQL tables. */ + printf("\nBinding arrays..."); + if (obndra(&cda, + (text *) ":description", + -1, + (ub1 *) descrip, + DESC_LEN, + VARCHAR2_TYPE, + -1, + (sb2 *)descrip_indp, + descrip_alen, + descrip_rc, + (ub4) MAX_TABLE_SIZE, + &descrip_cs, + (text *) 0, + -1, + -1)) + oci_error(); + + if (obndra(&cda, + (text *) ":partno", + -1, + (ub1 *) numbers, + (sword) sizeof (sword), + INT_TYPE, + -1, + (sb2 *)num_indp, + num_alen, + num_rc, + (ub4) MAX_TABLE_SIZE, + &num_cs, + (text *) 0, + -1, + -1)) + oci_error(); + + printf("\nExecuting block..."); + if (oexec(&cda)) + oci_error(); + + /* drop table part_nos */ + if (oparse(&cda, dt, -1, 0, 2)) + oci_error(); + + printf("\n"); + if (oclose(&cda)) + { + printf("Error closing cursor!\n"); + return -1; + } + + if (ologof(&lda)) + { + printf("Error logging off!\n"); + return -1; + } + exit(1); +} + + +dvoid +oci_error(void) +{ + text msg[600]; + sword rv; + + rv = oerhms(&lda, (sb2)cda.rc, msg, 600); + + printf("\n\n%.*s", rv, msg); + printf("Processing OCI function %s\n", oci_func_tab[cda.fc]); + if (oclose(&cda)) + printf("Error closing cursor!\n"); + if (ologof(&lda)) + printf("Error logging off!\n"); + exit(1); +} + diff --git a/occiaqlis.cpp b/occiaqlis.cpp new file mode 100644 index 0000000..6b48202 --- /dev/null +++ b/occiaqlis.cpp @@ -0,0 +1,124 @@ +/* Copyright (c) 2003, 2009, Oracle and/or its affiliates. +All rights reserved. */ +/* + NAME + occiaqlis.cpp - OCCI AQ listener functionality demo + + DESCRIPTION + This demo program explains the use of listener class of advanced + queueing in occi. + This functionality aims at listening on behalf of a bunch of agents + which are specified on 1 or more queues, and return the agent + for whom a message has arrived. + The listen() call listens on one or more queues on behalf + of a list of agents. + This call returns the agent for which there is a message. + Prior to this call, the list of agents on behalf to listen to must been set + This is a blocking call that returns when there is a message ready for + consumption for an agent in the list. + If there are no messages found when the wait time expires, + an error is returned. + + MODIFIED (MM/DD/YY) + sudsrini 07/08/09 - Include string.h, iostream not including it on sles11 + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/22/04 - Copyright info + sprabhak 03/05/03 - Creation + +*/ + +#include +#include +#include +#include + +using namespace std; +using namespace oracle::occi; +using namespace oracle::occi::aq; + +void test_enqueue(Environment *env, Connection *conn) +{ + cout<<"Enqueuing the message into the queue"<commit(); + cout<<"Enqueue done"< agList; + + agList.push_back(Agent(env, "AGT1", "hr.queue04")); + agList.push_back(Agent(env, "AGT2", "hr.queue04")); + // The listener is to listen for the above 2 agents. + l.setAgentList(agList); + l.setTimeOutForListen(10); + + cout<<"Listening..."<createConnection("hr","hr"); + test_enqueue(env, con); + test_listener(env, con); + env->terminateConnection(con); + } + catch(SQLException &ex) + { + cout<<"Exception thrown "< +#include +#include +#include "occiaqopm.h" + +using namespace oracle::occi; +using namespace std; +using namespace oracle::occi::aq; + +Environment *env; + +void test_raw(Connection *conn); +void test_raw_enqueue(Connection *conn); +void test_raw_dequeue(Connection *conn); +void test_anydata(Connection *conn); +void test_anydata_enqueue(Connection *conn); +void test_anydata_dequeue(Connection *conn); +void test_adt(Connection *conn); +void test_adt_enqueue(Connection *conn); +void test_adt_dequeue(Connection *conn); + +int main (void) +{ + try + { + env = Environment::createEnvironment (Environment::OBJECT); + cout<<"Demo for advanced queuing enqueue/dequeue"<createConnection("hr","hr"); + //Testing AQ operations on raw message + test_raw(conn); + //Testing AQ operations on anydata message + test_anydata(conn); + //Testing AQ operations on adt message + test_adt(conn); + env->terminateConnection(conn); + Environment::terminateEnvironment (env); + cout<<"Demo for advanced queueing enqueue/dequeue done"< list; + Agent a1(env); + a1.setName("AGT"); + a1.setAddress("hr.queue02"); + a1.setProtocol(0); + + //String functions + string in_str1("ANYDATA-MSG"); + any1.setFromString(in_str1); + cout << "Message before enqueue:" << in_str1 << endl; + + //Set the payload + m1.setAnyData(any1); + + //Setting the Recipient list + list.push_back(a1); + m1.setRecipientList(list); + + //Enqueue the message + Producer prod(conn); + prod.setVisibility(Producer::ENQ_ON_COMMIT); + Bytes by_enq=prod.send(m1, "hr.queue02"); + conn->commit(); + cout<<"Enqueue of anydata message done"<setA1 (a1); + obj->setA2 (a2); + m1.setObject(obj); + Producer prod(conn); + cout << "Object data before enqueue " << endl; + cout<<"A1: "<<(int)obj->getA1()<getA2 () << endl; + prod.send(m1, "hr.queue03"); + delete (obj); + cout<<"Enqueue of adt message done"<getA1()<getA2 () << endl; + delete(obnew1); + cout<<"Dequeue of adt message done"< +#include +#include +#include +using namespace oracle::occi; +using namespace std; + +/** + * The demo sample has starts from startDemo method. This method is called + * by main. startDemo calls other methods, the supporting methods for + * startDemo are, + * insertRows - insert the rows into the table + * dataRollBack - deletes the inserted rows + * populateBlob - populates a given blob + * dumpBlob - prints the blob as an integer stream + */ +// These will tell the type of read/write we use +#define USE_NORM 1 +#define USE_CHUN 2 +#define USE_BUFF 3 + +/* Buffer Size */ +#define BUFSIZE 200; + +class occiBlob +{ + public: + string username; + string password; + string url; + + void insertRows (Connection *conn) + throw (SQLException) + { + Statement *stmt = conn->createStatement ("INSERT INTO electronic_media(product_id,ad_id,ad_composite,ad_sourcetext) VALUES (:v1,:v2,:v3,:v4)"); + Blob blob(conn); + blob.setEmpty(); + Clob clob(conn); + clob.setEmpty(); + stmt->setInt(1,6666); + stmt->setInt(2,11001); + stmt->setBlob(3,blob); + stmt->setClob(4,clob); + stmt->executeUpdate(); + stmt->setSQL ("INSERT INTO electronic_media(product_id,ad_id,ad_composite,ad_sourcetext) VALUES (:v1, :v2, :v3, :v4)"); + stmt->setInt(1,7777); + stmt->setInt(2,11001); + stmt->setBlob(3,blob); + stmt->setClob(4,clob); + stmt->executeUpdate(); + stmt->setSQL ("INSERT INTO electronic_media(product_id,ad_id,ad_composite,ad_sourcetext) VALUES (:v1, :v2, :v3, :v4)"); + stmt->setInt(1,8888); + stmt->setInt(2,11001); + stmt->setBlob(3,blob); + stmt->setClob(4,clob); + stmt->executeUpdate(); + conn->commit(); + conn->terminateStatement (stmt); + + } + + void dataRollBack (Connection *conn) + throw (SQLException) + { + Statement *stmt = conn->createStatement ("DELETE FROM electronic_media WHERE product_id=6666 AND ad_id=11001"); + stmt->executeUpdate(); + stmt->setSQL("DELETE FROM electronic_media WHERE product_id=7777 AND ad_id=11001"); + stmt->executeUpdate(); + stmt->setSQL("DELETE FROM electronic_media WHERE product_id=8888 AND ad_id=11001"); + stmt->executeUpdate(); + conn->commit(); + conn->terminateStatement (stmt); + + } + + /** + * populating the blob uses write method; + */ + void populateBlob (Blob &blob,unsigned int way,unsigned int size=0) + throw (SQLException) + { + if (way == USE_NORM) + { + cout << "Populating the Blob using write method" << endl; + unsigned int offset=1; + unsigned char *buffer = new unsigned char[size]; + memset (buffer, (char)10, size); + unsigned int bytesWritten=blob.write (size,buffer, size,offset); + //cout <<"Bytes Written : " << bytesWritten << endl; + delete[] buffer; + } + else if(way==USE_CHUN) + { + cout << "Populating the Blob using writeChunk method" << endl; + unsigned int offset=1; + unsigned int pieceCount = 4; + unsigned char *buffer = new unsigned char[size*pieceCount]; + memset (buffer, (char)10, size*pieceCount); + // Open the blob for writeChunk + blob.open(OCCI_LOB_READWRITE); + for (int i = 0; i < pieceCount; ++i,offset+=size) + blob.writeChunk(size,buffer,size,offset); + cout << "Blob Size " << blob.length() << endl; + delete[] buffer; + blob.close(); + } + else if(way==USE_BUFF) + { + // Uses stream here + unsigned int size; + unsigned int bufsize=BUFSIZE; + cout << "Populating the Blob using writeBuffer(Stream) method" << endl; + char *file = (char *)"blobdemo.dat"; + char *buffer = new char[bufsize]; + ifstream inFile; + inFile.open(file,ios::in); + if (!inFile) + { + cout << "blobdemo.dat file not found\n"; + delete[] buffer; + return; + } + Stream *strm=blob.getStream(); + while(inFile) + { + memset (buffer, NULL, bufsize); + inFile.read(buffer,bufsize); + strm->writeBuffer(buffer,strlen(buffer)); + } + strcpy(buffer,"This piece for writeLastBuffer"); + size=strlen(buffer); + strm->writeLastBuffer(buffer,size); + blob.closeStream(strm); + inFile.close(); + delete[] buffer; + } + cout << "Populating the Blob - Success" << endl; + } + + /** + * printing the blob data as integer stream + */ + void dumpBlob (Blob &blob,unsigned int way) + throw (SQLException) + { + unsigned int size=BUFSIZE; + if (blob.isNull()) + { + cout << "Blob is Null\n"; + return; + } + unsigned int offset= 1,bloblen = blob.length(); + cout << "Length of Blob : "<< bloblen << endl; + if (bloblen == 0) + return; + unsigned char *buffer= new unsigned char[size]; + memset (buffer, NULL, size); + if (way==USE_NORM) + { + cout << "Dumping blob (using read ): "; + int bytesRead=blob.read(bloblen,buffer,bloblen,offset); + for (int i = 0; i < bytesRead; ++i) + cout << (int) buffer[i]; + cout << endl; + } + else if(way==USE_BUFF) + { + Stream *inStream = blob.getStream (1,0); + cout << "Dumping blob(using stream): "; + int bytesRead=(inStream->readBuffer((char *)buffer, size)); + while (bytesRead > 0) + { + for (int i = 0; i < bytesRead; ++i) + { + cout << (int) buffer[i]; + } + bytesRead=(inStream->readBuffer((char *)buffer, size)); + } + cout << endl; + blob.closeStream (inStream); + } + delete []buffer; + } + + occiBlob () + { + /** + * default values of username & password + */ + username = "hr"; + password = "hr"; + url = ""; + } + + void setUsername (string u) + { + username = u; + } + + void setPassword (string p) + { + password = p; + } + + void setUrl (string u) + { + url = u; + } + + void runSample () + throw (SQLException) + { + Environment *env = Environment::createEnvironment ( + Environment::DEFAULT); + Connection *conn = env->createConnection (username, password, url); + insertRows (conn); + + // Selecting and modifying the blob column of the table + string sqlQuery = + "SELECT product_id,ad_id,ad_composite FROM electronic_media FOR UPDATE"; + Statement *stmt1 = conn->createStatement (sqlQuery); + ResultSet *rset1 = stmt1->executeQuery (); + cout << "Query :" << sqlQuery << endl; + unsigned int way=USE_NORM; + while (rset1->next ()) + { + cout << "Product_id : " << (int)rset1->getInt(1) << endl; + cout << "Ad_id : " << (int)rset1->getInt(2) << endl; + Blob blob = rset1->getBlob (3); + dumpBlob (blob, USE_NORM); + if (way==USE_NORM) + { + populateBlob(blob,USE_NORM,20); + way=USE_CHUN; + } + else if(way==USE_CHUN) + { + populateBlob(blob,USE_CHUN,20); + way=USE_BUFF; + } + else if(way==USE_BUFF) + { + populateBlob(blob,USE_BUFF); + way=USE_NORM; + } + } + stmt1->executeUpdate(); + stmt1->closeResultSet (rset1); + + // Printing after updating the blob content. + way = USE_BUFF; + sqlQuery = "SELECT product_id, ad_id, ad_composite FROM electronic_media \ +ORDER BY product_id"; + Statement *stmt2 = conn->createStatement (sqlQuery); + ResultSet *rset2 = stmt2->executeQuery (); + cout << "Query :" << sqlQuery << endl; + while (rset2->next ()) + { + cout << "Product_id : " << (int)rset2->getInt(1) << endl; + cout << "Ad_id : " << (int)rset2->getInt(2) << endl; + Blob blob = rset2->getBlob (3); + if (way==USE_NORM) + { + dumpBlob (blob, USE_NORM); + way=USE_BUFF; + } + else if(way==USE_BUFF) + { + dumpBlob (blob, USE_BUFF); + way=USE_NORM; + } + } + stmt2->closeResultSet (rset2); + + dataRollBack(conn); + + conn->terminateStatement (stmt1); + conn->terminateStatement (stmt2); + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + } + +};//end of class occiBlob + +int main (void) +{ + try + { + occiBlob *b = new occiBlob (); + b->setUsername ("hr"); + b->setPassword ("hr"); + b->runSample (); + delete(b); + } + catch (exception &e) + { + cout << e.what(); + } +} + diff --git a/occiclob.cpp b/occiclob.cpp new file mode 100644 index 0000000..2be18ed --- /dev/null +++ b/occiclob.cpp @@ -0,0 +1,326 @@ +/* Copyright (c) 2001, 2009, Oracle and/or its affiliates. +All rights reserved. */ +/* + NAME + occiclob.cpp - OCCI CLOB Interface demo + + DESCRIPTION + This demo program explains the way of using CLOB interface. + This program inserts an empty clob into the table,selects the + clob from table, modifies it and stores it back into the table. + The Clob content will be printed finally. + This demo uses write , writeChunk and writeBuffer methods to + modify the clob contents, and also uses read and readBuffer + methods for reading. + + MODIFIED (MM/DD/YY) + sudsrini 07/08/09 - Include string.h, iostream not including it on sles11 + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/22/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include +#include +#include +using namespace oracle::occi; +using namespace std; + +/** + * The demo sample has starts from startDemo method. This method is called + * by main. startDemo calls other methods, the supporting methods for + * startDemo are, + * insertRows - insert the rows into the table + * dataRollBack - deletes the inserted rows + * populateClob - populates a given clob + * dumpClob - prints the clob as an integer stream + */ +// These will tell the type of read/write we use +#define USE_NORM 1 +#define USE_CHUN 2 +#define USE_BUFF 3 + +/* Buffer Size */ +#define BUFSIZE 200; + +class occiClob +{ + public: + string username; + string password; + string url; + + void insertRows (Connection *conn) + throw (SQLException) + { + Statement *stmt = conn->createStatement ("INSERT INTO electronic_media(product_id,ad_id,ad_composite,ad_sourcetext) VALUES (:v1,:v2,:v3,:v4)"); + Blob blob(conn); + blob.setEmpty(); + Clob clob(conn); + clob.setEmpty(); + stmt->setInt(1,6666); + stmt->setInt(2,11001); + stmt->setBlob(3,blob); + stmt->setClob(4,clob); + stmt->executeUpdate(); + stmt->setSQL ("INSERT INTO electronic_media(product_id,ad_id,ad_composite,ad_sourcetext) VALUES (:v1, :v2, :v3, :v4)"); + stmt->setInt(1,7777); + stmt->setInt(2,11001); + stmt->setBlob(3,blob); + stmt->setClob(4,clob); + stmt->executeUpdate(); + stmt->setSQL ("INSERT INTO electronic_media(product_id,ad_id,ad_composite,ad_sourcetext) VALUES (:v1, :v2, :v3, :v4)"); + stmt->setInt(1,8888); + stmt->setInt(2,11001); + stmt->setBlob(3,blob); + stmt->setClob(4,clob); + stmt->executeUpdate(); + conn->commit(); + conn->terminateStatement (stmt); + + } + + void dataRollBack (Connection *conn) + throw (SQLException) + { + Statement *stmt = conn->createStatement ("DELETE FROM electronic_media WHERE product_id=6666 AND ad_id=11001"); + stmt->executeUpdate(); + stmt->setSQL("DELETE FROM electronic_media WHERE product_id=7777 AND ad_id=11001"); + stmt->executeUpdate(); + stmt->setSQL("DELETE FROM electronic_media WHERE product_id=8888 AND ad_id=11001"); + stmt->executeUpdate(); + conn->commit(); + conn->terminateStatement (stmt); + + } + + /** + * populating the clob uses write method; + */ + void populateClob (Clob &clob,unsigned int way) + throw (SQLException) + { + unsigned int bufsize=BUFSIZE; + if (way == USE_NORM) + { + cout << "Populating the Clob using write method" << endl; + unsigned int offset=1; + unsigned char *buffer = new unsigned char[bufsize]; + strcpy((char *)buffer, + "Just for source text content(added using write method)"); + unsigned int size=strlen((char *)buffer); + unsigned int bytesWritten=clob.write (size,buffer, size,offset); + //cout <<"Bytes Written : " << bytesWritten << endl; + delete[] buffer; + } + else if(way==USE_CHUN) + { + cout << "Populating the Clob using writeChunk method" << endl; + unsigned int offset=1; + unsigned int pieceCount = 4; + unsigned char *buffer = new unsigned char[bufsize*pieceCount]; + strcpy((char *)buffer, + "Just for source text content(added using writeChunk method)"); + unsigned int size=strlen((char *)buffer); + // Open the clob for writeChunk + clob.open(OCCI_LOB_READWRITE); + for (int i = 0; i < pieceCount; ++i,offset+=size) + clob.writeChunk(size,buffer,size,offset); + cout << "Clob Size " << clob.length() << endl; + delete[] buffer; + clob.close(); + } + else if(way==USE_BUFF) + { + // Uses stream here + cout << "Populating the Clob using writeBuffer(Stream) method" << endl; + char *file = (char *)"clobdemo.dat"; + char *buffer = new char[bufsize + 1]; + ifstream inFile; + inFile.open(file,ios::in); + if (!inFile) + { + cout << "clobdemo.dat file not found\n"; + delete[] buffer; + return; + } + unsigned int size; + Stream *strm=clob.getStream(); + while(inFile) + { + memset (buffer, NULL, bufsize + 1); + inFile.read(buffer,bufsize); + strm->writeBuffer(buffer,strlen(buffer)); + } + strcpy(buffer,"This piece for writeLastBuffer"); + size=strlen(buffer); + strm->writeLastBuffer(buffer,size); + clob.closeStream(strm); + inFile.close(); + delete[] buffer; + } + cout << "Populating the Clob - Success" << endl; + } + + /** + * printing the clob data as integer stream + */ + void dumpClob (Clob &clob,unsigned int way) + throw (SQLException) + { + unsigned int size=BUFSIZE; + unsigned int offset = 1; + + if (clob.isNull()) + { + cout << "Clob is Null\n"; + return; + } + unsigned int cloblen = clob.length(); + cout << "Length of Clob : "<< cloblen << endl; + if (cloblen == 0) + return; + unsigned char *buffer= new unsigned char[size]; + memset (buffer, NULL, size); + if (way==USE_NORM) + { + cout << "Dumping clob (using read ): "; + int bytesRead=clob.read(size,buffer,size,offset); + for (int i = 0; i < bytesRead; ++i) + cout << buffer[i]; + cout << endl; + } + else if(way==USE_BUFF) + { + Stream *inStream = clob.getStream (1,0); + cout << "Dumping clob(using stream): "; + int bytesRead=(inStream->readBuffer((char *)buffer, size)); + while (bytesRead > 0) + { + for (int i = 0; i < bytesRead; ++i) + { + cout << buffer[i]; + } + bytesRead=(inStream->readBuffer((char *)buffer, size)); + } + cout << endl; + clob.closeStream (inStream); + } + delete []buffer; + } + + occiClob () + { + /** + * default values of username & password + */ + username = "hr"; + password = "hr"; + url = ""; + } + + void setUsername (string u) + { + username = u; + } + + void setPassword (string p) + { + password = p; + } + + void setUrl (string u) + { + url = u; + } + + void runSample () + throw (SQLException) + { + Environment *env = Environment::createEnvironment ( + Environment::DEFAULT); + Connection *conn = env->createConnection (username, password, url); + insertRows (conn); + + // Selecting and modifying the clob column of the table + string sqlQuery = + "SELECT product_id,ad_id,ad_sourcetext FROM electronic_media FOR UPDATE"; + Statement *stmt1 = conn->createStatement (sqlQuery); + ResultSet *rset1 = stmt1->executeQuery (); + cout << "Query :" << sqlQuery << endl; + unsigned int way=USE_NORM; + while (rset1->next ()) + { + cout << "Product_id : " << (int)rset1->getInt(1) << endl; + cout << "Ad_id : " << (int)rset1->getInt(2) << endl; + Clob clob = rset1->getClob (3); + dumpClob (clob, USE_NORM); + if (way==USE_NORM) + { + populateClob(clob,USE_NORM); + way=USE_CHUN; + } + else if(way==USE_CHUN) + { + populateClob(clob,USE_CHUN); + way=USE_BUFF; + } + else if(way==USE_BUFF) + { + populateClob(clob,USE_BUFF); + way=USE_NORM; + } + } + stmt1->executeUpdate(); + stmt1->closeResultSet (rset1); + + // Printing after updating the clob content. + way = USE_BUFF; + sqlQuery = "SELECT product_id, ad_id, ad_sourcetext FROM electronic_media \ +ORDER BY product_id"; + Statement *stmt2 = conn->createStatement (sqlQuery); + ResultSet *rset2 = stmt2->executeQuery (); + cout << "Query :" << sqlQuery << endl; + while (rset2->next ()) + { + cout << "Product_id : " << (int)rset2->getInt(1) << endl; + cout << "Ad_id : " << (int)rset2->getInt(2) << endl; + Clob clob = rset2->getClob (3); + if (way==USE_NORM) + { + dumpClob (clob, USE_NORM); + way=USE_BUFF; + } + else if(way==USE_BUFF) + { + dumpClob (clob, USE_BUFF); + way=USE_NORM; + } + } + stmt2->closeResultSet (rset2); + dataRollBack(conn); + conn->terminateStatement (stmt1); + conn->terminateStatement (stmt2); + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + } + +};//end of class occiClob + +int main (void) +{ + try + { + occiClob *b = new occiClob (); + b->setUsername ("hr"); + b->setPassword ("hr"); + b->runSample (); + } + catch (exception &e) + { + cout << e.what(); + } +} + diff --git a/occicoll.cpp b/occicoll.cpp new file mode 100644 index 0000000..aadb7d7 --- /dev/null +++ b/occicoll.cpp @@ -0,0 +1,230 @@ +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. */ +/* + NAME + occicoll.cpp - OCCI Collections Demo + + DESCRIPTION + To exhibit simple insert, delete & update operations on table + having a Nested Table column + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/22/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include +#include +using namespace oracle::occi; +using namespace std; + +typedef vector journal; + +class occicoll +{ + private: + + Environment *env; + Connection *conn; + Statement *stmt; + string tableName; + string typeName; + + public: + + occicoll (string user, string passwd, string db) + { + env = Environment::createEnvironment (Environment::OBJECT); + conn = env->createConnection (user, passwd, db); + } + + ~occicoll () + { + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + } + + void setTableName (string s) + { + tableName = s; + } + + /** + * Insertion of a row + */ + void insertRow () + { + int c1 = 11; + journal c2; + + c2.push_back ("LIFE"); + c2.push_back ("TODAY"); + c2.push_back ("INVESTOR"); + + cout << "Inserting row with jid = " << 11 << + " and journal_tab (LIFE, TODAY, INVESTOR )" << endl; + try{ + stmt = conn->createStatement ( + "INSERT INTO journal_tab (jid, jname) VALUES (:x, :y)"); + stmt->setInt (1, c1); + setVector (stmt, 2, c2, "JOURNAL"); + stmt->executeUpdate (); + }catch(SQLException ex) + { + cout<<"Exception thrown for insertRow"<terminateStatement (stmt); + + } + + // Displaying all the rows of the table + void displayAllRows () + { + cout << "Displaying all the rows of the table" << endl; + stmt = conn->createStatement ( + "SELECT jid, jname FROM journal_tab order by jid"); + + journal c2; + + ResultSet *rs = stmt->executeQuery(); + try{ + while (rs->next()) + { + cout << "jid: " << rs->getInt(1) << endl; + cout << "jname: "; + getVector (rs, 2, c2); + for (int i = 0; i < c2.size(); ++i) + cout << c2[i] << " "; + cout << endl; + } + }catch(SQLException ex) + { + cout<<"Exception thrown for displayRow"<closeResultSet (rs); + conn->terminateStatement (stmt); + + } // End of displayAllRows() + + // Deleting a row of the nested table of strings + void deleteRow (int c1, string str) + { + cout << "Deleting a row of the nested table of strings" << endl; + stmt = conn->createStatement ( + "SELECT jname FROM journal_tab WHERE jid = :x"); + journal c2; + stmt->setInt (1, c1); + + ResultSet *rs = stmt->executeQuery(); + try{ + if (rs->next()) + { + getVector (rs, 1, c2); + c2.erase (find (c2.begin(), c2.end(), str)); + } + stmt->closeResultSet (rs); + + stmt->setSQL ("UPDATE journal_tab SET jname = :x WHERE jid = :y"); + stmt->setInt (2, c1); + setVector (stmt, 1, c2, "JOURNAL"); + stmt->executeUpdate (); + }catch(SQLException ex) + { + cout<<"Exception thrown for delete row"<commit(); + conn->terminateStatement (stmt); + } // End of deleteRow (int, string) + + // Updating a row of the nested table of strings + void updateRow (int c1, string str) + { + cout << "Updating a row of the nested table of strings" << endl; + stmt = conn->createStatement ( + "SELECT jname FROM journal_tab WHERE jid = :x"); + + journal c2; + + stmt->setInt (1, c1); + ResultSet *rs = stmt->executeQuery(); + try{ + if (rs->next()) + { + getVector (rs, 1, c2); + c2[0] = str; + } + stmt->closeResultSet (rs); + + stmt->setSQL ("UPDATE journal_tab SET jname = :x WHERE jid = :y"); + stmt->setInt (2, c1); + setVector (stmt, 1, c2, "JOURNAL"); + stmt->executeUpdate (); + }catch(SQLException ex) + { + cout<<"Exception thrown for updateRow"<commit(); + conn->terminateStatement (stmt); + } // End of UpdateRow (int, string) + + void cleanup() + { + stmt = conn->createStatement ("DELETE FROM journal_tab"); + stmt->execute(); + stmt->setSQL ("INSERT INTO journal_tab (jid, jname) VALUES (22, journal ('NATION', 'TIMES'))"); + stmt->executeUpdate(); + stmt->setSQL ("INSERT INTO journal_tab (jid, jname) VALUES (33, journal ('CRICKET', 'ALIVE'))"); + stmt->executeUpdate(); + conn->commit(); + conn->terminateStatement (stmt); + } + +};//end of class occicoll + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + + try + { + cout << "occicoll - Exhibiting simple insert, delete & update operations" + " on table having a Nested Table column" << endl; + occicoll *demo = new occicoll (user, passwd, db); + + cout << "Displaying all rows before the operations" << endl; + demo->displayAllRows (); + + demo->insertRow (); + + demo->deleteRow (11, "TODAY"); + + demo->updateRow (33, "New_String"); + + cout << "Displaying all rows after all the operations" << endl; + demo->displayAllRows (); + + demo->cleanup(); + delete (demo); + cout << "occicoll - done" << endl; + }catch (SQLException ea) + { + cerr << "Error running the demo: " << ea.getMessage () << endl; + } +} diff --git a/occidemo.sql b/occidemo.sql new file mode 100644 index 0000000..6d1c6a8 --- /dev/null +++ b/occidemo.sql @@ -0,0 +1,344 @@ +/* Copyright (c) 2002, 2004, Oracle. All rights reserved. */ + +/* + NAME + occidemo.sql - Create OCCI demo objects + + DESCRIPTION + SQL Script to create OCCI demo objects + Assumes HR schema is setup + Assumes system's account passwd to be manager + Execute this before any of the OCCI demos are run + To drop the objects created by this SQL use occidemod.sql + + MODIFIED + sudsrini 03/06/03 - sudsrini_occi_10ir1_demos (include occidemod) + idcqe 03/13/01 - Created + +*/ + + +/* Drop objects before creating them */ + +@occidemod.sql + +connect hr/hr + +CREATE TABLE elements ( + element_name VARCHAR2(25), + molar_volume BINARY_FLOAT, + atomic_weight BINARY_DOUBLE +); + +CREATE TABLE author_tab ( + author_id NUMBER, + author_name VARCHAR2(25) +); + +INSERT INTO author_tab (author_id, author_name) VALUES (333, 'JOE'); +INSERT INTO author_tab (author_id, author_name) VALUES (444, 'SMITH'); + +CREATE OR REPLACE TYPE publ_address AS OBJECT ( + street_no NUMBER, + city VARCHAR2(25) +) +/ + +CREATE TABLE publisher_tab ( + publisher_id NUMBER, + publisher_add publ_address +); + +INSERT INTO publisher_tab (publisher_id, publisher_add) VALUES +(11, publ_address (121, 'NEW YORK')); + +CREATE TABLE publ_address_tab OF publ_address; + +INSERT INTO publ_address_tab VALUES (22, 'BOSTON'); +INSERT INTO publ_address_tab VALUES (33, 'BUFFALO'); +INSERT INTO publ_address_tab VALUES (44, 'CALIFORNIA'); + + +CREATE OR REPLACE TYPE journal AS TABLE OF VARCHAR2(50) +/ +CREATE TABLE journal_tab (jid NUMBER, jname journal) +NESTED TABLE jname STORE AS journal_store; + +INSERT INTO journal_tab (jid, jname) VALUES (22, journal ('NATION', 'TIMES')); +INSERT INTO journal_tab (jid, jname) VALUES (33, journal ('CRICKET', 'ALIVE')); + +CREATE OR REPLACE TYPE people_obj AS OBJECT ( + ssn NUMBER, + name VARCHAR2(25) +) NOT FINAL; +/ + +CREATE OR REPLACE TYPE librarian UNDER people_obj( + empno NUMBER, + sal NUMBER(7,2), + dob DATE, + photo BLOB +) +/ + +CREATE TABLE librarian_tab OF librarian; + +INSERT INTO librarian_tab VALUES +(101, 'DAVE', 1001, 10000, '12-Jan-1970', empty_blob()); +INSERT INTO librarian_tab VALUES +(102, 'BOB', 1002, 12000, '17-Jan-1970', empty_blob()); + +CREATE TABLE article_tab ( + artid NUMBER, + artdesc VARCHAR2(4000), + artsummary LONG, + artfeedbk VARCHAR2(2000) +); + +CREATE OR REPLACE PROCEDURE demo_proc (col1 IN NUMBER, col2 IN OUT VARCHAR2, +col3 OUT CHAR) AS +BEGIN + col2 := col1 || ' ' || col2 || ' ' || 'IN-OUT'; + col3 := 'OUT'; +END; +/ + +CREATE OR REPLACE FUNCTION demo_fun (col1 IN NUMBER, +col2 IN OUT VARCHAR2, col3 OUT CHAR) RETURN CHAR AS +BEGIN + col2 := col1 || ' ' || col2 || ' ' || 'IN-OUT'; + col3 := 'OUT'; + RETURN 'abcd'; +END; +/ + +CREATE TABLE book (bookid NUMBER, summary VARCHAR2(4000)); + +CREATE TABLE cover (c1 NUMBER(5), c2 VARCHAR2(20)); + +DECLARE +ch1 VARCHAR2(4000) := 'aa'; +ch2 VARCHAR2(4000):= ''; +nu NUMBER := 0; +BEGIN + FOR nu IN 1..11 LOOP + ch2 := ch1 || ch2; ch1 := ch2; + END LOOP; + INSERT INTO book (bookid, summary) VALUES (11, ch1); +END; +/ + +CREATE TYPE elecdoc_typ AS OBJECT + ( document_typ VARCHAR2(32) + , formatted_doc BLOB + ) ; +/ +CREATE TYPE elecdoc_tab AS TABLE OF elecdoc_typ; +/ + +CREATE TYPE elheader_typ AS OBJECT + ( header_name VARCHAR2(256) + , creation_date DATE + , header_text VARCHAR2(1024) + , logo BLOB + ); +/ + +CREATE TABLE electronic_media + ( product_id NUMBER(6) + , ad_id NUMBER(6) + , ad_composite BLOB + , ad_sourcetext CLOB + , ad_finaltext CLOB + , ad_fltextn NCLOB + , ad_elecdocs_ntab elecdoc_tab + , ad_photo BLOB + , ad_graphic BFILE + , ad_header elheader_typ + , press_release LONG + ) NESTED TABLE ad_elecdocs_ntab STORE AS elecdocs_nestedtab; +CREATE UNIQUE INDEX printmedia_pk + ON electronic_media (product_id, ad_id); + +ALTER TABLE electronic_media +ADD ( CONSTRAINT printmedia__pk + PRIMARY KEY (product_id, ad_id) + ) ; + + + +CREATE TYPE people_typ AS OBJECT +( + name VARCHAR2(30), + ssn NUMBER, + dob DATE +) not final; +/ + +CREATE TABLE people_tab OF people_typ; + +INSERT INTO people_tab VALUES (people_typ('john', 111, '01-Jan-1970')); +INSERT INTO people_tab VALUES (people_typ('jill', 666, '06-Jan-1976')); + +CREATE TYPE student UNDER people_typ +( + stud_id NUMBER, + teammate REF people_typ +) NOT FINAL; +/ + +CREATE TABLE student_tab OF student; +INSERT INTO student_tab VALUES ('jimmy',222,'02-Feb-1976',200, +(SELECT REF(a) FROM people_tab a where name='john')); + +CREATE TYPE parttime_stud UNDER student +( + course_id NUMBER, + partner REF student +)NOT FINAL; +/ +CREATE TABLE parttime_stud_tab OF parttime_stud; + +INSERT INTO parttime_stud_tab VALUES ('james',333,'03-Feb-1976',300, +(SELECT REF(a) FROM people_tab a where name='john'),3000, +(SELECT REF(a) FROM student_tab a)); + + +CREATE TYPE foreign_student UNDER parttime_stud +( + country VARCHAR2(30), + leader REF parttime_stud +); +/ +CREATE TABLE foreign_student_tab OF foreign_student; + +COMMIT; + + +/* OCCI AQ Objects */ + + +connect system/manager + +grant aq_administrator_role, aq_user_role to hr; +grant execute on dbms_aq to hr; +grant execute on dbms_aqadm to hr; + +BEGIN + dbms_aqadm.grant_system_privilege('ENQUEUE_ANY','hr',FALSE); + dbms_aqadm.grant_system_privilege('DEQUEUE_ANY','hr',FALSE); +END; +/ + +connect hr/hr + +CREATE OR REPLACE TYPE hr_obj AS OBJECT +(a1 NUMBER, a2 VARCHAR2(25)); +/ + +BEGIN + dbms_aqadm.create_queue_table ( + queue_table => 'hr.table01', + queue_payload_type => 'RAW', + comment => 'single-consumer', + multiple_consumers => false, + compatible => '8.1.0' +); +END; +/ + +BEGIN + dbms_aqadm.create_queue ( + queue_name => 'queue01', + queue_table=> 'hr.table01' +); +END; +/ +BEGIN + dbms_aqadm.start_queue(queue_name => 'queue01'); +END; +/ + +BEGIN + dbms_aqadm.create_queue_table ( + queue_table => 'hr.table02', + queue_payload_type => 'SYS.ANYDATA', + comment => 'multi-consumer', + multiple_consumers => true, + compatible => '8.1.0' +); +END; +/ + +BEGIN + dbms_aqadm.create_queue ( + queue_name => 'queue02', + queue_table=> 'hr.table02' +); +END; +/ +BEGIN + dbms_aqadm.start_queue(queue_name => 'queue02'); +END; +/ + +BEGIN + dbms_aqadm.create_queue_table ( + queue_table => 'hr.table03', + queue_payload_type => 'hr_obj', + comment => 'multi-consumer', + multiple_consumers => true, + compatible => '8.1.0' +); +END; +/ + +BEGIN + dbms_aqadm.create_queue ( + queue_name => 'queue03', + queue_table=> 'hr.table03' +); +END; +/ +BEGIN + dbms_aqadm.start_queue(queue_name => 'queue03'); +END; +/ + +BEGIN + dbms_aqadm.create_queue_table ( + queue_table => 'hr.table04', + queue_payload_type => 'RAW', + comment => 'multiple-consumer', + multiple_consumers => true, + compatible => '8.1.0' +); +END; +/ + +BEGIN + dbms_aqadm.create_queue ( + queue_name => 'queue04', + queue_table=> 'hr.table04' +); +END; +/ +BEGIN + dbms_aqadm.start_queue(queue_name => 'queue04'); +END; +/ + +Rem Add default local subscribers to the queues + +BEGIN + dbms_aqadm.add_subscriber( queue_name=> 'queue03', + subscriber=> sys.aq$_agent('AGT1','hr.queue03', 0)); +END; +/ + +BEGIN + dbms_aqadm.add_subscriber( queue_name=> 'queue04', + subscriber=> sys.aq$_agent('AGT1','hr.queue04', 0)); +END; +/ + diff --git a/occidemod.sql b/occidemod.sql new file mode 100644 index 0000000..d5d4ce7 --- /dev/null +++ b/occidemod.sql @@ -0,0 +1,121 @@ +/* Copyright (c) 2002, 2003, Oracle Corporation. All rights reserved. */ + +/* + NAME + occidemod - SQL Script to drop OCCI demo objects + + DESCRIPTION + SQL Script to drop OCCI demo objects created by occidemo.sql + To be run in the end to drop OCCI demo objects from HR schema + + MODIFIED + sudsrini 03/06/03 - sudsrini_occi_10ir1_demos + sudsrini 02/21/03 - Created + +*/ + +connect hr/hr + +DROP PROCEDURE demo_proc; +DROP FUNCTION demo_fun; + +DROP TABLE elements; +DROP TABLE author_tab; +DROP TABLE publisher_tab; +DROP TABLE publ_address_tab; +DROP TABLE journal_tab; +DROP TABLE article_tab; +DROP TABLE librarian_tab; +DROP TABLE book; +DROP TABLE cover; + +DROP TYPE journal; +DROP TYPE publ_address; +DROP TYPE librarian; +DROP TYPE people_obj; + + +DROP TABLE electronic_media; +DROP TYPE elheader_typ; +DROP TYPE elecdoc_tab; +DROP TYPE elecdoc_typ; + +DROP TABLE foreign_student_tab; +DROP TABLE parttime_stud_tab; +DROP TABLE student_tab; +DROP TABLE people_tab; +DROP TYPE foreign_student; +DROP TYPE parttime_stud; +DROP TYPE student; +DROP TYPE people_typ; + +/* OCCI AQ Object */ + +connect system/manager + +revoke aq_administrator_role from hr; + +connect hr/hr + +BEGIN + dbms_aqadm.stop_queue(queue_name => 'queue01'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue('queue01'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue_table('hr.table01'); +END; +/ + +BEGIN + dbms_aqadm.stop_queue(queue_name => 'queue02'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue('queue02'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue_table('hr.table02'); +END; +/ + +BEGIN + dbms_aqadm.stop_queue(queue_name => 'queue03'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue('queue03'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue_table('hr.table03'); +END; +/ + +BEGIN + dbms_aqadm.stop_queue(queue_name => 'queue04'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue('queue04'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue_table('hr.table04'); +END; +/ + +DROP TYPE hr_obj; + diff --git a/occidesc.cpp b/occidesc.cpp new file mode 100644 index 0000000..22387e2 --- /dev/null +++ b/occidesc.cpp @@ -0,0 +1,400 @@ +/* Copyright (c) 2001, 2008, Oracle. All rights reserved. */ +/* + NAME + occidesc.cpp - Describing the various objects of the database + + DESCRIPTION + This program describes the database objects like table, object and + procedure to get the metadata + + MODIFIED (MM/DD/YY) + mvasudev 05/22/08 - Add try / catch blocks + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/22/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include +using namespace oracle::occi; +using namespace std; + +class occidesc +{ + private: + + Environment *env; + Connection *conn; + public : + /** + * Constructor for the occidesc demo program. + */ + occidesc (string user, string passwd, string db) throw (SQLException) + { + env = Environment::createEnvironment (Environment::OBJECT); + conn = env->createConnection (user, passwd, db); + }// end of constructor occidesc (string, string, string ) + + /** + * Destructor for the occidesc demo program. + */ + ~occidesc () throw (SQLException) + { + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + } // end of ~occidesc () + + // Describing a subtype + void describe_type() + { + cout << "Describing the object - PEOPLE_OBJ"; + MetaData metaData = conn->getMetaData ((char *)"PEOPLE_OBJ"); + int mdTyp = metaData.getInt(MetaData::ATTR_PTYPE); + if (mdTyp == MetaData::PTYPE_TYPE) + { + cout << "PEOPLE_OBJis a type" << endl; + } + int typcode = metaData.getInt(MetaData::ATTR_TYPECODE); + if (typcode == OCCI_TYPECODE_OBJECT) + cout << "PERSON is an object type" << endl; + else + cout << "PERSON is not an object type" << endl; + int numtypeattrs = metaData.getInt(MetaData::ATTR_NUM_TYPE_ATTRS); + cout << "Object has " << numtypeattrs << " attributes" << endl; + try + { + cout << "Object id: " << metaData.getUInt (MetaData::ATTR_OBJ_ID) + << endl; + } + catch (SQLException ex) + { + cout << ex.getMessage() << endl; + } + cout << "Object Name: " << + metaData.getString (MetaData::ATTR_OBJ_NAME) << endl; + cout << "Schema Name: " << + (metaData.getString(MetaData::ATTR_OBJ_SCHEMA)) << endl; + cout << "Attribute version: " << + (metaData.getString(MetaData::ATTR_VERSION)) << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_INCOMPLETE_TYPE)) + cout << "Incomplete type" << endl; + else + cout << "Not Incomplete type" << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_SYSTEM_TYPE)) + cout << "System type" << endl; + else + cout << "Not System type" << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_PREDEFINED_TYPE)) + cout << "Predefined Type" << endl; + else + cout << "Not Predefined Type" << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_TRANSIENT_TYPE)) + cout << "Transient Type" << endl; + else + cout << "Not Transient Type" << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_SYSTEM_GENERATED_TYPE)) + cout << "System-generated type" << endl; + else + cout << "Not System-generated type" << endl; + if (metaData.getBoolean(MetaData::ATTR_HAS_NESTED_TABLE)) + cout << "Has nested table" << endl; + else + cout << "Does not have nested table" << endl; + if (metaData.getBoolean(MetaData::ATTR_HAS_LOB)) + cout << "Has LOB" << endl; + else + cout << "Does not have LOB" << endl; + if (metaData.getBoolean(MetaData::ATTR_HAS_FILE)) + cout << "Has BFILE" << endl; + else + cout << "Does not have BFILE" << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_INVOKER_RIGHTS)) + cout << "Object is Invoker rights" << endl; + else + cout << "Object is Not Invoker rights" << endl; + RefAny ref = metaData.getRef (MetaData::ATTR_REF_TDO); + MetaData md1 = conn->getMetaData (ref); + vector v1 = + md1.getVector (MetaData::ATTR_LIST_TYPE_ATTRS); + + for (int i = 0; i < v1.size (); ++i) + { + MetaData md2 = (MetaData)v1[i]; + cout << "Column Name :" << + (md2.getString(MetaData::ATTR_NAME)) << endl; + cout << " Data Type :" << + (printType (md2.getInt(MetaData::ATTR_DATA_TYPE))) << endl; + cout << " Size :" << md2.getInt(MetaData::ATTR_DATA_SIZE) << endl; + cout << " Precision :" << md2.getInt(MetaData::ATTR_PRECISION) << endl; + cout << " Scale :" << md2.getInt(MetaData::ATTR_SCALE) << endl << endl; + } + + cout << "describe_type - done" << endl; + } // end of describe_type() + + // Describing a table + void describe_table () + { + cout << "Describing the table - _TAB1" << endl; + vector v1; + MetaData metaData = conn->getMetaData("PUBLISHER_TAB"); + cout << "Object name:" << + (metaData.getString(MetaData::ATTR_OBJ_NAME)) << endl; + cout << "Schema:" << + (metaData.getString(MetaData::ATTR_OBJ_SCHEMA)) << endl; + if (metaData.getInt(MetaData::ATTR_PTYPE) == + MetaData::PTYPE_TABLE) + { + cout << "_TAB1 is a table" << endl; + } + else + cout << "_TAB1 is not a table" << endl; + if (metaData.getBoolean(MetaData::ATTR_PARTITIONED)) + cout << "Table is partitioned" << endl; + else + cout << "Table is not partitioned" << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_TEMPORARY)) + cout << "Table is temporary" << endl; + else + cout << "Table is not temporary" << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_TYPED)) + cout << "Table is typed" << endl; + else + cout << "Table is not typed" << endl; + if (metaData.getBoolean(MetaData::ATTR_CLUSTERED)) + cout << "Table is clustered" << endl; + else + cout << "Table is not clustered" << endl; + if (metaData.getBoolean(MetaData::ATTR_INDEX_ONLY)) + cout << "Table is Index-only" << endl; + else + cout << "Table is not Index-only" << endl; + cout << "Duration:"; + switch (metaData.getInt(MetaData::ATTR_DURATION)) + { + case MetaData::DURATION_SESSION : cout << "Connection" << endl; + break; + case MetaData::DURATION_TRANS : cout << "Transaction" << endl; + break; + case MetaData::DURATION_NULL : cout << "Table not temporary" << endl; + break; + } + try + { + cout << "Data Block Address:" << + metaData.getUInt (MetaData::ATTR_RDBA) << endl; + } + catch (SQLException ex) + { + cout << ex.getMessage() << endl; + } + try + { + cout << "Tablespace:" << + metaData.getInt (MetaData::ATTR_TABLESPACE) << endl; + } + catch (SQLException ex) + { + cout << ex.getMessage() << endl; + } + try + { + cout << "Object Id:" << + metaData.getUInt(MetaData::ATTR_OBJID) << endl; + } + catch (SQLException ex) + { + cout << ex.getMessage() << endl; + } + + int columnCount = metaData.getInt(MetaData::ATTR_NUM_COLS); + cout << "Number of Columns : " << columnCount << endl; + + v1 = metaData.getVector(MetaData::ATTR_LIST_COLUMNS); + for(int i=0; i < v1.size(); i++) + { + MetaData md = v1[i]; + cout << " Column Name :" << + (md.getString(MetaData::ATTR_NAME)) << endl; + cout << " Data Type :" << + (printType (md.getInt(MetaData::ATTR_DATA_TYPE))) << endl; + cout << " Size :" << md.getInt(MetaData::ATTR_DATA_SIZE) << endl; + cout << " Precision :" << md.getInt(MetaData::ATTR_PRECISION) << endl; + cout << " Scale :" << md.getInt(MetaData::ATTR_SCALE) << endl; + bool isnull = md.getBoolean(MetaData::ATTR_IS_NULL); + if (isnull) + cout << " Allows null" << endl; + else + cout << " Does not allow null" << endl; + } + cout << "describe_table - done" << endl; + } // end of describe_table () + + // Describing a procedure + void describe_proc () + { + cout << "Describing the procedure - DEMO_PROC" << endl; + MetaData metaData = conn->getMetaData("DEMO_PROC"); + vector v1 = + metaData.getVector ( MetaData::ATTR_LIST_ARGUMENTS ); + cout << "The number of arguments are:" << v1.size() << endl; + cout << "Object Name :" << + (metaData.getString(MetaData::ATTR_OBJ_NAME)) << endl; + cout << "Schema Name :" << + (metaData.getString(MetaData::ATTR_OBJ_SCHEMA)) << endl; + if (metaData.getInt(MetaData::ATTR_PTYPE) == MetaData:: + PTYPE_PROC) + { + cout << "DEMO_PROC is a procedure" << endl; + } + else + { + if (metaData.getInt(MetaData::ATTR_PTYPE) == MetaData:: + PTYPE_FUNC) + { + cout << "HIKE is a function" << endl; + } + } + try + { + cout << "Object Id:" << + metaData.getUInt(MetaData::ATTR_OBJ_ID) << endl; + } + catch (SQLException ex) + { + cout << ex.getMessage() << endl; + } + try + { + cout << "Name :" << + (metaData.getString(MetaData::ATTR_NAME)) << endl; + } + catch (SQLException ex) + { + cout << ex.getMessage() << endl; + } + + if (metaData.getBoolean(MetaData::ATTR_IS_INVOKER_RIGHTS)) + cout << "It is Invoker-rights" << endl; + else + cout << "It is not Invoker-rights" << endl; + cout << "Overload Id:" << + metaData.getInt(MetaData::ATTR_OVERLOAD_ID) << endl; + + for(int i=0; i < v1.size(); i++) + { + MetaData md = v1[i]; + cout << "Column Name :" << + (md.getString(MetaData::ATTR_NAME)) << endl; + cout << "DataType :" << + (printType (md.getInt(MetaData::ATTR_DATA_TYPE))) + << endl; + cout << "Argument Mode:"; + int mode = md.getInt (MetaData::ATTR_IOMODE); + if (mode == 0) + cout << "IN" << endl; + if (mode == 1) + cout << "OUT" << endl; + if (mode == 2) + cout << "IN/OUT" << endl; + cout << "Size :" << + md.getInt(MetaData::ATTR_DATA_SIZE) << endl; + cout << "Precision :" << + md.getInt(MetaData::ATTR_PRECISION) << endl; + cout << "Scale :" << + md.getInt(MetaData::ATTR_SCALE) << endl; + int isNull = md.getInt ( MetaData::ATTR_IS_NULL); + if (isNull != 0) + cout << "Allows null," << endl; + else + cout << "Does not allow null," << endl; + + int hasDef = md.getInt ( MetaData::ATTR_HAS_DEFAULT); + if (hasDef != 0) + cout << "Has Default" << endl; + else + cout << "Does not have Default" << endl; + } + cout << "test1 - done" << endl; + } + + // Method which prints the data type + string printType (int type) + { + switch (type) + { + case OCCI_SQLT_CHR : return "VARCHAR2"; + break; + case OCCI_SQLT_NUM : return "NUMBER"; + break; + case OCCIINT : return "INTEGER"; + break; + case OCCIFLOAT : return "FLOAT"; + break; + case OCCI_SQLT_STR : return "STRING"; + break; + case OCCI_SQLT_VNU : return "VARNUM"; + break; + case OCCI_SQLT_LNG : return "LONG"; + break; + case OCCI_SQLT_VCS : return "VARCHAR"; + break; + case OCCI_SQLT_RID : return "ROWID"; + break; + case OCCI_SQLT_DAT : return "DATE"; + break; + case OCCI_SQLT_VBI : return "VARRAW"; + break; + case OCCI_SQLT_BIN : return "RAW"; + break; + case OCCI_SQLT_LBI : return "LONG RAW"; + break; + case OCCIUNSIGNED_INT : return "UNSIGNED INT"; + break; + case OCCI_SQLT_LVC : return "LONG VARCHAR"; + break; + case OCCI_SQLT_LVB : return "LONG VARRAW"; + break; + case OCCI_SQLT_AFC : return "CHAR"; + break; + case OCCI_SQLT_AVC : return "CHARZ"; + break; + case OCCI_SQLT_RDD : return "ROWID"; + break; + case OCCI_SQLT_NTY : return "NAMED DATA TYPE"; + break; + case OCCI_SQLT_REF : return "REF"; + break; + case OCCI_SQLT_CLOB: return "CLOB"; + break; + case OCCI_SQLT_BLOB: return "BLOB"; + break; + case OCCI_SQLT_FILE: return "BFILE"; + break; + default: return ""; + } + } // End of printType (int) + + +}; // end of class occidesc + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + + cout << "occidesc - Describing the various objects of the database" << endl; + try{ + occidesc *demo = new occidesc (user, passwd, db); + demo->describe_table(); + demo->describe_type(); + demo->describe_proc(); + delete demo; + } + catch (SQLException ex){ + cout << ex.getMessage() << endl; + } + +}// end of main () diff --git a/occidml.cpp b/occidml.cpp new file mode 100644 index 0000000..ec5381c --- /dev/null +++ b/occidml.cpp @@ -0,0 +1,292 @@ +/* Copyright (c) 2001, 2008, Oracle. All rights reserved. */ +/* + NAME + occidml.cpp - Basic DML Operations demo + + DESCRIPTION + To exhibit the insertion, selection, updating and deletion of + a row using OCCI interface + + MODIFIED (MM/DD/YY) + mvasudev 05/22/08 - Add try/catch blocks + sudsrini 10/22/06 - Username/Password lower case + lburgess 04/14/06 - lowercase passwords + sudsrini 07/23/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include +using namespace oracle::occi; +using namespace std; + +class occidml +{ + private: + + Environment *env; + Connection *conn; + Statement *stmt; + public: + + occidml (string user, string passwd, string db) + { + env = Environment::createEnvironment (Environment::DEFAULT); + conn = env->createConnection (user, passwd, db); + } + + ~occidml () + { + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + } + + /** + * Insertion of a row with dynamic binding, PreparedStatement functionality. + */ + void insertBind (int c1, string c2) + { + string sqlStmt = "INSERT INTO author_tab VALUES (:x, :y)"; + stmt=conn->createStatement (sqlStmt); + try{ + stmt->setInt (1, c1); + stmt->setString (2, c2); + stmt->executeUpdate (); + cout << "insert - Success" << endl; + }catch(SQLException ex) + { + cout<<"Exception thrown for insertBind"<terminateStatement (stmt); + } + + /** + * Inserting a row into the table. + */ + void insertRow () + { + string sqlStmt = "INSERT INTO author_tab VALUES (111, 'ASHOK')"; + stmt = conn->createStatement (sqlStmt); + try{ + stmt->executeUpdate (); + cout << "insert - Success" << endl; + }catch(SQLException ex) + { + cout<<"Exception thrown for insertRow"<terminateStatement (stmt); + } + + /** + * updating a row + */ + void updateRow (int c1, string c2) + { + string sqlStmt = + "UPDATE author_tab SET author_name = :x WHERE author_id = :y"; + stmt = conn->createStatement (sqlStmt); + try{ + stmt->setString (1, c2); + stmt->setInt (2, c1); + stmt->executeUpdate (); + cout << "update - Success" << endl; + }catch(SQLException ex) + { + cout<<"Exception thrown for updateRow"<terminateStatement (stmt); + } + + + /** + * deletion of a row + */ + void deleteRow (int c1, string c2) + { + string sqlStmt = + "DELETE FROM author_tab WHERE author_id= :x AND author_name = :y"; + stmt = conn->createStatement (sqlStmt); + try{ + stmt->setInt (1, c1); + stmt->setString (2, c2); + stmt->executeUpdate (); + cout << "delete - Success" << endl; + }catch(SQLException ex) + { + cout<<"Exception thrown for deleteRow"<terminateStatement (stmt); + } + + /** + * displaying all the rows in the table + */ + void displayAllRows () + { + string sqlStmt = "SELECT author_id, author_name FROM author_tab \ + order by author_id"; + stmt = conn->createStatement (sqlStmt); + ResultSet *rset = stmt->executeQuery (); + try{ + while (rset->next ()) + { + cout << "author_id: " << rset->getInt (1) << " author_name: " + << rset->getString (2) << endl; + } + }catch(SQLException ex) + { + cout<<"Exception thrown for displayAllRows"<closeResultSet (rset); + conn->terminateStatement (stmt); + } + + /** + * Inserting a row into elements table. + * Demonstrating the usage of BFloat and BDouble datatypes + */ + void insertElement (string elm_name, float mvol=0.0, double awt=0.0) + { + BFloat mol_vol; + BDouble at_wt; + + if (!(mvol)) + mol_vol.isNull = TRUE; + else + mol_vol.value = mvol; + + if (!(awt)) + at_wt.isNull = TRUE; + else + at_wt.value = awt; + + string sqlStmt = "INSERT INTO elements VALUES (:v1, :v2, :v3)"; + stmt = conn->createStatement (sqlStmt); + + try{ + stmt->setString(1, elm_name); + stmt->setBFloat(2, mol_vol); + stmt->setBDouble(3, at_wt); + stmt->executeUpdate (); + cout << "insertElement - Success" << endl; + }catch(SQLException ex) + { + cout<<"Exception thrown for insertElement"<terminateStatement (stmt); + } + + /** + * displaying rows from element table + */ + void displayElements () + { + string sqlStmt = + "SELECT element_name, molar_volume, atomic_weight FROM elements \ + order by element_name"; + stmt = conn->createStatement (sqlStmt); + ResultSet *rset = stmt->executeQuery (); + try{ + cout.precision(7); + while (rset->next ()) + { + string elem_name = rset->getString(1); + BFloat mol_vol = rset->getBFloat(2); + BDouble at_wt = rset->getBDouble(3); + + cout << "Element Name: " << elem_name << endl; + + if ( mol_vol.isNull ) + cout << "Molar Volume is NULL" << endl; + else + cout << "Molar Volume: " << mol_vol.value << " cm3 mol-1" << endl; + + if ( at_wt.isNull ) + cout << "Atomic Weight is NULL" << endl; + else + cout << "Atomic Weight: " << at_wt.value << " g/mole" << endl; + } + }catch(SQLException ex) + { + cout<<"Exception thrown for displayElements"<closeResultSet (rset); + conn->terminateStatement (stmt); + } + +}; // end of class occidml + + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + try{ + cout << "occidml - Exhibiting simple insert, delete & update operations" + << endl; + occidml *demo = new occidml (user, passwd, db); + cout << "Displaying all records before any operation" << endl; + demo->displayAllRows (); + + cout << "Inserting a record into the table author_tab " + << endl; + demo->insertRow (); + + cout << "Displaying the records after insert " << endl; + demo->displayAllRows (); + + cout << "Inserting a records into the table author_tab using dynamic bind" + << endl; + demo->insertBind (222, "ANAND"); + + cout << "Displaying the records after insert using dynamic bind" << endl; + demo->displayAllRows (); + + cout << "deleting a row with author_id as 222 from author_tab table" << endl; + demo->deleteRow (222, "ANAND"); + + cout << "updating a row with author_id as 444 from author_tab table" << endl; + demo->updateRow (444, "ADAM"); + + cout << "displaying all rows after all the operations" << endl; + demo->displayAllRows (); + + cout << "inserting radio active element properties" << endl; + demo->insertElement ("Uranium", 12.572, 238.0289 ); + demo->insertElement ("Plutonium", 12.12, 244.0642 ); + demo->insertElement ("Curium", 18.17, 247.0703 ); + demo->insertElement ("Thorium"); + demo->insertElement ("Radium", 41.337, 226.0254); + + cout << "displaying all radio active element properties" << endl; + demo->displayElements (); + + delete (demo); + } + catch (SQLException ex){ + cout << ex.getMessage() << endl; + } + cout << "occidml - done" << endl; +} diff --git a/occiinh.cpp b/occiinh.cpp new file mode 100644 index 0000000..b5379b3 --- /dev/null +++ b/occiinh.cpp @@ -0,0 +1,278 @@ +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. */ +/* + NAME + occiinh.cpp - OCCI Object Inheritance demo + + DESCRIPTION + This demo performs all DML operations using OCCI interface + on the objects + Object Hierarchy + people_typ <---- student <----- parttime_stud <----- foreign_student + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/23/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include +using namespace oracle::occi; +using namespace std; + +#include "occiinhm.h" + +/* Add on your methods in this class*/ +class foreign_student_obj : public foreign_student +{ + /* New methods can be added here */ +}; + +class occiinh +{ + private: + + Environment *env; + Connection *con; + + // This method will return the Ref + RefAny getRefObj(string sqlString) + { + Statement *stmt = con->createStatement (sqlString); + ResultSet *rs; + try + { + rs = stmt->executeQuery (); + if ( rs->next() ) + { + RefAny ref1 = rs->getRef (1); + stmt->closeResultSet (rs); + con->terminateStatement (stmt); + return ref1; + } + } + catch(SQLException ex) + { + cout << "Error in fetching ref" << endl; + } + stmt->closeResultSet (rs); + con->terminateStatement (stmt); + return RefAny(); + } + + + public: + + occiinh (string user, string passwd, string db) + throw (SQLException) + { + env = Environment::createEnvironment (Environment::OBJECT); + occiinhm(env); + con = env->createConnection (user, passwd, db); + }// end of constructor occiinh (string, string, string) + + ~occiinh () + throw (SQLException) + { + env->terminateConnection (con); + Environment::terminateEnvironment (env); + }// end of destructor + + /** + * Insertion of a row + */ + void insertRow () + throw (SQLException) + { + cout << "Inserting a record (joe)" << endl; + string sqlStmt = + "INSERT INTO foreign_student_tab VALUES(:a)"; + Statement *stmt = con->createStatement (sqlStmt); + string fs_name = "joe"; + Number fs_ssn (4); + Date fs_dob(env, 2000, 5, 11, 16, 05, 0); + Number fs_stud_id (400); + Ref< people_typ > fs_teammate = getRefObj( + "SELECT REF(a) FROM people_tab a where name='john'"); + Number fs_course_id(4000); + Ref< student > fs_partner = getRefObj( + "SELECT REF(a) FROM student_tab a"); + string fs_country = "india"; + Ref< parttime_stud > fs_leader = getRefObj( + "SELECT REF(a) FROM parttime_stud_tab a"); + foreign_student_obj *fs_obj = new foreign_student_obj (); + fs_obj->setname(fs_name); + fs_obj->setssn(fs_ssn); + fs_obj->setdob(fs_dob); + fs_obj->setstud_id(fs_stud_id); + fs_obj->setteammate(fs_teammate); + fs_obj->setcourse_id(fs_course_id); + fs_obj->setpartner(fs_partner); + fs_obj->setcountry(fs_country); + fs_obj->setleader(fs_leader); + stmt->setObject(1, fs_obj); + stmt->executeUpdate(); + + con->terminateStatement (stmt); + delete fs_obj; + cout << "Insertion Successful" << endl; + }// end of insertRow (); + + + /** + * updating a row + */ + void updateRow () + throw (SQLException) + { + cout << "Upadating record (Changing name,teammate and course_id)" << endl; + string sqlStmt = + "UPDATE foreign_student_tab SET name=:x, teammate=:y, course_id=:z"; + Statement *stmt = con->createStatement (sqlStmt); + string fs_name = "jeffree"; + Ref< people_typ > fs_teammate = getRefObj( + "SELECT REF(a) FROM people_tab a where name='jill'"); + Number fs_course_id(5000); + stmt->setString(1, fs_name); + stmt->setRef(2,fs_teammate); + stmt->setInt(3, fs_course_id); + stmt->executeUpdate (); + con->commit(); + con->terminateStatement (stmt); + cout << "Updation Successful" << endl; + }// end of updateRow (int, string); + + + /** + * deletion of a row + */ + void deleteRow () + throw (SQLException) + { + cout << "Deletion of jeffree record " << endl; + string sqlStmt = "DELETE FROM foreign_student_tab where name=:x"; + Statement *stmt = con->createStatement (sqlStmt); + string fs_name = "jeffree"; + stmt->setString(1,fs_name); + stmt->executeUpdate(); + con->commit(); + con->terminateStatement (stmt); + cout << "Deletion Successful" << endl; + }// end of deleteRow (int, string); + + /** + * displaying all the rows in the table + */ + void displayAllRows () + throw (SQLException) + { + int count=0; + string sqlStmt = "SELECT REF(a) FROM foreign_student_tab a"; + Statement *stmt = con->createStatement (sqlStmt); + ResultSet *resultSet = stmt->executeQuery (); + + while (resultSet->next ()) + { + count++; + RefAny fs_refany = resultSet->getRef(1); + Ref fs_ref(fs_refany); + fs_ref.setPrefetch(4); + string fmt = "DD-MON-YYYY"; + string nlsParam = "NLS_DATE_LANGUAGE = American"; + Date fs_dob = fs_ref->getdob(); + string date1 = fs_dob.toText (fmt, nlsParam); + cout << "Foreign Student Information" << endl; + cout << "Name : " << fs_ref->getname(); + cout << " SSN : " << (int)fs_ref->getssn(); + cout << " DOB : " << date1 << endl; + cout << "Stud id : " << (int)fs_ref->getstud_id() ; + cout << " Course id : " << (int)fs_ref->getcourse_id(); + cout << " Country : " << fs_ref->getcountry() < fs_teammate = (Ref ) + fs_ref->getteammate(); + cout << "Teammate's Information " << endl; + cout << "Name : " << fs_teammate->getname(); + cout << " SSN : " << (int)fs_teammate->getssn(); + fs_dob = fs_teammate->getdob(); + date1 = fs_dob.toText(fmt, nlsParam); + cout << " DOB : " << date1 << endl << endl; + /* Leader */ + Ref< parttime_stud > fs_leader = (Ref < parttime_stud >) + fs_ref->getleader(); + /* Leader's Partner */ + Ref < student > fs_partner = (Ref ) + fs_leader->getpartner(); + /* Leader's Partenr's teammate */ + fs_teammate = (Ref ) fs_partner->getteammate(); + + cout << "Leader Information " << endl; + cout << "Name : " << fs_leader->getname(); + cout << " SSN : " << (int)fs_leader->getssn(); + fs_dob = fs_leader->getdob(); + date1 = fs_dob.toText(fmt, nlsParam); + cout << " DOB : " << date1 << endl; + cout << "Stud id : " << (int)fs_leader->getstud_id(); + cout << " Course id : " << (int)fs_leader->getcourse_id() << endl; + + cout << "Leader's Partner's Information " << endl; + cout << "Name : " << fs_partner->getname() ; + cout << " SSN : " << (int)fs_partner->getssn(); + fs_dob = fs_partner->getdob(); + date1 = fs_dob.toText(fmt, nlsParam); + cout << " DOB : " << date1 ; + cout << " Stud id : " << (int)fs_partner->getstud_id() << endl; + + + cout << "Leader's Partner's Teammate's Information " << endl; + cout << "Name : " << fs_teammate->getname(); + cout << " SSN : " << (int)fs_teammate->getssn(); + fs_dob = fs_teammate->getdob(); + date1 = fs_dob.toText(fmt, nlsParam); + cout << " DOB : " << date1 << endl << endl; + + }//end of while (resultSet->next ()); + if (count <=0) + cout << "No record found " << endl; + stmt->closeResultSet (resultSet); + con->terminateStatement (stmt); + }// end of updateRow (string); + +}; // end of class occiinh + + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + + try + { + cout << "occiinh - Exhibiting simple insert, delete & update operations" + " on Oracle objects" << endl; + occiinh *demo = new occiinh (user, passwd, db); + + cout << "displaying all rows before operations" << endl; + demo->displayAllRows (); + + demo->insertRow (); + cout << "displaying all rows after insertions" << endl; + demo->displayAllRows (); + + demo->updateRow (); + cout << "displaying all rows after updations" << endl; + demo->displayAllRows (); + + demo->deleteRow (); + cout << "displaying all rows after deletions" << endl; + demo->displayAllRows (); + + + delete (demo); + cout << "occiinh - done" << endl; + }catch (SQLException ea) + { + cerr << "Error running the demo: " << ea.getMessage () << endl; + } +}// end of int main (void); diff --git a/occiinh.typ b/occiinh.typ new file mode 100644 index 0000000..774d6af --- /dev/null +++ b/occiinh.typ @@ -0,0 +1,3 @@ +CASE=LOWER +MAPFILE=occiinhm.cpp +TYPE FOREIGN_STUDENT as foreign_student diff --git a/occilbar.cpp b/occilbar.cpp new file mode 100644 index 0000000..3404789 --- /dev/null +++ b/occilbar.cpp @@ -0,0 +1,400 @@ +/* Copyright (c) 2004, 2006, Oracle. All rights reserved. */ +/* + NAME + occilbar.cpp - OCCI Support for reading/writing arrays of LOB's. + + DESCRIPTION + To exhibit OCCI Support for reading/writing arrays of LOB's. + Create a table with BLOB, CLOB column. + Populate the values in the table by using new LOB Array Write method + Retrieve the values from the table by using the LOB Array Read method + + 1. readVectorOfBlobs() + 2. readVectorOfClobs() + 3. writeVectorOfBlobs() + 4. writeVectorOfClobs() + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + kukannan 09/21/04 - Include iostream + sudsrini 07/22/04 - Copyright Info + debanerj 06/04/04 - debanerj_13064_lob_array_read + kukannan 05/26/04 - Creation +*/ + +#include +#include +#include +using namespace oracle::occi; +using namespace std; + +#define NO_OF_LOBS 10 + +class lobarray +{ + private: + + Environment *env; + Connection *conn; + + public: + + lobarray (string user, string passwd, string db) + { + env = Environment::createEnvironment (Environment::DEFAULT); + conn = env->createConnection (user, passwd, db); + } + + /** + * Destructor for the lobarray test case. + */ + ~lobarray () + { + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + } // end of ~lobarray () + + /** + * Creating schema objects. + */ + dvoid createTables () + { + string sqlstr1 = "CREATE TABLE lobarray_tab"; + sqlstr1 += " (c1 NUMBER, c2 BLOB, c3 CLOB)"; + Statement *stmt = conn->createStatement(sqlstr1); + stmt->execute(); + } // end of createTables () + + /** + * Removing schema objects created. + */ + dvoid dropTable () + { + Statement *stmt= conn->createStatement("DROP TABLE lobarray_tab"); + stmt->execute(); + } // end of cleanup () + + /** + * The testing logic of the test case. + */ + dvoid test () + { + cout << "lobarray - Testing the OCCI Array LOB Api's" << endl; + createTables (); + + Statement *stmt = conn->createStatement(""); + + char stmt_str[500]; + for (int i=0; iexecute ((const char *)stmt_str); + } + conn->terminateStatement (stmt); + + writeArrayBlob (); + readArrayBlob (); + + cout << "Writing into clob by mentioning character amts " << endl; + writeArrayClob (1); + cout << "Reading from clob by mentioning character amts " << endl; + readArrayClob (1); + + cout << "Writing into clob by mentioning byte amts " << endl; + writeArrayClob (2); + cout << "Reading from clob by mentioning byte amts " << endl; + readArrayClob (2); + + dropTable (); + cout << "lobarray - done" << endl; + } // end of test() + + /************************************************************/ + /* writeArrayBlob() */ + /************************************************************/ + /*Select all the Lob Locators from Blob col from the table. */ + /*Push these Lob Locators in a Vector of Blobs. */ + /*Call populate_buffer function which would populate the */ + /*amount of data to be written, sets the offsets, populates */ + /*the buffer. */ + /*Call writeVectorOfBlobs with the populate buffer,amount */ + /*and offset value. This would write the buffered values */ + /*into respective lobs. Do and connection commit and release*/ + /*the allocated memory. */ + /************************************************************/ + + void writeArrayBlob () + { + cout << "Writing Array Lob using writeVectorofBlobs" << endl; + char stmt_str[500]; + + vector lob_vec; + sprintf(stmt_str,"Select c2 from lobarray_tab for update"); + Statement *stmt = conn->createStatement((const char *)stmt_str); + ResultSet *rs = stmt->executeQuery(); + + while (rs->next()) + lob_vec.push_back(rs->getBlob(1)); + + stmt->closeResultSet(rs); + conn->terminateStatement(stmt); + + oraub8 byte_amts[NO_OF_LOBS]; + oraub8 offsets[NO_OF_LOBS]; + unsigned char *buffers[NO_OF_LOBS]; + oraub8 buffer_lens[NO_OF_LOBS]; + + populate_buffer(byte_amts,offsets, buffers,buffer_lens,1); + writeVectorOfBlobs(conn,lob_vec,byte_amts,offsets,buffers,buffer_lens); + conn->commit(); + release_memory(buffers); + cout << "Writing - Done" << endl; + } + /************************************************************/ + /* writeArrayClob() */ + /************************************************************/ + /*Select all the Lob Locators from Clob col from the table. */ + /*Push these Lob Locators in a Vector of Clobs. */ + /*Call populate_buffer function which would populate the */ + /*amount of data to be written, sets the offsets, populates */ + /*the buffer. */ + /*Call writeVectorOfClobs with the populated buffer,amount */ + /*and offset value. This would write the buffered values */ + /*into respective lobs. Do and connection commit and release*/ + /*the allocated memory. */ + /*The type variable differentiates the attributes based on */ + /*which the value gets inserted into the Clob. */ + /*A value of 1 for the TYPE variable means that the */ + /*of CHARACTER gets inserted into the Lobs. */ + /*A value of 2 for the TYPE variable means that the */ + /*of BYTES gets inserted into the Lobs. */ + /************************************************************/ + + void writeArrayClob (int type) + { + char stmt_str[500]; + + vector lob_vec; + sprintf(stmt_str,"Select c3 from lobarray_tab for update"); + Statement *stmt = conn->createStatement((const char *)stmt_str); + ResultSet *rs = stmt->executeQuery(); + + // Got all the loblocator and pushed in to the vector + while (rs->next()) + lob_vec.push_back(rs->getClob(1)); + + stmt->closeResultSet(rs); + conn->terminateStatement(stmt); + + oraub8 amts[NO_OF_LOBS]; + oraub8 offsets[NO_OF_LOBS]; + unsigned char *buffers[NO_OF_LOBS]; + oraub8 buffer_lens[NO_OF_LOBS]; + populate_buffer(amts,offsets, buffers,buffer_lens,1); + + /**************************************************************/ + /*Populating the Lob by passing Character amounts if type = 1 */ + /*Populating the Lob by passing Byte amounts if type = 2 */ + /**************************************************************/ + + if (type==1) + { + writeVectorOfClobs(conn,lob_vec,NULL,amts,offsets,\ + buffers,buffer_lens); + } + else + { + writeVectorOfClobs(conn,lob_vec,amts,NULL,offsets,\ + buffers,buffer_lens); + } + conn->commit(); + release_memory(buffers); + cout << "Writing - Done" << endl; + } + /************************************************************/ + /* readArrayBlob() */ + /************************************************************/ + /*Select all the Lob Locators from Blob col from the table. */ + /*Push these Lob Locators in a Vector of Blobs. */ + /*Call populate_buffer function which would assign the */ + /*the offsets, allocate memory for the buffer for */ + /*readVectorOfBlobs to read the value into. */ + /*Call readVectorOfBlobs with the populated amount and */ + /*offset value. This would read the LOB data into the */ + /*allocated buffers. Print the buffers by calling */ + /*print_buffers() and release the allocated memory. */ + /************************************************************/ + + + void readArrayBlob () + { + cout << "Reading Array Lob using readVectorofBlob" << endl; + char stmt_str[500]; + + vector lob_vec; + sprintf(stmt_str,"Select c2 from lobarray_tab order by c1"); + Statement *stmt = conn->createStatement((const char *)stmt_str); + ResultSet *rs = stmt->executeQuery(); + + while (rs->next()) + lob_vec.push_back(rs->getBlob(1)); + + stmt->closeResultSet(rs); + conn->terminateStatement(stmt); + + oraub8 read_amts[NO_OF_LOBS]; + oraub8 offsets[NO_OF_LOBS]; + unsigned char *buffers[NO_OF_LOBS]; + oraub8 buffer_lens[NO_OF_LOBS]; + populate_buffer(read_amts,offsets, buffers,buffer_lens,0); + + readVectorOfBlobs(conn,lob_vec,read_amts,offsets,buffers,buffer_lens); + + print_buffer(buffers,read_amts); + release_memory(buffers); + cout << "Reading - Done " << endl; + } + /************************************************************/ + /* readArrayClob() */ + /************************************************************/ + /*Select all the Lob Locators from Clob col from the table. */ + /*Push these Lob Locators in a Vector of Clobs. */ + /*Call populate_buffer function which would assign the */ + /*the offsets, allocate memory for the buffer for */ + /*readVectorOfClobs to read the value into. */ + /*Call readVectorOfClobs with the populated amount and */ + /*offset value. This would read the LOB data into the */ + /*allocated buffers.Print the buffers by calling */ + /*print_buffers() and release the allocated memory. */ + /*A value of 1 for the TYPE variable means that the */ + /*of CHARACTER gets inserted into the Lobs. */ + /*A value of 2 for the TYPE variable means that the */ + /*of BYTES gets inserted into the Lobs. */ + /************************************************************/ + + + void readArrayClob (int type) + { + char stmt_str[500]; + + vector lob_vec; + sprintf(stmt_str,"Select c3 from lobarray_tab order by c1"); + Statement *stmt = conn->createStatement((const char *)stmt_str); + ResultSet *rs = stmt->executeQuery(); + + while (rs->next()) + lob_vec.push_back(rs->getClob(1)); + + stmt->closeResultSet(rs); + conn->terminateStatement(stmt); + + oraub8 read_amts[NO_OF_LOBS]; + oraub8 offsets[NO_OF_LOBS]; + unsigned char *buffers[NO_OF_LOBS]; + oraub8 buffer_lens[NO_OF_LOBS]; + populate_buffer(read_amts,offsets,buffers,buffer_lens,0); + + if (type==1) + readVectorOfClobs(conn,lob_vec,NULL,read_amts,offsets,\ + buffers,buffer_lens); + else if (type==2) + readVectorOfClobs(conn,lob_vec,read_amts,NULL,offsets,\ + buffers,buffer_lens); + + print_buffer(buffers,read_amts); + release_memory(buffers); + cout << "Reading - Done " << endl; + } + + /************************************************************/ + /* populate_buffer() */ + /************************************************************/ + /*This function assign the offsets,buffer_lens,buffer_amts */ + /*for each Lob.Allocates memory for each buffer and populate*/ + /*buffer for each Lob. The significance of Idx is to */ + /*differentiate the calls made while reading or writing the */ + /*Lob Data. Reading/Writing Lobs require offset,amts and */ + /*buffer_lens for each Lob. */ + /*Idx=1 means the function is called prior to writing into */ + /*the LOB and populates the buffer */ + /*Idx=1 means the function is called prior to reading from */ + /*the LOB and donot populate the buffer */ + /************************************************************/ + + void populate_buffer(oraub8 *amts,oraub8 *offsets,unsigned char **buffers,\ + oraub8 *buffer_lens,int idx) + { + for (int i=0; i < NO_OF_LOBS ; i++) + { + offsets[i]=1; + buffer_lens[i]=i+1; //Writing upto multiples of 5 + amts[i]=buffer_lens[i]; + buffers[i]=new unsigned char[buffer_lens[i]]; + + if (idx!=0) + { + for (int j=0; jtest (); + } + catch (SQLException ea) + { + cout<<"Exception thrown by test Function" < occimb1.html + + MODIFIED (MM/DD/YY) + sudsrini 03/07/08 - order by for deterministic output + sudsrini 10/22/06 - Username/Password lower case + kukannan 03/12/06 - Fix bug 5074203 + sudsrini 07/23/04 - Copyright Info + shiyer 03/05/03 - Creation + +*/ + +#include +#include + +using namespace std; +using namespace oracle::occi; + + +int main() +{ + //part1 - use ZHT16BIG5 characterset + try + { + cout << "Creating environment with ZHT16BIG5(Chinese) characterset
" << endl; + Environment *big5env = Environment::createEnvironment("ZHT16BIG5","ZHT16BIG5"); + + Connection *conn = big5env->createConnection("hr", "hr"); + + cout << "Inserting some information in Chinese - Periodic table elements
" << endl; + + Statement *stmt = + conn->createStatement("INSERT INTO GLOBALINFO_TAB VALUES (:1, :2 ,:3)"); + + stmt->setString(1,"Chinese"); + stmt->setString(2,"Periodic Table Elements"); + + //the code-points in ZHT16BIG5 for the symbols + const char siliconsym[] = {0xD6,0xBA,0x00}; + const char goldsym[] = {0xAA,0xF7,0x00}; + const char calciumsym[] = {0xE0,0xB3,0x00}; + + string info; + info += "Silicon = "; + info += siliconsym; + info += " Gold = "; + info += goldsym; + info += " Calcium = "; + info += calciumsym; + stmt->setString(3,info); + + stmt->executeUpdate(); + conn->commit(); + + conn->terminateStatement(stmt); + big5env->terminateConnection(conn); + Environment::terminateEnvironment(big5env); + } + catch (SQLException &e) + { + cout << "Error : "; + cout << e.getMessage() << endl; + } + + //part2 - use EL8ISO8859P7(Greek) characterset + try + { + cout << "Now creating environment with EL8ISO8859P7(Greek) characterset
" << endl; + Environment *greekenv= Environment::createEnvironment("EL8ISO8859P7","EL8ISO8859P7"); + + Connection *conn = greekenv->createConnection("hr", "hr"); + + cout << "Inserting some information in Greek - Mathematical symbols
" << endl; + + Statement *stmt = + conn->createStatement("INSERT INTO GLOBALINFO_TAB VALUES (:1, :2 ,:3)"); + + stmt->setString(1,"Greek"); + stmt->setString(2,"Mathematical symbols"); + + string info; + info += "alpha = "; + info += "á";//codepoint - 0xE1 in EL8ISO8859P7 + info += " beta = "; + info += "â";//codepoint - 0xE2 + info += " gamma = "; + info += "ã";//codepoint - 0xE3 + info += " delta = "; + info += "ä";//codepoint - 0xE4 + info += " epsilon = "; + info += "å";//codepoint - 0xE5 + stmt->setString(3,info); + stmt->executeUpdate(); + conn->commit(); + } + catch (SQLException &e) + { + cout << "Error : "; + cout << e.getMessage() << endl; + } + + //part3 - use UTF8 characterset and retrieve the data we have inserted + try + { + cout << "Now creating environment with UTF8 characterset
" << endl; + Environment *utf8env= Environment::createEnvironment("UTF8","UTF8"); + + Connection *conn = utf8env->createConnection("hr","hr"); + + cout << "Retrieveing the Chinese & Greek information inserted
" << endl; + + Statement *stmt = + conn->createStatement("SELECT G_LANG, G_INFODESC, G_INFO FROM GLOBALINFO_TAB ORDER BY G_LANG"); + ResultSet *rs = stmt->executeQuery(); + + cout << +"The Unicode data will not display correctly in terminal. \ +To properly view, pipe the output of this program to a text file. \ +Open this text file from a Web browser and set \ +Encoding/Characterset to UTF8
" << endl; + + cout << "=========================================
" << endl; + + while (rs->next()) + { + cout << rs->getString(1) << "," << rs->getString(2) << ","; + cout << rs->getString(3); //Chinese/Greek Info + + cout << "
" << endl; //HTML formatting tag + } + + cout << "=========================================
" << endl; + + stmt->closeResultSet(rs); + conn->terminateStatement(stmt); + + utf8env->terminateConnection(conn); + Environment::terminateEnvironment(utf8env); + + } + catch (SQLException &e) + { + cout << "Error : "; + cout << e.getMessage() << endl; + } + + return 0; +} diff --git a/occimb1.sql b/occimb1.sql new file mode 100644 index 0000000..06a3b13 --- /dev/null +++ b/occimb1.sql @@ -0,0 +1,31 @@ +/* Copyright (c) 2003, 2004, Oracle Corporation. All rights reserved. */ +/* + + NAME + occimb1.sql - Create Objects for OCCI Globalization demo + + DESCRIPTION + + This sql script creates objects for occi multibyte demo + This program assumes sample HR schema is setup. + + NOTES + The database characterset must be UTF8. + + MODIFIED (MM/DD/YY) + sudsrini 08/02/04 - Copyright Info + shiyer 03/05/03 - Creation + +*/ + +connect hr/hr; + +drop table globalinfo_tab; + +create table globalinfo_tab +( + g_lang varchar2(10), + g_infodesc varchar2(50), + g_info varchar2(100) +); + diff --git a/occiobj.cpp b/occiobj.cpp new file mode 100644 index 0000000..499595a --- /dev/null +++ b/occiobj.cpp @@ -0,0 +1,196 @@ +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. */ +/* + NAME + occiobj.cpp - OCCI Embedded Object demo + + DESCRIPTION + This demo performs all DML operations using OCCI interface + on embedded object column of table + + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + lburgess 04/14/06 - lowercase passwords + sudsrini 07/23/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include "occiobjm.h" + +using namespace oracle::occi; +using namespace std; + +class occiobj +{ + private: + + Environment *env; + Connection *con; + Statement *stmt; + public: + + occiobj (string user, string passwd, string db) + { + env = Environment::createEnvironment (Environment::OBJECT); + occiobjm (env); + con = env->createConnection (user, passwd, db); + } + + ~occiobj () + { + env->terminateConnection (con); + Environment::terminateEnvironment (env); + } + + /** + * Insertion of a row + */ + void insertRow (int c1, int a1, string a2) + { + cout << "Inserting record - Publisher id :" << c1 << + ", Publisher address :" << a1 << ", " << a2 <createStatement (sqlStmt); + stmt->setInt (1, c1); + address *o = new address (); + o->setStreet_no (Number (a1)); + o->setCity (a2); + stmt->setObject (2, o); + stmt->executeUpdate (); + cout << "Insert - Success" << endl; + delete (o); + }catch(SQLException ex) + { + cout<<"Exception thrown for insertRow"<terminateStatement (stmt); + } + + + /** + * updating a row + */ + void updateRow (int c1, int a1, string a2) + { + cout << "Upadating record with publisher id :"<< c1 << endl; + string sqlStmt = + "UPDATE publisher_tab SET publisher_add= :x WHERE publisher_id = :y"; + try{ + stmt = con->createStatement (sqlStmt); + address *o = new address (); + o->setStreet_no (Number (a1)); + o->setCity (a2); + stmt->setObject (1, o); + stmt->setInt (2, c1); + stmt->executeUpdate (); + cout << "Update - Success" << endl; + delete (o); + }catch(SQLException ex) + { + cout<<"Exception thrown for updateRow"<terminateStatement (stmt); + } + + + /** + * deletion of a row + */ + void deleteRow (int c1, int a1, string a2) + { + cout << "Deletion of record where publisher id :" << c1 <createStatement (sqlStmt); + stmt->setInt (1, c1); + + address *o = new address (); + o->setStreet_no (Number (a1)); + o->setCity (a2); + stmt->setObject (2, o); + stmt->executeUpdate (); + cout << "Delete - Success" << endl; + delete (o); + }catch(SQLException ex) + { + cout<<"Exception thrown for deleteRow"<terminateStatement (stmt); + } + + /** + * displaying all the rows in the table + */ + void displayAllRows () + { + string sqlStmt = "SELECT publisher_id, publisher_add FROM publisher_tab \ + order by publisher_id"; + try{ + stmt = con->createStatement (sqlStmt); + ResultSet *rset = stmt->executeQuery (); + + while (rset->next ()) + { + cout << "publisher id: " << rset->getInt (1) + << " publisher address: address (" ; + address *o = (address *)rset->getObject (2); + cout << (int)o->getStreet_no () << ", " << o->getCity () << ")" << endl; + } + + stmt->closeResultSet (rset); + }catch(SQLException ex) + { + cout<<"Exception thrown for displayAllRows"<terminateStatement (stmt); + } + +};//end of class occiobj; + + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + + try + { + cout << "occiobj - Exhibiting simple insert, delete & update operations" + " on Oracle objects" << endl; + occiobj *demo = new occiobj (user, passwd, db); + + cout << "displaying all rows before operations" << endl; + demo->displayAllRows (); + + demo->insertRow (12, 122, "MIKE"); + + demo->deleteRow (11, 121, "ANNA"); + + demo->updateRow (23, 123, "KNUTH"); + + cout << "displaying all rows after all operations" << endl; + demo->displayAllRows (); + + delete (demo); + cout << "occiobj - done" << endl; + }catch (SQLException ea) + { + cerr << "Error running the demo: " << ea.getMessage () << endl; + } +} diff --git a/occiobj.typ b/occiobj.typ new file mode 100644 index 0000000..dd788cd --- /dev/null +++ b/occiobj.typ @@ -0,0 +1,3 @@ +CASE=SAME +MAPFILE=occiobjm.cpp +TYPE publ_address as address diff --git a/occipobj.cpp b/occipobj.cpp new file mode 100644 index 0000000..3961049 --- /dev/null +++ b/occipobj.cpp @@ -0,0 +1,199 @@ +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. */ +/* + NAME + occipobj.cpp - OCCI Objects demo using Navigational Access + + DESCRIPTION + This demo uses OCCI navigational access for manipulating persistent + objects demonstrating pinning, unpinning, marking for flush and delete + + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/23/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include "occipobjm.h" + +using namespace oracle::occi; +using namespace std; + +class occipobj +{ + private: + + Environment *env; + Connection *conn; + Statement *stmt; + string tableName; + string typeName; + + public: + + occipobj (string user, string passwd, string db) + { + env = Environment::createEnvironment (Environment::OBJECT); + occipobjm (env); + conn = env->createConnection (user, passwd, db); + } + + ~occipobj () + { + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + } + + void setTableName (string s) + { + tableName = s; + } + + /** + * Insertion of a row + */ + void insertRow (int a1, string a2) + { + cout << "Inserting row ADDRESS (" << a1 << ", " << a2 << ")" << endl; + Number n1(a1); + address *o = new (conn, tableName) address(); + o->setStreet_no(n1); + o->setCity(a2); + conn->commit (); + cout << "Insertion - Successful" << endl; + } + + /** + * updating a row + */ + void updateRow (int b1, int a1, string a2) + { + cout << "Updating a row with attribute a1 = " << b1 << endl; + stmt = conn->createStatement + ("SELECT REF(a) FROM publ_address_tab a WHERE street_no = :x FOR UPDATE"); + stmt->setInt (1, b1); + ResultSet *rs = stmt->executeQuery (); + try{ + if ( rs->next() ) + { + RefAny rany = rs->getRef (1); + Ref

r1(rany); + address *o = r1.ptr(); + o->markModified (); + o->setStreet_no (Number (a1)); + o->setCity (a2); + o->flush (); + } + }catch(SQLException ex) + { + cout<<"Exception thrown updateRow"<commit (); + stmt->closeResultSet(rs); + conn->terminateStatement (stmt); + cout << "Updation - Successful" << endl; + } + + + /** + * deletion of a row + */ + void deleteRow (int a1, string a2) + { + cout << "Deleting a row with object ADDRESS (" << a1 << ", " << a2 + << ")" << endl; + stmt = conn->createStatement + ("SELECT REF(a) FROM publ_address_tab a WHERE street_no = :x AND city = :y FOR UPDATE"); + stmt->setInt (1, a1); + stmt->setString (2, a2); + ResultSet *rs = stmt->executeQuery (); + try{ + if ( rs->next() ) + { + RefAny rany = rs->getRef (1); + Ref
r1(rany); + address *o = r1.ptr(); + o->markDelete (); + } + }catch(SQLException ex) + { + cout<<"Exception thrown for deleteRow"<commit (); + stmt->closeResultSet(rs); + conn->terminateStatement (stmt); + cout << "Deletion - Successful" << endl; + } + + /** + * displaying all the rows in the table + */ + void displayAllRows () + { + string sqlStmt = "SELECT REF (a) FROM publ_address_tab a \ + ORDER BY street_no"; + stmt = conn->createStatement (sqlStmt); + ResultSet *rset = stmt->executeQuery (); + try{ + while (rset->next ()) + { + RefAny rany = rset->getRef (1); + Ref
r1(rany); + address *o = r1.ptr(); + cout << "ADDRESS(" << (int)o->getStreet_no () << ", " << o->getCity () << ")" << endl; + } + }catch(SQLException ex) + { + cout<<"Exception thrown for displayAllRows"<closeResultSet (rset); + conn->terminateStatement (stmt); + } + +}; // end of class occipobj + + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + + try + { + cout << "occipobj - Exhibiting simple insert, delete & update operations" + " on persistent objects" << endl; + occipobj *demo = new occipobj (user, passwd, db); + + cout << "Displaying all rows before the opeations" << endl; + demo->displayAllRows (); + + demo->setTableName ("PUBL_ADDRESS_TAB"); + + demo->insertRow (21, "KRISHNA"); + + demo->deleteRow (22, "BOSTON"); + + demo->updateRow (33, 123, "BHUMI"); + + cout << "Displaying all rows after all the operations" << endl; + demo->displayAllRows (); + + delete (demo); + cout << "occipobj - done" << endl; + }catch (SQLException ea) + { + cerr << "Error running the demo: " << ea.getMessage () << endl; + } +} diff --git a/occipobj.typ b/occipobj.typ new file mode 100644 index 0000000..8d53132 --- /dev/null +++ b/occipobj.typ @@ -0,0 +1,3 @@ +CASE=SAME +MAPFILE=occipobjm.cpp +TYPE publ_address as address diff --git a/occipool.cpp b/occipool.cpp new file mode 100644 index 0000000..bde834b --- /dev/null +++ b/occipool.cpp @@ -0,0 +1,129 @@ +/* Copyright (c) 2001, 2008, Oracle. All rights reserved. */ +/* + NAME + occipool.cpp - OCCI Connection Pool Interface demo + + DESCRIPTION : + This program demonstates creating and using of connection pool + + Make sure setup file, occidemo.sql is run prior to running this program. + + MODIFIED (MM/DD/YY) + mvasudev 05/23/08 - Add try/catch blocks + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/23/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include +using namespace oracle::occi; +using namespace std; + +class occipool +{ + private: + + Environment *env; + Connection *con; + Statement *stmt; + public : + /** + * Constructor for the occipool test case. + */ + occipool () + { + env = Environment::createEnvironment (Environment::DEFAULT); + }// end of constructor occipool () + + /** + * Destructor for the occipool test case. + */ + ~occipool () + { + Environment::terminateEnvironment (env); + } // end of ~occipool () + + /** + * The testing logic of the test case. + */ + dvoid select () + { + cout << "occipool - Selecting records using ConnectionPool interface" << + endl; + const string poolUserName = "hr"; + const string poolPassword = "hr"; + const string connectString = ""; + const string username = "hr"; + const string passWord = "hr"; + unsigned int maxConn = 5; + unsigned int minConn = 3; + unsigned int incrConn = 2; + ConnectionPool *connPool; + try{ + connPool = env->createConnectionPool + (poolUserName, poolPassword, connectString, minConn, maxConn, incrConn); + if (connPool) + cout << "SUCCESS - createConnectionPool" << endl; + else + cout << "FAILURE - createConnectionPool" << endl; + con = connPool->createConnection (username, passWord); + if (con) + cout << "SUCCESS - createConnection" << endl; + else + cout << "FAILURE - createConnection" << endl; + }catch(SQLException ex) + { + cout<<"Exception thrown for createConnectionPool"<createStatement + ("SELECT author_id, author_name FROM author_tab"); + ResultSet *rset = stmt->executeQuery(); + while (rset->next()) + { + cout << "author_id:" << rset->getInt (1) << endl; + cout << "author_name:" << rset->getString (2) << endl; + } + stmt->closeResultSet (rset); + con->terminateStatement (stmt); + connPool->terminateConnection (con); + env->terminateConnectionPool (connPool); + }catch(SQLException ex) + { + cout<<"Exception thrown for retrieving data"<select(); + delete demo; + } + catch(SQLException ex) + { + cout< +#include +using namespace oracle::occi; +using namespace std; + +class occiproc +{ + private: + + Environment *env; + Connection *con; + + public : + /** + * Constructor for the occiproc demo program. + */ + occiproc (string user, string passwd, string db) throw (SQLException) + { + env = Environment::createEnvironment (Environment::DEFAULT); + con = env->createConnection (user, passwd, db); + }// end of constructor occiproc (string, string, string ) + + /** + * Destructor for the occiproc demo program. + */ + ~occiproc () throw (SQLException) + { + env->terminateConnection (con); + Environment::terminateEnvironment (env); + } // end of ~occiproc () + + // Function to call a PL/SQL procedure + void callproc () + { + cout << "callproc - invoking a PL/SQL procedure having IN, OUT and IN/OUT "; + cout << "parameters" << endl; + Statement *stmt = con->createStatement + ("BEGIN demo_proc(:v1, :v2, :v3); END;"); + try{ + cout << "Executing the block :" << stmt->getSQL() << endl; + stmt->setInt (1, 10); + stmt->setMaxParamSize (2, 30); + stmt->setString (2, "IN"); + stmt->registerOutParam (3, OCCISTRING, 30, ""); + int updateCount = stmt->executeUpdate (); + cout << "Update Count:" << updateCount << endl; + string c1 = stmt->getString (2); + string c2 = stmt->getString (3); + cout << "Printing the INOUT & OUT parameters:" << endl; + cout << "Col2: " << c1 << endl; + cout << "Col3: " << c2 << endl; + con->terminateStatement (stmt); + cout << "occiproc - done" << endl; + } + catch (SQLException ex){ + cout << ex.getMessage() << endl; + } + } // end of callproc () + + // Function to call a PL/SQL function + void callfun () + { cout << "callfun - invoking a PL/SQL function having IN, OUT and IN/OUT "; + cout << "parameters" << endl; + Statement *stmt = con->createStatement + ("BEGIN :a := demo_fun(:v1, :v2, :v3); END;"); + try{ + cout << "Executing the block :" << stmt->getSQL() << endl; + stmt->setInt (2, 10); + stmt->setMaxParamSize (3, 30); + stmt->setString (3, "IN"); + stmt->registerOutParam (1, OCCISTRING, 30, ""); + stmt->registerOutParam (4, OCCISTRING, 30, ""); + int updateCount = stmt->executeUpdate (); + cout << "Update Count : " << updateCount << endl; + + string c1 = stmt->getString (1); + string c2 = stmt->getString (3); + string c3 = stmt->getString (4); + + cout << "Printing the INOUT & OUT parameters :" << endl; + cout << "Col2: " << c2 << endl; + cout << "Col3: " << c3 << endl; + cout << "Printing the return value of the function: "; + cout << c1 << endl; + + con->terminateStatement (stmt); + cout << "occifun - done" << endl; + } + catch (SQLException ex){ + cout << ex.getMessage() << endl; + } + } // end of callfun () +}; // end of class occiproc + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + + cout << "occiproc - invoking a PL/SQL function and procedure having "; + cout << "parameters" << endl; + try{ + occiproc *demo = new occiproc (user, passwd, db); + demo->callproc(); + demo->callfun(); + delete demo; + } + catch (SQLException ex){ + cout << ex.getMessage() << endl; + } + +}// end of main () diff --git a/occiscp.cpp b/occiscp.cpp new file mode 100644 index 0000000..130b44c --- /dev/null +++ b/occiscp.cpp @@ -0,0 +1,193 @@ +/* Copyright (c) 2003, 2006, Oracle. All rights reserved. */ +/* + NAME + occiscp.cpp - OCCI StatelessConnectionPool with Statement Cache + + DESCRIPTION : + This program demonstates the creating and using of + StatelessConnectionPool in the database with statement caching enabled. + + * Create a StatelessConnectionPool. + * Caching can be enabled for all the connections in the pool + by calling setStmtCacheSize(size) on the pool object with + a non-zero value of size. + * Get a connection from the pool. + * If necessary, override the cache size for the connection + with setStmtCacheSize(size) on the connection. + * Create a statement with a call to createStatement(sql, tag) + or createStatement(sql). If the statement is in the cache, + it is returned; if not, a new statement with NULL tag is created + for the user and returned. + * Use the statement to execute SQL commands and obtain results. + * Return the statement back to the cache by calling + terminateStatement(stmt, tag) or terminateStatement(stmt). + Alternately, if the user does not want the statement to be cached, + he can call setDisableStmtCaching(TRUE) on the statement and + then terminateStatement(stmt). This will delete the statement + instead of caching it. + * Release the connection back to the pool. + + NOTE : + Stateless Connection Pool & Statement Cache are two different + features of OCCI and can be used exclusively. + This program makes use of both the features for demonstration purpose only + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/23/04 - Copyright Info + idcqe 03/05/03 - Creation + +*/ + +#include +#include +using namespace oracle::occi; +using namespace std; + +Environment *env; +int main (void) +{ + env = Environment::createEnvironment (Environment::DEFAULT); + const string poolUserName = "hr"; + const string poolPassword = "hr"; + const string connectString = ""; + unsigned int maxConn = 5; + unsigned int minConn = 3; + unsigned int incrConn = 2; + + cout<<"Demo for StatelessConnectionPool with statement cache"<createStatelessConnectionPool + (poolUserName, poolPassword, connectString, maxConn, + minConn, incrConn, StatelessConnectionPool::HOMOGENEOUS); + + if (scPool) + cout<<"SUCCESS - createStatelessConnectionPool"<getConnection(); + if (con1) + cout<<"SUCCESS - getConnection"<setStmtCacheSize(2); + unsigned size1 = con1->getStmtCacheSize(); + cout<<"The size of cache for the connection is "<releaseConnection (con1, tag); + + // Get the connection with tag = "tagA" from the pool. + con1 = scPool->getConnection (tag); + if (con1) + cout<<"SUCCESS - getConnection"<createStatement(sqlquery1); + ResultSet *rset1 = stmt1->executeQuery (); + cout<<"Retrieving the data"<next()) + { + cout<<"Emp id: "<getInt(1)<closeResultSet ( rset1 ); + //Put the statement into the cache + con1->terminateStatement ( stmt1); + //Check if the statement is in the cache. + bool cached = con1->isCached(sqlquery1); + if (cached) + cout<<"The statement is in the cache"<createStatement(sqlquery2); + ResultSet *rset2 = stmt2->executeQuery (); + cout<<"Retrieving the data"<next()) + { + cout<<"Emp id: "<getInt(1)<closeResultSet ( rset2 ); + + //Put the statement into the cache by tagging it + con1->terminateStatement(stmt2, tag); + + stmt3=con1->createStatement(sqlquery2,tag); + //Remove the statement from the cache + cout<<"Now disable caching on the statement"<disableCaching(); + con1->terminateStatement (stmt3 ); + + //Check if the statement is in the cache. + cached = con1->isCached(sqlquery2, tag); + if (cached) + cout<<"The statement is in the cache"<releaseConnection(con1); + + //Get one tagged connection from the pool + con2 = scPool->getAnyTaggedConnection(tag); + if (con2) + cout<<"SUCCESS - getAnyTaggedConnection"<terminateConnection (con2); + + //Get one more connection from the pool + con3 = scPool->getConnection(); + if (con3) + cout<<"SUCCESS - getConnection"< +#include +using namespace oracle::occi; +using namespace std; + +class occistrm +{ + private: + + Environment *env; + Connection *conn; + + public: + + occistrm (string user, string passwd, string db) + throw (SQLException) + { + env = Environment::createEnvironment (Environment::DEFAULT); + conn = env->createConnection (user, passwd, db); + }// end of constructor occistrm (string, string, string) + + ~occistrm () + throw (SQLException) + { + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + }// end of destructor + + /** + * displaying all the rows in the table + */ + void displayAllRows () + { + Statement *stmt = conn->createStatement ( + "SELECT summary FROM book WHERE bookid = 11"); + stmt->execute (); + ResultSet *rs = stmt->getResultSet (); + rs->setCharacterStreamMode(1, 4000); + char buffer[500]; + int length = 0; + unsigned int size = 500; + try{ + while (rs->next ()) + { + Stream *stream = rs->getStream (1); + while( (length=stream->readBuffer(buffer, size))!=-1) + { + cout << "Read " << length << " bytes from stream" << endl; + } + rs->closeStream(stream); + } + } + catch (SQLException ex){ + cout << ex.getMessage() << endl; + } + stmt->closeResultSet (rs); + conn->terminateStatement (stmt); + }// end of updateRow (string); + +}; // end of class occistrm + + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + try{ + cout << "occistrm - Exhibiting usage of streams for VARCHAR2 data" + << endl; + occistrm *demo = new occistrm (user, passwd, db); + + demo->displayAllRows (); + + delete (demo); + } + catch (SQLException ex){ + cout << ex.getMessage() << endl; + } + cout << "occistrm - done" << endl; +}// end of int main (void); diff --git a/occiuni1.cpp b/occiuni1.cpp new file mode 100644 index 0000000..73a9d38 --- /dev/null +++ b/occiuni1.cpp @@ -0,0 +1,186 @@ +/* Copyright (c) 2003, 2006, Oracle. All rights reserved. */ +/* + NAME + occiuni1.cpp - OCCI Globalization Support demo (Unicode) + + DESCRIPTION + Demonstrates OCCI globalization support capabilities :- + + 1.createEnvironment : specifying client characterset & + national characterset of the application + + 2.setUString : binding Unicode data for a NVARCHAR2 + column using OCCI's UString datatype + + 3.setCharSet : specifying charactersets different from the + Environment's for Statement bind and ResultSet fetch + + 4.getString : fetching Unicode data from a NVARCHAR2 + column in UTF8 charset + + Demo schema : - + table Countries_Tab + ( + CID Number(10), Country Id + CENGLISHNAME Varchar2(100), Country name in English + CNATIONALNAME NVarchar2(100), Country name in national language + ) + + Oracle's NVARCHAR2 datatype is capable of storing Unicode data. + + This demo inserts some country names in their national languages( + e.g Japan in japanese) in Unicode(UTF16) and then fetches them in + UTF8 characterset. + + INSTRUCTIONS + ------------ + + 1.Run SQL script - occiuni1.sql before running this program. The + database characterset can be any characterset, the database + national characterset will be one of the Unicode + charactersets : AL16UTF16 or UTF8. + + 2.Run this program and direct output to a file and view the output + file from a browser :- + $ ./occiuni1 > occiuni1.html + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + kukannan 03/12/06 - Fix bug 5074203 + sudsrini 07/23/04 - Copyright Info + shiyer 03/05/03 - Creation + +*/ + +#include +#include + +using namespace std; +using namespace oracle::occi; + +//ascii2utf16 - simpile utility function to convert an +//ASCII string to Unicode string +UString ascii2utf16(string asciistr) +{ + UString ustr; + ustr.resize (asciistr.length()); + for (int i = 0; i < asciistr.length(); i++) + ustr[i] = (unsigned short)asciistr[i]; + + return ustr; +} + +int main() +{ + + try + { + +//initialize environment with client characterset = US7ASCII, +//national characterset = UTF16 + Environment *env = Environment::createEnvironment("US7ASCII","OCCIUTF16"); + + Connection *conn = env->createConnection("hr","hr"); + + cout << "Inserting Unicode data in UTF16 characterset
" << endl; + + Statement *stmt = conn->createStatement("insert into Countries_Tab values (:1,:2,:3)"); + +//If the database column type is NCHAR/NVARCHAR2 then need to call +//setDatabaseNCHARParam with true to indicate this. + stmt->setDatabaseNCHARParam(3, true); + +//-------------------1, U.S.A---------------------------------------- + stmt->setInt(1, 1); + stmt->setString(2, "U.S.A"); //data in ASCII + UString uUSA = ascii2utf16("U.S.A");//U.S.A in Unicode + stmt->setUString(3, uUSA);//setUString for binding Unicode + stmt->executeUpdate(); + +//-------------------2, Russia---------------------------------------- + stmt->setInt(1, 2); + stmt->setString(2, "Russia"); +//the 6 Cyrillic Unicode characters for 'Russia'. + unsigned short russiaunicodechars[] = {0x0420,0x043E,0x0441, + 0x0441,0x0438,0x044F}; + UString uRussia(russiaunicodechars,6); + stmt->setUString(3,uRussia); + + stmt->executeUpdate(); + +//-------------------3, Japan---------------------------------------- + stmt->setInt(1, 3); + stmt->setString(2, "Japan"); + +//the 2 Katakana Unicode characters for 'Japan' in japanese + unsigned short japanunicodechars[] = {0x65E5,0x672C}; + UString uJapan(japanunicodechars, 2); + stmt->setUString(3,uJapan); + + stmt->executeUpdate(); + +//-------------------4, Austria---------------------------------------- + stmt->setInt(1, 4); + stmt->setString(2, "Austria"); + +// the client charset & client national charset environment settings +// can be over-ridden for specific columns by calling the setCharSet +// method on Statement/ResultSet + stmt->setCharSet(3, "WE8DEC");//override UTF16 for this column + +//the character Ö (WE8DEC codepoint D6) is for Latin capital letter O with +//Diaresis. Use setString instead of setUString, since not in UTF16 + string aAustria("Österreich");//data in WE8DEC + stmt->setString(3, aAustria); + + stmt->executeUpdate(); + +//commit the inserts. Users can view the inserted data from SQL*Plus or +//ISQL*Plus + conn->commit(); + + conn->terminateStatement(stmt); + +//Now fetch the data. We will fetch the Unicode data (i.e country +//names in national language) in UTF8 charset +//added some HTML
output for formatting in browser + + cout << "Retrieving data in UTF8 characterset
" << endl; + cout << +"The Unicode data will not display correctly in terminal. \ +To properly view, pipe the output of this program to a text file. \ +Open this text file from a Web browser and set \ +Encoding/Characterset to UTF8
" << endl; + cout << "=========================================
" << endl; + + stmt = conn->createStatement("select Cid, CEnglishName, CNationalName from Countries_Tab"); + ResultSet *rs = stmt->executeQuery(); + + rs->setDatabaseNCHARParam(3, true);//NVARCHAR2 column + rs->setCharSet(3, "UTF8"); //explicitly specify characterset + + while (rs->next()) + { + cout << rs->getInt(1) << "," << rs->getString(2) << ","; + cout << rs->getString(3); //country name in UTF8 + + cout << "
" << endl; //HTML formatting tag + } + + cout << "=========================================
" << endl; + + stmt->closeResultSet(rs); + conn->terminateStatement(stmt); + + //terminate connection & environment + env->terminateConnection(conn); + Environment::terminateEnvironment(env); + } + catch (SQLException e) + { + cout << "Error : "; + cout << e.getMessage() << endl; + } + + return 0; +} diff --git a/occiuni1.sql b/occiuni1.sql new file mode 100644 index 0000000..975f591 --- /dev/null +++ b/occiuni1.sql @@ -0,0 +1,30 @@ +/* Copyright (c) 2003, 2005, Oracle. All rights reserved. */ +/* + + NAME + occiuni1.sql - Create Objects for OCCI Globalization demo + + DESCRIPTION + + This sql script creates objects for occi unicode demo + This program assumes sample HR schema is setup. + + + MODIFIED (MM/DD/YY) + sudsrini 08/02/04 - Copyright Info + shiyer 03/05/03 - Creation + +*/ + +connect hr/hr; + +drop table countries_tab; + +create table countries_tab +( + CID Number(10), + CENGLISHNAME Varchar2(100), + CNATIONALNAME NVarchar2(100) +) +/ + diff --git a/occiuni2.cpp b/occiuni2.cpp new file mode 100644 index 0000000..0aa566d --- /dev/null +++ b/occiuni2.cpp @@ -0,0 +1,250 @@ +/* Copyright (c) 2003, 2006, Oracle. All rights reserved. */ +/* + NAME + occiuni2.cpp - OCCI Globalization Support demo (Unicode, Windows specific) + + DESCRIPTION + This is a Microsoft Windows specific demo. + Except for the use of Windows API's and wstring datatypes, other concepts + demonstrated apply to all platforms. + The data file used is also Windows specific. + + Demonstrates the following capabilities :- + 1. Equivalance of OCCI's UString & Windows wstring datatype. + A wstring can be passed to OCCI Unicode interfaces expecting a + UString datatype. A wchar literal (L prefix) can also be passed + for a UString + + 2. Initialize OCCI Environment in Unicode(UTF16) + + 3. Logon & executing statements using the UString interfaces + + 4. Creating & updating persistent objects containing NCLOB + attributes + + 5. Reading & writing Unicode data from/into NCLOBs. Shows use of + Clob::writeChunk & Clob::read methods for wchar data. The Unicode + data is stored in text files. + + 6. OTT generated class definition with UString attribute. + + Schema :- + create type DocObjType as object + ( + DocName varchar2(100), + DocText nclob + ) + + create table DocumentsTab of DocObjType; + + OTT generated C++ class : DocObjType + + INSTRUCTIONS + ------------ + 1.Run SQL script - occiuni2.sql before running this program. + 2.This demo is Microsoft Windows only. + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + kukannan 03/12/06 - Fix bug 5074203 + sudsrini 07/23/04 - Copyright Info + shiyer 03/05/03 - Creation + +*/ + +#include +#include +#include + +#include + +//mapping function include +#include "occiuni2m.h" + +using namespace std; +using namespace oracle::occi; + +int main() +{ + cout << "***OCCI Globalization Support demo program.***" << endl; + cout << "***This program loads Unicode data files into a NClob attribute***" << endl; + + char *unicodefiles[4] = {"occiuni2_hindi.txt", "occiuni2_russian.txt", "occiuni2_korean.txt", + "occiuni2_japanese.txt"}; + try + { + + cout << "Initializing OCCI environment in Unicode mode" << endl; + //initialize in Unicode(UTF16) mode + Environment *utf16env = Environment::createEnvironment( "OCCIUTF16", + "OCCIUTF16", Environment::OBJECT ); + occiuni2m(utf16env); + + //"L" prefix will create a widechar i.e Unicode literal which is equivalent to + // OCCI's UString datatype + Connection *conn = utf16env->createConnection( L"hr",L"hr",L"" ); + + //load the 4 sample Unicode files + for (int i = 0; i < 4;i++) + { + //convert the filename argument to Unicode. We will be saving the filename + //as one of the attributes of the object. + const char *asciifilename = unicodefiles[i]; + wchar_t wcfilename[100]; + MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, (LPCSTR)asciifilename, + strlen(asciifilename)+1, (LPWSTR)wcfilename, 100 ); + wstring docname(wcfilename); + + cout << "Loading " << asciifilename << endl; + + + //Create a persistent object, set the NClob to empty and save + //the object. Use the overloaded new operator that takes UString + //arugments + DocObjType *newdoc = new (conn, L"DOCUMENTSTAB",L"DOCOBJTYPE", + L"HR",L"HR") DocObjType(); + + newdoc->setDocname(docname); + + //first insert a empty clob + Clob doccontents(conn); + doccontents.setEmpty(); + newdoc->setDoctext(doccontents);//empty + + conn->commit(); + + //Now, we will select the object again and add the document text + //to the NClob attribute. + Statement *stmt = conn->createStatement( + L"select ref(a) from documentstab a where docname = :1 for update"); + + stmt->setUString(1, docname);//bind wstring + ResultSet *rs = stmt->executeQuery(); + + rs->next();//this will actually fetch the Ref + + Ref docobjref = rs->getRef(1); + DocObjType *docobj = docobjref.ptr();//pin the object + + doccontents = docobj->getDoctext();//get the Clob + doccontents.open(); + + doccontents.setCharSetId("OCCIUTF16"); + doccontents.setCharSetForm(OCCI_SQLCS_NCHAR); + + ifstream in( asciifilename, ios::binary ); + int bytesread=0, totalbytesread=0, wcharsread=0; + wchar_t wbuffer1[50];//50 chars = 100 bytes at a time + + //we have stored the data in a Unicode text file. The first + //character (2 bytes) is a Unicode Byte-Order-Mark and + //indicates whether the data in the file is little-endian or + //big-endian + in.read((char *)wbuffer1,2);//read & skip BOM + int offset = 1; + + while (in.read( (char *)wbuffer1,sizeof(wbuffer1) )) + { + bytesread = in.gcount(); + wcharsread = bytesread/2; + + //write to the NClob + doccontents.writeChunk( wcharsread, (utext *)wbuffer1, sizeof(wbuffer1), offset ); + + offset += wcharsread;//offset is in terms of characters + totalbytesread += bytesread; + } + //last chunk + bytesread = in.gcount(); + wcharsread = bytesread/2; + totalbytesread += bytesread; + + doccontents.writeChunk( wcharsread, (utext *)wbuffer1, bytesread, offset ); + doccontents.close(); + + //update the object and flush to database + docobj->setDoctext(doccontents); + docobj->markModified(); + docobj->flush(); + conn->commit(); + + + cout << totalbytesread/2 << " characters saved" << endl; + + //Statement & ResultSet objects will be created again + stmt->closeResultSet(rs); + conn->terminateStatement(stmt); + }//for (i = 0; i < 4) + + + cout << "Now reading the NClob data back and saving to new files" << endl; + + Statement *selectstmt = conn->createStatement( + L"select ref(a) from DocumentsTab a" ); + ResultSet *queryrs = selectstmt->executeQuery(); + wstring wfilehdrtxt = L"If you cannot see the text properly, try setting your font to a Unicode font like : - Arial Unicode MS, Lucinda Sans Unicode etc..."; + while (queryrs->next()) + { + Ref docobjref = queryrs->getRef(1); + + wstring docname = docobjref->getDocname(); + + //create the output file, prepend "fetch_" to the original filename + docname = L"fetch_" + docname; + char asciifilenamebuf[100]; + + int ret = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)docname.c_str(), + docname.length()+1, (LPSTR)asciifilenamebuf, 100, NULL, NULL); + + cout << "Creating Unicode textfile " << asciifilenamebuf << endl; + ofstream outdoc(asciifilenamebuf, ios_base::binary | ios_base::trunc); + + //first write the BOM + wchar_t bom = 0xFEFF;//Windows is little-endian + outdoc.write((char *)&bom, 2); + + outdoc.write((char *)wfilehdrtxt.c_str(), wfilehdrtxt.length()*2); + + Clob doccontents = docobjref->getDoctext(); + doccontents.setCharSetId("OCCIUTF16"); + doccontents.setCharSetForm(OCCI_SQLCS_NCHAR); + int offset = 1; + int clobcharsread=0; + //now read the NClob and write to file + wchar_t wbuffer2[100];//100 chars at a time + while ( (clobcharsread = + doccontents.read(100, wbuffer2, sizeof(wbuffer2), offset)) !=0 ) + { + offset = offset+clobcharsread; + outdoc.write((char *)wbuffer2,clobcharsread*2);//write takes number of bytes + } + outdoc.close(); + + }//while (queryrs->next()) + + //done + cout << "You can view the created files in Notepad(or any other editor that displays Unicode)" << endl; + selectstmt->closeResultSet(queryrs); + conn->terminateStatement(selectstmt); + + //delete the rows from the table + //if you want to retain the rows, comment out + cout << "Cleaning up table" << endl; + Statement *deletestmt = conn->createStatement( + L"delete from DocumentsTab"); + deletestmt->executeUpdate(); + + conn->commit(); + + utf16env->terminateConnection(conn); + Environment::terminateEnvironment(utf16env); + + cout << "Done" << endl; + + } + catch (SQLException &e) + { + std::cout << e.getErrorCode() << std::endl; + } + return 0; +} diff --git a/occiuni2.sql b/occiuni2.sql new file mode 100644 index 0000000..6b7f0d2 --- /dev/null +++ b/occiuni2.sql @@ -0,0 +1,36 @@ +/* Copyright (c) 2003, 2005, Oracle. All rights reserved. */ +/* + + NAME + occiuni2.sql - Create Objects for OCCI Globalization demo + + DESCRIPTION + + This sql script creates objects for OCCI Windows Specific unicode demo + This program assumes sample HR schema is setup. + + NOTES + The demo to be run only on windows + + MODIFIED (MM/DD/YY) + sudsrini 08/02/04 - Copyright Info + shiyer 03/05/03 - Creation + +*/ + +connect hr/hr + +drop table DocumentsTab; + +drop type DocObjType; + +create type DocObjType as object +( + DocName varchar2(100), + --nclob to store Unicode data + DocText nclob +) +/ + +create table DocumentsTab of DocObjType; + diff --git a/occiuni2.typ b/occiuni2.typ new file mode 100644 index 0000000..075fbd0 --- /dev/null +++ b/occiuni2.typ @@ -0,0 +1,4 @@ +MAPFILE=occiuni2m.cpp +TYPE docobjtype as DocObjType +TRANSLATE docname as DocName + doctext as DocText diff --git a/occiuni2_hindi.txt b/occiuni2_hindi.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d2f3d641d0ed6e078cfe34d1b76caeacd867b1f GIT binary patch literal 710 zcmZXST}uK{5Qc|9Xo4<7h#)V-qD&-E_R3lj5o7B@p=;fh5=_O9pg*5IXLhZ#d9i2D zp7YE*GwHuBDX&iRK-WX*ocS4n#IPFPRnBx92-`i}cRpR}e8 zZE0N{F_f*v`%F!bw5azU^$L@q?=tyhRYSeLTV{Y@ztyQyUB8!jB zcc)M@4*frV>|1U&w0A9s7+0db>}m$(h!Z7rZFLR zZ#-+9N#hF4Dj-+cVh89gxts7`j9FJ172rsj$wykHE0^U(Vz@<)D%cDznbn?phWI>C SbKdz{9f7xl5QL|Uka&hrA(}`rKY^5y5CsyU0Ersx<3|`{0gjZ%$fMEI@*2SGv1iUA zg{|{^J9E41>!ph+eo;Y{&j4E_IAFSb}7 zpN+6FGF$1>b?WGZEYd8$q8Yo2G5g4{V+TI3<@r6bRe>G7{=dGBzB|8<{~6wAQ&_;m*OLov^^4u%Wwf!iwiIsm?iRE&gXlc(;m)g z2TkAS_q>1W{nrv-_EM8Nem&VpD2e>wJ%qlNsl<3+AgW0hG=kzIsz^C=2U>j@SKo zKRn1hQ99SA-mjq}umDw9-F8%O#^GTGg>EiCUkz`AEu7ra#jqhJN_4he`}F*Bh2Azh zJPhmT?G&Doz6!TmIvTfYWAZT^u5Xr8(;KnUL|>G(*19rd(xzBei@Uu z*Et<@<>gX+nML%ItgNZiDD9(U4jSVwrqfrUV~C1d&?zPy;~8bXxS-QLz(xuF4YqUR WXms`A*cB>9T$6$`$f^Gb?10Vy literal 0 HcmV?d00001 diff --git a/occiuni2_russian.txt b/occiuni2_russian.txt new file mode 100644 index 0000000000000000000000000000000000000000..646481d5673cd006caadbc4f5ad252b872d1ed20 GIT binary patch literal 742 zcmZXSO>4qH5QgV4r$YaOr``&hR%S1IkMZco3X!^E6*>z!YxcsyV}vF z-ZLKcg>_5YYU~@gO|47^8pDSr>K$f@`Z*avnQGl@tx?O))Se+?4VXi{bKDSSQ_0xV z1jecwdaWtdADmjbvPk>d;Oj!?Ij1mbMJpg0(VbNmF*@|yba_Y4p(AtVyftSM;sIJA zl=(5F$2svTH9#SNsXO;_k44IgQw9M6z=oZaKGDU3;z?bH2E1|F*dI;H$Gv zR{p%DV^_KHBdXb+Dz-?W6cPDg?D49|72tB8&huKPDDH@^cr|n8%yYRjF}^oWy(jc@ g;H{OpE>2ddF~s+UUI*99S_6p11!eEAjZ=Bff4cl;p#T5? literal 0 HcmV?d00001 diff --git a/occixa.cpp b/occixa.cpp new file mode 100644 index 0000000..8f9604a --- /dev/null +++ b/occixa.cpp @@ -0,0 +1,321 @@ +/* Copyright (c) 2003, 2009, Oracle and/or its affiliates. +All rights reserved. */ +/* + NAME + occixa.cpp: OCCI XA interface demo + + DESCRIPTION + This program creates an XA Environment, gets an XA Connection from the + created environment, uses the XA connection to do DMLs on a table. + + The key APIs that are used are: + - getXAEnviroment + - getXAConnection + - getXAErrorCode + - releaseXAConnection + - releaseXAEnvironment + + For more more information, please refer Oracle documentaion. + + MODIFIED (MM/DD/YY) + sudsrini 07/08/09 - Include string.h, iostream not including it on sles11 + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/23/04 - Copyright Info + shiyer 03/05/03 - Creation + +*/ + +#include +#include +#include +#include // Should be included for all OCCI XA interface + +using namespace oracle::occi; +using namespace std; + +#ifdef WIN32COMMON + extern "C" __declspec(dllimport) struct xa_switch_t xaosw; + extern "C" __declspec(dllimport) struct xa_switch_t xaoswd; +#else + extern struct xa_switch_t xaosw; + extern struct xa_switch_t xaoswd; +#endif + +static XID xidx = { 0x1e0a0a1e, 12, 8, "KeesGTID01Branch0001" }; +static XID *xid = &xidx; + +class occixa +{ + +private : + struct xa_switch_t *xafunc ; + Environment *xaenvrnmnt; + Connection *xaConnection; + +public : + +occixa () +{ +} + +~occixa () +{ +} + +void test (Connection *conn) +{ + Statement *stmt; + + showln("Invoking createStatement using XA Connection"); + stmt = conn->createStatement + ("INSERT INTO EMPLOYEES (employee_id, last_name, email,hire_date,job_id) \ + values (998, 'Mike', 'x1@y.com','12-Mar-1970','AC_ACCOUNT')"); + + showln("Inserting Records into Local Database"); + stmt->executeUpdate(); + + showln("Selecting Records From Local Database using XA Connection"); + displayQueryResult ( conn, + "SELECT Employee_id,last_name FROM EMPLOYEES where employee_id \ + between 998 and 999 ORDER BY 1,2" ); + + showln("Deleting the inserted Records from Database"); + stmt = conn->createStatement + ("DELETE EMPLOYEES where employee_id between 998 and 999"); + + stmt->executeUpdate(); + + showln("Terminating the Statements using XA Connection "); + conn->terminateStatement (stmt); + +} + +// This function establishes an XA connection to the resource manager +void startXATest (string uname, string pwd, string db , XID *xid ) +{ + + int xarslt = 0; // xa result code + int rmid = 1; + char *xaoinfo; + this->xafunc = &xaoswd; + + //Forming the xaoinfo1 string which has to be sent as a parameter for + //xa_open_entry function call. + + string xaoinfo1 = "oracle_xa+ACC=P/"; + xaoinfo1 += uname; + xaoinfo1 +="/"; + xaoinfo1 += pwd; + + //For an Object Test this parameter OBJECTS=T should also be given to the + //xaoinfo string ( a parameter of the xa_open_entry function call) + + #ifdef OBJECTS + xaoinfo1 +="+OBJECTS=T"; + #endif + + //To open an entry for XA with a remote database, DB="database_name" + //should also be given to the xaoinfo string ( a parameter of the + //xa_open_entry function call) + + if (!db.empty()) + xaoinfo1 += "+SESTM=50+logdir=.+DB="+db; + else + xaoinfo1 += "+SESTM=50+logdir=."; + xaoinfo=(char *)xaoinfo1.c_str(); + + // Connects to the resource manager + xarslt = xafunc->xa_open_entry(xaoinfo, rmid, TMNOFLAGS); + + if ( xarslt ) + cout << "xaoopen = " << xarslt << endl; + + XID *t = xid; + int i; + for (i=0;i<64;i++) + t->data[i] = '\0'; + t->formatID = 1; + t->gtrid_length = 8; + for (i=0;igtrid_length;i++) + t->data[i] = 1; + t->bqual_length = 4; + for (i=0;ibqual_length;i++) + t->data[i+t->gtrid_length] = 1; + xid=t; + + // Starts a new transaction and associates it with the given transaction ID (XID) + xarslt = xafunc->xa_start_entry(xid, rmid, TMNOFLAGS); + + if ( xarslt ) + cout << "xaostart = " << xarslt << endl; + + try + { + // This method returns a pointer to OCCI Environment Object that corresponds + // to the one opened by the XA Library + // db represents the database name in which the XA Environment is created + + xaenvrnmnt = Environment::getXAEnvironment(db); + } + catch(SQLException &ex) + { + cout << ex.what() << endl; + + //This method returns an XA error code when a XA exception is encountered. + //It returns a XA_OK if the error is not due to XA.It takes db as paramter. + + int error = ex.getXAErrorCode(db); + if(error==XA_OK) + cout << "Error in SQL processing" << endl; + else + cout << "XA Error Code:" << error << endl; + } + + try + { + // This method returns a pointer to an OCCI Connection object that corresponds + // to the one opened by the XA Library. + //db represents the database name to which the XA Connection is got + + xaConnection = xaenvrnmnt->getXAConnection(db); + } + catch(SQLException &ex) + { + cout << ex.what() << endl; + int error = ex.getXAErrorCode(db); + if(error==XA_OK) + cout << "Error in SQL processing" << endl; + else + cout << "XA Error Code:" << error << endl; + } + + try + { + test ( xaConnection ); + } + catch (SQLException ea) + { + showError (ea); + } + + try + { + //This method releases/de-allocates the neccessary handles allocated by the + //getXAConnection call. It takes XA Connection as the parameter + + xaenvrnmnt->releaseXAConnection (xaConnection); + } + catch(SQLException &ex) + { + cout << ex.what() << endl; + int error = ex.getXAErrorCode(db); + if(error==XA_OK) + cout << "Error in SQL processing" << endl; + else + cout << "XA Error Code:" << error << endl; + } + + // Disassociates the process from the given XID + xarslt = xafunc->xa_end_entry(xid, rmid, TMSUCCESS); + if ( xarslt ) + cout << "xaoend = " << xarslt << endl; + + // Prepares the transaction associated with the given XID. First phase of + // two-phase commit protocol. + xarslt = xafunc->xa_prepare_entry(xid, rmid, TMNOFLAGS); + if ( xarslt ) + cout << "xaoprepare = " << xarslt << endl; + + // Commits the transaction associated with the given XID. Second phase of + // two-phase commit protocol. + xarslt = xafunc->xa_commit_entry(xid, rmid, TMNOFLAGS); + if ( xarslt ) + cout << "xaocommit = " << xarslt << endl; + + try + { + //This call releases the neccessary handles allocated by the + //getXAEnvironment call. It takes XA Environment as the parameter + + Environment::releaseXAEnvironment (xaenvrnmnt); + } + catch(SQLException &ex) + { + cout << ex.what() << endl; + int error = ex.getXAErrorCode(db); + if(error==XA_OK) + cout << "Error in SQL processing" << endl; + else + cout << "XA Error Code:" << error << endl; + } + + // Disconnects from the resource manager. + xarslt = xafunc->xa_close_entry(xaoinfo, rmid, TMNOFLAGS); + if ( xarslt ) + { + cout << "xaoclose = " << xarslt << endl; + } + +} + +dvoid displayQueryResult (Connection* conn, string sqlQuery) +{ + Statement *stmt = conn->createStatement (sqlQuery); + int i=0; + try + { + ResultSet *rs = stmt->executeQuery (); + while (rs->next ()) + { + int a = rs->getInt (1); + cout << "Col 1" << ": " << a << endl; + string ch = rs->getString (2); + cout << "Col 2" << ": " << ch << endl; + + } + stmt->closeResultSet (rs); + } + catch ( SQLException e ) + { + showError ( e ); + conn->terminateStatement (stmt); + throw; + } + + conn->terminateStatement (stmt); +} + +dvoid showError (SQLException ex) +{ + showln ("Error number: ") << ex.getErrorCode() << endl; + showln (ex.getMessage()) << endl; +} + + +ostream& showln (string str) +{ + return cout << str << endl; +} +}; + +int main ( int argc, char* argv[]) +{ + string userName = "hr"; + string password = "hr"; + string database =""; + + occixa* h = new occixa(); + + // Gets an XA Connection to the default database, uses the XA Connection + // to Insert/Select from a table with/without database link + + try + { + h->startXATest (userName, password, database,xid); + } + catch (SQLException ea) + { + h->showError (ea); + } + +} diff --git a/oci02.c b/oci02.c new file mode 100644 index 0000000..0fbdd40 --- /dev/null +++ b/oci02.c @@ -0,0 +1,353 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci02.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests single row fetch of a query with a bind by position + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + aliu 01/05/06 - add order by in the select to fix intermittent + diffs + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci02.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number. + * + * It illustrates getting data back using SINGLE ROW FETCH + * via a SELECT statement. + * It also illustrates re-executing the same query again without + * having to rebind + * + * Based on: oci01.c + * Changes: added obndrn call + * added where clause to query with :1 + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - the number of tables + * + * oci02 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndrn + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexec + * Fetch - ofetch + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ + + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT cname, clength, colid \ + FROM ocicolu \ + WHERE tname = :1 order by colid"; + +/* return values from query - kept as globals for simplicity */ +uword colid; +uword collen; +text cname [MAX_NAME_LENGTH+1]; + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 2) + { + printf("\n\n Usage: where numtabs is the number of \ +tables with name TESTxx \n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndrn(&cda, 1, (ub1 *)tabname, (sword)sizeof(tabname), /* bind */ + SQLT_STR, -1, (sb2 *) 0, (text *) 0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 1, (ub1 *) cname, (sword) sizeof(cname), /* define */ + (sword) SQLT_STR, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 2, (ub1 *) &collen, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 3, (ub1 *) &colid, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n printing column information for table %s :\n\n", tabname); + + while (ofetch(&cda) == 0) + { + row_count++; /* bump this for printing purposes */ + dump_data(); + } + + if (cda.rc != NO_DATA_FOUND) + err_report(&cda); + + row_count = 0; /* reset for next table */ + +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + printf(" column %d name is %s\n", row_count, cname); + printf(" column %d length is %d \n", row_count, collen); + printf(" column %d id is %d \n", row_count, colid); + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci02.sql b/oci02.sql new file mode 100644 index 0000000..e2924c9 --- /dev/null +++ b/oci02.sql @@ -0,0 +1,54 @@ +rem +rem $Header: oci02.sql 11-oct-2006.15:55:31 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci02.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci02.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + SELECT o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + FROM sys.col$ c$, sys.obj$ o$ + WHERE o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* user version for ocitest */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (this_col_name_is_30_chars_long number, + two long, three date, four char(10)); + diff --git a/oci03.c b/oci03.c new file mode 100644 index 0000000..2b332cf --- /dev/null +++ b/oci03.c @@ -0,0 +1,353 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci03.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests single row fetch using bind by value + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + aliu 01/05/06 - add order by in the select statements to fix + intermittent diffs + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci03.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number. + * + * It illustrates getting data back using SINGLE ROW FETCH + * via a SELECT statement. + * It also illustrates re-executing the same query again without + * having to rebind + * + * Based on: oci02.c + * Changes: changed obndrn call to obndrv + * changed query where clause to :tabname + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - the number of tables + * + * oci03 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndrv + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexec + * Fetch - ofetch + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ + + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT cname, clength, colid \ + FROM ocicolu\ + WHERE tname = :tabname order by colid"; + +/* return values from query - kept as globals for simplicity */ +uword colid; +uword collen; +text cname [MAX_NAME_LENGTH+1]; + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 2) + { + printf("\n\n Usage: where numtabs is the number of \ +tables with name TESTxx \n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndrv(&cda, (text *)":tabname", -1, + (ub1 *)tabname, (sword)sizeof(tabname), + SQLT_STR, -1, (sb2 *) 0, (text *) 0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 1, (ub1 *) cname, (sword) sizeof(cname), /* define */ + (sword) SQLT_STR, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 2, (ub1 *) &collen, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 3, (ub1 *) &colid, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n printing column information for table %s :\n\n", tabname); + + while (ofetch(&cda) == 0) + { + row_count++; /* bump this for printing purposes */ + dump_data(); + } + + if (cda.rc != NO_DATA_FOUND) + err_report(&cda); + + row_count = 0; /* reset for next table */ +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + printf(" column %d name is %s\n", row_count, cname); + printf(" column %d length is %d \n", row_count, collen); + printf(" column %d id is %d \n", row_count, colid); + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci03.sql b/oci03.sql new file mode 100644 index 0000000..48760f9 --- /dev/null +++ b/oci03.sql @@ -0,0 +1,54 @@ +rem +rem $Header: oci03.sql 11-oct-2006.15:55:31 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci03.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci03.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + SELECT o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + FROM sys.col$ c$, sys.obj$ o$ + WHERE o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* user version for ocitest */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (this_col_name_is_30_chars_long number, + two long, three date, four char(10)); + diff --git a/oci04.c b/oci04.c new file mode 100644 index 0000000..f13558e --- /dev/null +++ b/oci04.c @@ -0,0 +1,354 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci04.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests single row fetch of a query with an array bind of a scalar + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + aliu 01/05/06 - add order by in the select statements to fix + intermittent diffs + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci04.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number. + * + * It illustrates getting data back using SINGLE ROW FETCH + * via a SELECT statement. + * It also illustrates re-executing the same query again without + * having to rebind + * + * Based on: oci02.c + * Changes: changed obndrn call to obndra call + * modified where clause to include :tabname + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - the number of tables + * + * oci04 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexec + * Fetch - ofetch + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ + + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT cname, clength, colid \ + FROM ocicolu\ + WHERE tname = :tabname order by colid"; + +/* return values from query - kept as globals for simplicity */ +uword colid; +uword collen; +text cname [MAX_NAME_LENGTH+1]; + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 2) + { + printf("\n\n Usage: where numtabs is the number of \ +tables with name TESTxx \n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":tabname", -1, + (ub1 *)tabname, (sword)sizeof(tabname), + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 1, (ub1 *) cname, (sword) sizeof(cname), /* define */ + (sword) SQLT_STR, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 2, (ub1 *) &collen, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 3, (ub1 *) &colid, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n printing column information for table %s :\n\n", tabname); + + while (ofetch(&cda) == 0) + { + row_count++; /* bump this for printing purposes */ + dump_data(); + } + + if (cda.rc != NO_DATA_FOUND) + err_report(&cda); + + row_count = 0; /* reset for next table */ +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + printf(" column %d name is %s\n", row_count, cname); + printf(" column %d length is %d \n", row_count, collen); + printf(" column %d id is %d \n", row_count, colid); + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci04.sql b/oci04.sql new file mode 100644 index 0000000..05aab1e --- /dev/null +++ b/oci04.sql @@ -0,0 +1,54 @@ +rem +rem $Header: oci04.sql 11-oct-2006.15:55:31 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci04.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci01.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + SELECT o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + FROM sys.col$ c$, sys.obj$ o$ + WHERE o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* user version for ocitest */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (this_col_name_is_30_chars_long number, + two long, three date, four char(10)); + diff --git a/oci05.c b/oci05.c new file mode 100644 index 0000000..2f221e4 --- /dev/null +++ b/oci05.c @@ -0,0 +1,368 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci05.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests single row fetch with cancellation + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + aliu 01/05/06 - add order by in the select statements to fix + intermittent diffs + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci05.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number. + * + * It illustrates getting data back using SINGLE ROW FETCH + * via a SELECT statement. + * It also illustrates re-executing the same query again without + * having to rebind + * + * Based on: oci02.c + * Changes: call ocan after 4 (arbitrary number) rows have been fetched + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - the number of tables + * + * oci05 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndrn + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexec + * Fetch - ofetch + * Close - oclose + * Logoff - olof + * Cancel - ocan Cancel cursor after 4 rows + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +#define CANCEL_ROWS 4 /* cancel after 4 rows - arbitrary number */ + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ + + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT cname, clength, colid \ + FROM ocicolu\ + WHERE tname = :1 order by colid"; + +/* return values from query - kept as globals for simplicity */ +uword colid; +uword collen; +text cname [MAX_NAME_LENGTH+1]; + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 2) + { + printf("\n\n Usage: where numtabs is the number of \ +tables with name TESTxx \n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndrn(&cda, 1, (ub1 *)tabname, (sword)sizeof(tabname), /* bind */ + SQLT_STR, -1, (sb2 *) 0, (text *) 0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 1, (ub1 *) cname, (sword) sizeof(cname), /* define */ + (sword) SQLT_STR, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 2, (ub1 *) &collen, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 3, (ub1 *) &colid, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n printing column information for table %s :\n\n", tabname); + + while (ofetch(&cda) == 0) + { + row_count++; /* bump this for printing purposes */ + dump_data(); + + if ((row_count == CANCEL_ROWS) && (cda.rc == 0)) + { + printf(" Cancelling query after %d rows retrieved \n", row_count); + if (ocan(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + row_count = 0; /* reset since we are returning prematurely */ + return; + } + + } + + if (cda.rc != NO_DATA_FOUND) + err_report(&cda); + + row_count = 0; /* reset for next table */ + +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + printf(" column %d name is %s\n", row_count, cname); + printf(" column %d length is %d \n", row_count, collen); + printf(" column %d id is %d \n", row_count, colid); + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci05.sql b/oci05.sql new file mode 100644 index 0000000..4044697 --- /dev/null +++ b/oci05.sql @@ -0,0 +1,65 @@ +rem +rem $Header: oci05.sql 11-oct-2006.15:55:31 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci05.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci05.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + SELECT o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + FROM sys.col$ c$, sys.obj$ o$ + WHERE o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* user version for ocitest */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (this_col_name_is_30_chars_long number, two long, + three date, four char(10)); +create table test5( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char); +create table test6( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char, col11 number, col12 char, + col13 number, col14 char, col15 number, col16 char, + col17 number, col18 char, col19 number); +create table test7 (one number, two long, three date, four char(10), + five number, six number, seven number, eight number, + nine char(1), ten varchar(2000)); diff --git a/oci06.c b/oci06.c new file mode 100644 index 0000000..bbee745 --- /dev/null +++ b/oci06.c @@ -0,0 +1,383 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci06.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array fetch of just one table + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + aliu 01/05/06 - add order by in the select statements to fix + intermittent diffs + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci06.c + * + * Description: This program retrieves the column information for a single + * table called TEST1 + * + * It illustrates getting data back using ARRAY FETCH + * via a SELECT statement. + * The number of columns being returned is hard coded + * at 4 columns. The table has 4 columns for simplicity + * + * Based on: oci04.c + * Changes: added array features + * where clause has :tabname + * changed ofetch to ofen for multiple rows + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires NO arguments + * + * oci06 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra array bind by name + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexec + * Fetch - ofen fetching multiple rows + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ +uword numrows = 4; /* HARDCODED */ + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT cname, clength, colid \ + FROM ocicolu\ + WHERE tname = :tabname order by colid"; + +#define NUMCOLS 3 /* number of columns returned by above query */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = /* query returns one char and two numbers */ + { {MAX_NAME_LENGTH+1, SQLT_STR}, + {sizeof(eword), SQLT_INT}, + {sizeof(eword), SQLT_INT} + }; + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + numtabs = 1; /* hardcoded */ + printf("\n Number of tables is %d\n", numtabs); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":tabname", -1, + (ub1 *)tabname, (sword)sizeof(tabname), + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((ub4)(numrows*sizeof(sb2))); + colsptr->c_rlen = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_rcode = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_buf = (ub1 *)malloc((ub4)(numrows*colsptr->c_size)); + + if (odefin(&cda, colindex + 1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, (text *)0, -1, -1, + colsptr->c_rlen, colsptr->c_rcode)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n printing column information for table %s :\n\n", tabname); + + while (ofen(&cda, numrows) == 0) + { + dump_data(); + } + + if (cda.rc != NO_DATA_FOUND) + err_report(&cda); + +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + + uword index; + ub4 value; + for (index = 0; index < numrows; index++) + { + + printf(" column %d name is %s\n", index + 1 , + cols[0].c_buf + index * cols[0].c_size); + + memcpy((dvoid *)&value, (dvoid *)(cols[1].c_buf + index * cols[1].c_size), + *(cols[1].c_rlen + index)); + printf(" column %d length is %d \n", index + 1 , value); + + memcpy((dvoid *)&value, (dvoid *)(cols[2].c_buf + index * cols[2].c_size), + *(cols[2].c_rlen + index)); + printf(" column %d id is %d \n", index + 1 , value); + + } +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci06.sql b/oci06.sql new file mode 100644 index 0000000..5c4ac66 --- /dev/null +++ b/oci06.sql @@ -0,0 +1,51 @@ +rem +rem $Header: oci06.sql 11-oct-2006.15:55:32 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci06.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci06.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + SELECT o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + FROM sys.col$ c$, sys.obj$ o$ + WHERE o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* user version for ocitest */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table test1 (this_col_name_is_30_chars_long number, + two long, three date, four char(10)); + diff --git a/oci07.c b/oci07.c new file mode 100644 index 0000000..fce1482 --- /dev/null +++ b/oci07.c @@ -0,0 +1,382 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci07.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array fetch with piggyback of first fetch and execute + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + aliu 01/05/06 - add order by in the select statements to fix + intermittent diffs + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci07.c + * + * Description: This program retrieves the column information for a single + * table called TEST1 + * + * It illustrates getting data back using ARRAY FETCH + * via a SELECT statement. + * The number of columns being returned is hard coded + * at 4 columns. The table has 4 columns for simplicity + * This program piggy backs the first fetch on the execute + * call + * + * Based on: oci06.c + * Changes: changed oexec to oexfet + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires NO arguments + * + * oci07 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra array bind by name + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexfet Includes first fetch + * Fetch - none Included in execute + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ +uword numrows = 4; /* HARDCODED */ + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT cname, clength, colid \ + FROM ocicolu\ + WHERE tname = :tabname order by colid"; + +#define NUMCOLS 3 /* number of columns returned by above query */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = /* query returns one char and two numbers */ + { {MAX_NAME_LENGTH+1, SQLT_STR}, + {sizeof(eword), SQLT_INT}, + {sizeof(eword), SQLT_INT} + }; + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + numtabs = 1; /* hardcoded */ + printf("\n Number of tables is %d\n", numtabs); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":tabname", -1, + (ub1 *)tabname, (sword)sizeof(tabname), + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((ub4)(numrows*sizeof(sb2))); + colsptr->c_rlen = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_rcode = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_buf = (ub1 *)malloc((ub4)(numrows*colsptr->c_size)); + + if (odefin(&cda, colindex + 1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, (text *)0, -1, -1, + colsptr->c_rlen, colsptr->c_rcode)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + printf("\n printing column information for table %s :\n\n", tabname); + + /* expecting an EXACT match */ + /* cancel cursor after oexfet */ + if (oexfet(&cda, (ub4)numrows, -1, -1) == 0) + { + dump_data(); + } + else + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + + uword index; + ub4 value; + for (index = 0; index < numrows; index++) + { + + printf(" column %d name is %s\n", index + 1 , + cols[0].c_buf + index * cols[0].c_size); + + memcpy((dvoid *)&value, (dvoid *)(cols[1].c_buf + index * cols[1].c_size), + *(cols[1].c_rlen + index)); + printf(" column %d length is %d \n", index + 1 , value); + + memcpy((dvoid *)&value, (dvoid *)(cols[2].c_buf + index * cols[2].c_size), + *(cols[2].c_rlen + index)); + printf(" column %d id is %d \n", index + 1 , value); + + } +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci07.sql b/oci07.sql new file mode 100644 index 0000000..ff82ad1 --- /dev/null +++ b/oci07.sql @@ -0,0 +1,51 @@ +rem +rem $Header: oci07.sql 11-oct-2006.15:55:32 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci07.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci07.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + SELECT o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + FROM sys.col$ c$, sys.obj$ o$ + WHERE o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* user version for ocitest */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table test1 (this_col_name_is_30_chars_long number, two long, + three date, four char(10)); + diff --git a/oci08.c b/oci08.c new file mode 100644 index 0000000..450be58 --- /dev/null +++ b/oci08.c @@ -0,0 +1,427 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci08.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array fetch with multiple fetches with piggyback of first fetch + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + aliu 01/05/06 - add order by in the select statements to fix + intermittent diffs + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci08.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number + * + * It illustrates getting data back using ARRAY FETCH + * via a SELECT statement. + * It also illustrates re-executing the same query again without + * having to re-bind. + * The user can create multiple TESTxx tables + * The user can enter the number of rows to be fetched on each + * cycle + * + * Based on: oci07.c + * Changes: added support for multiple tables + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires TWO arguments: + * - the number of tables + * - the number of rows to fetch per cycle + * + * oci08 4 3 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra array bind by name + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexfet Includes first fetch + * Fetch - ofen For subsequent fetches + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT cname, clength, colid \ + FROM ocicolu\ + WHERE tname = :tabname order by colid"; + +#define NUMCOLS 3 /* number of columns returned by above query */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = /* query returns one char and two numbers */ + { {MAX_NAME_LENGTH+1, SQLT_STR}, + {sizeof(eword), SQLT_INT}, + {sizeof(eword), SQLT_INT} + }; + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 3) + { + printf("\n\n Usage: \n"); + printf(" where numtabs is the number of tables with name TESTxx\n" ); + printf(" and numrows is number of rows per fetch cycle\n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + numrows = atoi((char *)argv[2]); + printf("\n Number of rows to be fetched per cycle is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":tabname", -1, + (ub1 *)tabname, (sword)sizeof(tabname), + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((ub4)(numrows*sizeof(sb2))); + colsptr->c_rlen = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_rcode = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_buf = (ub1 *)malloc((ub4)(numrows*colsptr->c_size)); + + if (odefin(&cda, colindex + 1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, (text *)0, -1, -1, + colsptr->c_rlen, colsptr->c_rcode)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + printf("\n printing column information for table %s :\n\n", tabname); + + /* don't cancel the cursor after the first execute/fetch */ + /* also don't want an exact match */ + if (oexfet(&cda, (ub4)numrows, 0, 0) != 0 && cda.rc != NO_DATA_FOUND) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + dump_data(); + + if (cda.rc == NO_DATA_FOUND) + { + row_count = 0; + return; /* no more rows to fetch */ + } + + while(1) /* we definitely have more rows to fetch */ + { + ofen(&cda, numrows); /* next fetch cycle */ + + if ((cda.rc == NO_DATA_FOUND) && ((cda.rpc - row_count) == 0)) + break; + + if ((cda.rc == 0) || + (cda.rc == NO_DATA_FOUND) && (cda.rpc - row_count)> 0) + { + dump_data(); + if ((cda.rc == NO_DATA_FOUND) && (cda.rpc == row_count)) + break; + } + + else + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + } + + row_count = 0; /* reset running counter for next table */ +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + + uword index; + ub4 value; + for (index = 0; index < cda.rpc - row_count; index++) + { + + printf(" column %d name is %s\n", row_count + index + 1 , + cols[0].c_buf + index * cols[0].c_size); + + memcpy((dvoid *)&value, (dvoid *)(cols[1].c_buf + index * cols[1].c_size), + *(cols[1].c_rlen + index)); + printf(" column %d length is %d \n", row_count + index + 1 , value); + + memcpy((dvoid *)&value, (dvoid *)(cols[2].c_buf + index * cols[2].c_size), + *(cols[2].c_rlen + index)); + printf(" column %d id is %d \n", row_count + index + 1 , value); + + } + + row_count += cda.rpc - row_count; /* we only need the increment */ + + printf(" ==> Total rows so far is %d\n", row_count); +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci08.sql b/oci08.sql new file mode 100644 index 0000000..953deff --- /dev/null +++ b/oci08.sql @@ -0,0 +1,64 @@ +rem +rem $Header: oci08.sql 11-oct-2006.15:55:32 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci08.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci08.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + SELECT o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + FROM sys.col$ c$, sys.obj$ o$ + WHERE o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* user version for ocitest */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (one number, two long, three date, four char(10)); +create table test5( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char); +create table test6( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char, col11 number, col12 char, + col13 number, col14 char, col15 number, col16 char, + col17 number, col18 char, col19 number); +create table test7 (one number, two long, three date, four char(10), + five number, six number, seven number, eight number, + nine char(1), ten varchar(2000)); diff --git a/oci09.c b/oci09.c new file mode 100644 index 0000000..1f6d1f7 --- /dev/null +++ b/oci09.c @@ -0,0 +1,347 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci09.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests single row fetch via PL/SQL procedures + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci09.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number. + * + * It illustrates getting data back using SINGLE ROW FETCH + * through a PLSQL PROCEDURE + * It also illustrates re-executing the same query again without + * having to rebind + * + * Based on: oci04.c + * Changes: changed odefin to obndra calls + * no fetch cycle, execute does the fetch now + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - the number of tables + * + * oci09 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none Use obndra for plsql parameters + * Execute - oexec + * Fetch - none Execute gets data back + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ + + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"\ + begin \ + oci09pkg.oci09proc(:tabname, :cname, :collen, :colid);\ + end;"; + +/* return values from query - kept as globals for simplicity */ +uword colid; +uword collen; +text cname [MAX_NAME_LENGTH+1]; + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 2) + { + printf("\n\n Usage: where numtabs is the number of \ +tables with name TESTxx \n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":tabname", -1, /* bind */ + (ub1 *)tabname, (sword)sizeof(tabname), + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":cname", -1, /* bind */ + (ub1 *)cname, (sword)sizeof(cname), + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":collen", -1, /* bind */ + (ub1 *)&collen, (sword)sizeof(collen), + SQLT_INT, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":colid", -1, /* bind */ + (ub1 *)&colid, (sword)sizeof(colid), + SQLT_INT, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + printf("\n printing column information for table %s :\n\n", tabname); + + while (oexec(&cda) == 0) + { + row_count++; /* bump this for printing purposes */ + dump_data(); + } + + if (cda.rc != NULL_VALUE_RETURNED) + err_report(&cda); + + row_count = 0; /* reset for next table */ +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + printf(" column %d name is %s\n", row_count, cname); + printf(" column %d length is %d \n", row_count, collen); + printf(" column %d id is %d \n", row_count, colid); + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci09.sql b/oci09.sql new file mode 100644 index 0000000..7e1daf2 --- /dev/null +++ b/oci09.sql @@ -0,0 +1,108 @@ +rem +rem $Header: oci09.sql 11-oct-2006.15:55:32 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci09.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci09.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem aliu 01/05/06 - add order by in the select statements from +rem ocicolu to fix intermittent diffs +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + select o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + from sys.col$ c$, sys.obj$ o$ + where o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* current user's columns */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (one number, two long, three date, four char(10)); +create table test5( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char); +create table test6( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char, col11 number, col12 char, + col13 number, col14 char, col15 number, col16 char, + col17 number, col18 char, col19 number); + +create table debug_cursor (col1 char); +create table debug_result (col1 varchar2(20)); +create or replace package oci09pkg as + + procedure oci09proc( + tabname in varchar2, + colname out varchar2, + collen out varchar2, + colid out varchar2); +end; +/ + +create or replace package body oci09pkg as + + cursor get_col( + table_name in varchar2) is + select cname, clength, colid from ocicolu + where tname = table_name order by colid; + + procedure oci09proc( + tabname in varchar2, + colname out varchar2, + collen out varchar2, + colid out varchar2) is + + begin + + if NOT get_col%ISOPEN then + open get_col(tabname); + insert into debug_cursor values('y'); + else + insert into debug_cursor values('n'); + end if; + + fetch get_col into colname, collen, colid; + + if get_col%NOTFOUND then + close get_col; + end if; -- close the cursor for the next table + + insert into debug_result values (colname); + commit; + end; + +end; +/ + diff --git a/oci10.c b/oci10.c new file mode 100644 index 0000000..17b5a20 --- /dev/null +++ b/oci10.c @@ -0,0 +1,487 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci10.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array fetch using PL/SQL procedures via PL/SQL arrays + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci10.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number. + * + * It illustrates getting data back using ARRAY FETCH + * through a PLSQL PROCEDURE + * It also illustrates re-executing the same query again without + * having to rebind + * The user can create multiple TESTxx tables + * The user can enter the number of rows to be fetched on each + * cycle + * + * Based on: oci07.c + * Changes: changed odefin to obndra calls + * no fetch cycle, execute does the fetch now + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires TWO arguments: + * - the number of tables + * - the number of rows to fetch per cycle + * + * oci10 4 3 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none Use obndra for plsql parameters + * Execute - oexec For the plsql procedure + * Fetch - none Execute gets data back + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"\ + begin \ + oci10pkg.oci10proc(:cname, :collen, :colid, :tabname,\ + :batch_size, :num_ret, :done_fetch);\ + end;"; + +#define NUMCOLS 3 /* number of columns returned by above query */ +sword num_ret; /* number of rows ACTUALLY returned from procedure */ +sword done_fetch; /* any more rows to fetch for this table? */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = /* query returns one char and two numbers */ + { {MAX_NAME_LENGTH+1, SQLT_STR}, + {sizeof(eword), SQLT_INT}, + {sizeof(eword), SQLT_INT} + }; + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + ub4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +#define BUG207799 + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 3) + { + printf("\n\n Usage: \n"); + printf(" where numtabs is the number of tables with name TESTxx\n" ); + printf(" and numrows is number of rows per fetch cycle\n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + numrows = atoi((char *)argv[2]); + printf("\n Number of rows to be fetched per cycle is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + /* bind all the scalar values */ + if (obndra(&cda, (text *)":tabname", -1, + (ub1 *)tabname, (sword)sizeof(tabname), + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":batch_size", -1, + (ub1 *)&numrows, (sword)sizeof(numrows), + SQLT_INT, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":num_ret", -1, + (ub1 *)&num_ret, (sword)sizeof(num_ret), + SQLT_INT, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":done_fetch", -1, + (ub1 *)&done_fetch, (sword)sizeof(done_fetch), + SQLT_INT, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((ub4)(numrows*sizeof(sb2))); + colsptr->c_rlen = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_rcode = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_buf = (ub1 *)malloc((ub4)(numrows*colsptr->c_size)); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + + if (obndra(&cda, (text *)":cname", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)numrows, &(colsptr->c_curlen), + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + + case(1) : + + if (obndra(&cda, (text *)":collen", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)numrows, &(colsptr->c_curlen), + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + + case(2) : + + if (obndra(&cda, (text *)":colid", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)numrows, &(colsptr->c_curlen), + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + colp *colsptr; + uword colindex; + + printf("\n printing column information for table %s :\n\n", tabname); + + row_count = 0; + done_fetch = FALSE; + while(!done_fetch) + { + +#ifdef BUG207799 + /* bug 207799 - need to reset the curlen to zero */ + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++,colsptr++) + colsptr->c_curlen = 0; +#endif /* BUG 207799 */ + + oexec(&cda); + + if (cda.rc == 0) + { + if (num_ret > 0) + dump_data(); + } + else + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + } + + row_count = 0; /* reset running counter for next table */ +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + + uword index; + ub4 value; + for (index = 0; index < num_ret; index++) + { + + printf(" column %d name is %s\n", row_count + index + 1 , + cols[0].c_buf + index * cols[0].c_size); + + memcpy((dvoid *)&value, (dvoid *)(cols[1].c_buf + index * cols[1].c_size), + *(cols[1].c_rlen + index)); + printf(" column %d length is %d \n", row_count + index + 1 , value); + + memcpy((dvoid *)&value, (dvoid *)(cols[2].c_buf + index * cols[2].c_size), + *(cols[2].c_rlen + index)); + printf(" column %d id is %d \n", row_count + index + 1 , value); + + } + + row_count += num_ret; /* we only need the increment */ + + printf(" ==> Total rows so far is %d\n", row_count); +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci10.sql b/oci10.sql new file mode 100644 index 0000000..deccf6c --- /dev/null +++ b/oci10.sql @@ -0,0 +1,120 @@ +rem +rem $Header: oci10.sql 11-oct-2006.15:55:32 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci10.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci10.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem aliu 01/10/06 - add order by in the select from ocicolu to fix +rem intermittent diffs +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + select o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + from sys.col$ c$, sys.obj$ o$ + where o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* current user's columns */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem Create a new user - call it ocitest +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (one number, two long, three date, four char(10)); +create table test5( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char); +create table test6( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char, col11 number, col12 char, + col13 number, col14 char, col15 number, col16 char, + col17 number, col18 char, col19 number); + +create or replace package oci10pkg as + + type char_array is table of varchar2(20) index by binary_integer; + type num_array is table of integer index by binary_integer; + + procedure oci10proc( + cname out char_array, -- array to put cname in + collen out num_array, -- array to put column lengths in + colid out num_array, -- array to put column ids in + tabname in varchar2, -- table name to get col definitions + batchsize in integer, -- number of rows per trip + numret in out integer, -- number of rows ACTUALLY RETURNED + donefetch in out integer); -- are we done fetching for this + -- table +end; +/ + +create or replace package body oci10pkg as + + cursor get_col( + table_name in varchar2) is + select cname, clength, colid from ocicolu + where tname = table_name order by colid; + + + procedure oci10proc( + cname out char_array, + collen out num_array, + colid out num_array, + tabname in varchar2, + batchsize in integer, + numret in out integer, + donefetch in out integer + ) is + + begin + + donefetch := 0; + numret := 0; + + if NOT get_col%ISOPEN then + open get_col(tabname); + end if; + + for i in 1..batchsize loop + fetch get_col + into cname(i), collen(i), colid(i); + + if get_col%NOTFOUND then + close get_col; + donefetch := 1; + exit; + else + numret := numret + 1; + end if; + end loop; + + end; + +end; +/ diff --git a/oci11.c b/oci11.c new file mode 100644 index 0000000..52cf897 --- /dev/null +++ b/oci11.c @@ -0,0 +1,435 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci11.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array fetch using PL/SQL procedures via cursor variables + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ +/* + * Name: oci11.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number. + * + * It illustrates getting data back using ARRAY FETCH + * through a PLSQL PROCEDURE using a RESULT SET + * It also illustrates re-executing the same query again without + * having to rebind + * The user can create multiple TESTxx tables + * The user can enter the number of rows to be fetched on each + * cycle + * + * Based on: oci08.c + * Changes: second cursor now returned from within plsql procedure + * define calls needed based on second cursor + * fetch cyle on second cursor, exec on first cursor + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires TWO arguments: + * - the number of tables + * - the number of rows to fetch per cycle + * + * oci11 4 3 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - odefin This is for the returned cursor + * Execute - oexec For the plsql procedure + * Fetch - ofen Fetch for second cursor. + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ +Cda_Def cursor2; + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"\ + begin \ + oci11pkg.oci11proc(:curs,:tabname);\ + end;"; + +#define NUMCOLS 3 /* number of columns returned by above query */ +sword num_ret; /* number of rows ACTUALLY returned from procedure */ +sword done_fetch; /* any more rows to fetch for this table? */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = /* query returns one char and two numbers */ + { {MAX_NAME_LENGTH+1, SQLT_STR}, + {sizeof(eword), SQLT_INT}, + {sizeof(eword), SQLT_INT} + }; + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + ub4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 3) + { + printf("\n\n Usage: \n"); + printf(" where numtabs is the number of tables with name TESTxx\n" ); + printf(" and numrows is number of rows per fetch cycle\n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + numrows = atoi((char *)argv[2]); + printf("\n Number of rows to be fetched per cycle is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + get_data(); + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + memset((dvoid *)&cursor2, 0, sizeof(Cda_Def)); + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + /* bind all the scalar values */ + if (obndra(&cda, (text *)":curs", -1, + (ub1 *)&cursor2, -1, + SQLT_CUR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":tabname", -1, + (ub1 *)tabname, 31, + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + colp *colsptr; + uword colindex; + printf("\n printing column information for table %s :\n\n", tabname); + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((ub4)(numrows*sizeof(sb2))); + colsptr->c_rlen = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_rcode = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_buf = (ub1 *)malloc((ub4)(numrows*colsptr->c_size)); + colsptr->c_curlen = 0; + + if (odefin(&cursor2, colindex + 1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, (text *)0, -1, -1, + colsptr->c_rlen, colsptr->c_rcode)) + { + err_report(&cursor2); + do_exit(OCI_EXIT_FAILURE); + } + } + + + while(1) /* we definitely have more rows to fetch */ + { + + ofen(&cursor2, numrows); /* next fetch cycle */ + + if ((cursor2.rc == NO_DATA_FOUND) && ((cursor2.rpc - row_count) == 0)) + break; + + if ((cursor2.rc == 0) || + (cursor2.rc == NO_DATA_FOUND) && (cursor2.rpc - row_count)> 0) + { + dump_data(); + if ((cursor2.rc == NO_DATA_FOUND) && (cursor2.rpc == row_count)) + break; + } + + else + { + err_report(&cursor2); + do_exit(OCI_EXIT_FAILURE); + } + + } + row_count = 0; /* reset running counter for next table */ +} + + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + + uword index; + ub4 value; + for (index = 0; index < cursor2.rpc - row_count; index++) + { + + printf(" column %d name is %s\n", row_count + index + 1 , + cols[0].c_buf + index * cols[0].c_size); + + memcpy((dvoid *)&value, (dvoid *)(cols[1].c_buf + index * cols[1].c_size), + *(cols[1].c_rlen + index)); + printf(" column %d length is %d \n", row_count + index + 1 , value); + + memcpy((dvoid *)&value, (dvoid *)(cols[2].c_buf + index * cols[2].c_size), + *(cols[2].c_rlen + index)); + printf(" column %d id is %d \n", row_count + index + 1 , value); + + } + + row_count += cursor2.rpc - row_count; /* we only need the increment */ + + printf(" ==> Total rows so far is %d\n", row_count); +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} + diff --git a/oci11.sql b/oci11.sql new file mode 100644 index 0000000..0cb850c --- /dev/null +++ b/oci11.sql @@ -0,0 +1,93 @@ +rem +rem $Header: oci11.sql 11-oct-2006.15:55:33 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci11.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci11.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem aliu 01/05/06 - add order by in the select from ocicolu to fix +rem intermittent diffs +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + select o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + from sys.col$ c$, sys.obj$ o$ + where o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* current user's columns */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem Create a new user - call it ocitest +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (one number, two long, three date, four char(10)); +create table test5( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char); +create table test6( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char, col11 number, col12 char, + col13 number, col14 char, col15 number, col16 char, + col17 number, col18 char, col19 number); + +create or replace package oci11pkg as + + type rectype is record (cname ocicolu.cname%type, + clength ocicolu.clength%type, + colid ocicolu.colid%type); + type ctype is ref cursor return rectype; + + procedure oci11proc( + curs in out ctype, + tabname in varchar2); + +end; +/ + +create or replace package body oci11pkg as + + procedure oci11proc( + curs in out ctype, + tabname in varchar2 + + ) is + + begin + + open curs for + select cname, clength, colid + from ocicolu + where tname = tabname order by colid; + + + end; + +end; +/ diff --git a/oci12.c b/oci12.c new file mode 100644 index 0000000..e203f81 --- /dev/null +++ b/oci12.c @@ -0,0 +1,352 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci12.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests single row fetch of LONG data with piecewise fetch + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ +/* + * Name: oci12.c + * + * Description: This program retrieves the rows contained in oci11tab which + * contains a long. Some rows have to be fetched piecewise. + * + * It illustrates getting data back using SINGLE ROW FETCH + * via a SELECT statement. + * It illustrates how to do a piecewise fetch of a long. + * Fetching 5 characters per long fetch + * + * Based on: oci04.c + * Changes: added long support + * hardcoded oci12tab in query + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires NO arguments + * + * oci12 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexec + * Fetch - ofetch, oflng Long fetch + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ + + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); +void fetch_long(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT col1, col2 FROM oci12tab ORDER BY col1"; + +/* return values from query - kept as globals for simplicity */ + +#define LONG_SIZE 5 /* getting back 5 chars per long fetch */ +sword col1; +text col2 [LONG_SIZE + 1]; +sb2 col2_ind; /* indicator variable for col2 */ +ub2 col2_rlen; /* return length for col2 */ + +main(argc, argv) +eword argc; +text **argv; +{ + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + get_data(); /* retrieve data */ + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 1, (ub1 *) &col1, (sword) sizeof(col1), /* define */ + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + /* save one character for null termination */ + if (odefin(&cda, 2, (ub1 *) col2, (sword) (sizeof(col2) - 1), + (sword) SQLT_LNG, + (sword) -1, (sb2 *)&col2_ind, (text *) 0, -1, -1, + (ub2 *)&col2_rlen, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n Printing the data for table oci12tab \n"); + + while (ofetch(&cda) == 0) + { + row_count++; /* bump this for printing purposes */ + + col2[col2_rlen] = '\0'; /* have to null terminate */ + + dump_data(); + + if ((col2_ind == -2) || (col2_rlen < col2_ind)) + fetch_long(); + + printf("\n"); + } + + if (cda.rc != NO_DATA_FOUND) + err_report(&cda); + +} + +/* + * Function: fetch_long + * + * Description: This routine retrieves the rest of a long row in pieces + * + */ +void fetch_long() +{ + + ub4 offset = col2_rlen; + /* we have already fetched col2_rlen characters so this is where the offset + starts for the next fetch cycle */ + ub4 piece = 0; + + printf(" \n", row_count); + + do + { + + if (oflng(&cda, 2, (ub1 *)col2, (sb4)(sizeof(col2) - 1), SQLT_LNG, + &piece, offset)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (piece) /* did we get anything? */ + { + printf(" received %d characters ", piece); + col2[piece] ='\0'; + printf(" data piece is %s\n", col2); + } + + offset += piece; /* bump the offset and keep going */ + + } while (piece == LONG_SIZE); + +} + + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + + printf(" row %d col1 is %d\n", row_count, col1); + printf(" row %d col2 is %s \n", row_count, col2); + +} + + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} + diff --git a/oci12.sql b/oci12.sql new file mode 100644 index 0000000..b3eb216 --- /dev/null +++ b/oci12.sql @@ -0,0 +1,43 @@ +rem +rem $Header: oci12.sql 11-oct-2006.15:55:33 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci12.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci12.c +rem RETURNS +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci12tab (col1 number, col2 long); + +insert into oci12tab values(1, 'A'); +insert into oci12tab values(2, 'AB'); +insert into oci12tab values(3, 'ABC'); +insert into oci12tab values(4, 'ABCDEFGHIJKLM'); +insert into oci12tab values(5, 'ABCD'); +insert into oci12tab values(6, 'ABCDE'); +insert into oci12tab values(7, 'ABCDEFGHIJ'); +insert into oci12tab values(8, '1'); +insert into oci12tab values(9, '12'); +insert into oci12tab values(10, '123'); +insert into oci12tab values(11, '123456789'); +insert into oci12tab values(12, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'); +commit; diff --git a/oci13.c b/oci13.c new file mode 100644 index 0000000..d4c3e58 --- /dev/null +++ b/oci13.c @@ -0,0 +1,504 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci13.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array fetch of LONG data with piecewise fetching + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci13.c + * + * Description: This program retrieves the rows contained in oci13tab which + * contains a long. Some rows have to be fetched piecewise. + * + * It illustrates getting data back using ARRAY FETCH + * via a SELECT statement. + * It illustrates how to do a piecewise fetch of a long. + * Fetching 5 characters per long fetch + * With an array fetch, piecewise longs will have to be + * fetched with a different cursor + * + * Based on: oci07.c + * Changes: added long support + * hardcoded oci13tab in query + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows per + * fetch cycle + * + * oci13 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexec + * Fetch - ofetch, oflng Long fetch + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +/* Globals needed */ +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows returned so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); +void fetch_long(); +void setup_long(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT col1, col2 FROM oci13tab ORDER BY col1"; + +#define NUMCOLS 2 /* number of columns returned by above query */ +#define LONG_SIZE 5 /* getting back 5 characters with each long piece */ +text col2[LONG_SIZE +1]; /* buffer to hold the long pieces */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {sizeof(eword), SQLT_INT}, + {LONG_SIZE, SQLT_LNG} + }; + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +Cda_Def cda_long; /* cursor area to get remaining long pieces */ + +text *long_sqlstmt = (text *)"SELECT col2 FROM oci13tab\ + where col1 = :row_number"; + +sword long_row_number; /* row number to fetch pieces for */ + + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: \ +where numrows is number of rows per fetch cycle\n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + printf("\n Number of rows to be fetched per cycle is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + setup_long(); /* prepare long query */ + + get_data(); /* retrieve data */ + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((ub4)(numrows*sizeof(sb2))); + colsptr->c_rlen = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_rcode = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_buf = (ub1 *)malloc((ub4)(numrows*colsptr->c_size)); + + if (odefin(&cda, colindex + 1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, (text *)0, -1, -1, + colsptr->c_rlen, colsptr->c_rcode)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + } + +} + +/* + * Function: setup_long + * + * Description: This routine allocates the second cursor needed to fetch + * the remaining piece of a long. + * + */ +void setup_long() +{ + + if (oopen(&cda_long, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda_long); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda_long, long_sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda_long); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndrv(&cda_long, (text *)":row_number", -1, + (ub1 *)&long_row_number, (sword)sizeof(long_row_number), + SQLT_INT, -1, (sb2 *) 0, (text *) 0, -1, -1)) /* bind */ + { + err_report(&cda_long); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda_long, 1, (ub1 *) col2, (sword) (sizeof(col2) - 1), + (sword) SQLT_LNG, + (sword) -1, (sb2 *)0, (text *) 0, -1, -1, + (ub2 *)0, (ub2 *) 0)) + { + err_report(&cda_long); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + printf("\n printing the information for oci13tab: \n"); + + /* don't cancel the cursor after the first execute/fetch */ + /* also don't want an exact match */ + if (oexfet(&cda, (ub4)numrows, 0, 0) != 0 && cda.rc != NO_DATA_FOUND) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + dump_data(); + + if (cda.rc == NO_DATA_FOUND) + { + row_count = 0; + return; /* no more rows to fetch */ + } + + while(1) + { + ofen(&cda, (sword)numrows); + + if ((cda.rc == NO_DATA_FOUND) && ((cda.rpc - row_count) == 0)) + break; + + if ((cda.rc == 0) || + (cda.rc == NO_DATA_FOUND) && (cda.rpc - row_count)> 0) + { + dump_data(); + if ((cda.rc == NO_DATA_FOUND) && (cda.rpc == row_count)) + break; + } + + else + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + } + + row_count = 0; /* reset running counter for next table */ +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + + uword index; + ub4 value; + text longbuf[LONG_SIZE + 1]; + + for (index = 0; index < cda.rpc - row_count; index++) + { + + + memcpy((dvoid *)&value, (dvoid *)(cols[0].c_buf + index * cols[0].c_size), + *(cols[0].c_rlen + index)); + printf(" row %d col1 is %d \n", row_count + index + 1 , value); + + memcpy((dvoid *)longbuf, (dvoid *)(cols[1].c_buf + index * cols[1].c_size), + cols[1].c_rlen[index]); + longbuf[cols[1].c_rlen[index]] = '\0'; /* need to null terminate */ + + printf(" row %d col2 is %s\n", row_count + index + 1 , longbuf); + + if ((cols[1].c_rlen[index] < cols[1].c_indp[index]) || + (cols[1].c_indp[index] == -2)) + { + long_row_number = row_count + index + 1; + fetch_long(cols[1].c_rlen[index]); + } + + printf("\n"); + + } + + row_count += cda.rpc - row_count; /* we only need the increment */ + + printf(" Total rows so far is %d\n", row_count); +} + +/* + * Function: fetch_long + * + * Description: This routine retrieves the rest of a long row in pieces + * + */ +void fetch_long(offset) +uword offset; +{ + + ub4 piece = 0; + + printf(" \n", long_row_number); + + /* we need exactly one row */ + if (oexfet(&cda_long, (ub4)1, 0, 0)) + { + err_report(&cda_long); + do_exit(OCI_EXIT_FAILURE); + } + + /* the above call returns the first piece of the long - we have already + printed it - so just ignore it */ + + do + { + + if (oflng(&cda_long, 1, (ub1 *)col2, (sb4)(sizeof(col2) - 1), SQLT_LNG, + &piece, (ub4)offset)) + { + err_report(&cda_long); + do_exit(OCI_EXIT_FAILURE); + } + + if (piece) /* did we get anything? */ + { + printf(" received %d characters ", piece); + col2[piece] ='\0'; + printf(" data piece is %s\n", col2); + } + + offset += piece; /* bump the offset and keep going */ + + } while (piece == LONG_SIZE); + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (oclose(&cda_long)) /* close LONG cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci13.sql b/oci13.sql new file mode 100644 index 0000000..80ba3ad --- /dev/null +++ b/oci13.sql @@ -0,0 +1,39 @@ +rem +rem $Header: oci13.sql 11-oct-2006.15:55:33 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci13.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci13.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci13tab (col1 number, col2 long); + +insert into oci13tab values(1, 'A'); +insert into oci13tab values(2, 'AB'); +insert into oci13tab values(3, 'ABC'); +insert into oci13tab values(4, 'ABCDEFGHIJKLM'); +insert into oci13tab values(5, 'ABCD'); +insert into oci13tab values(6, 'ABCDE'); +insert into oci13tab values(7, 'ABCDEFGHIJ'); +insert into oci13tab values(8, '1'); +insert into oci13tab values(9, '12'); +insert into oci13tab values(10, '123'); +insert into oci13tab values(11, '123456789'); +insert into oci13tab values(12, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'); +commit; diff --git a/oci14.c b/oci14.c new file mode 100644 index 0000000..5db5a37 --- /dev/null +++ b/oci14.c @@ -0,0 +1,387 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci14.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array insert + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + whe 10/20/99 - #1039217: add int for static variable pass + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci14.c + * + * Description: This program performs an array insert one column using + * an INSERT statement. + * Always inserting 5 rows at a time. + * + * Based on: none + * Changes: none + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows to insert + * + * oci14 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows inserted so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); +void initialize_data(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci14tab (col1) values (:col1)"; + +#define NUMCOLS 1 /* number of columns returned by above query */ +#define MAX_ROWS_PER_INSERT 5 /* 5 rows max per insert */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {MAX_NAME_LENGTH+1, SQLT_STR} + }; + + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + sb4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: where numrows is the number of \ +rows the user wants to insert \n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + if (numrows > 26) + { + printf("Please input a number under 26\n"); + do_exit(OCI_EXIT_FAILURE); + } + printf("\n Total number of rows to be inserted is %d\n", numrows); + + logon(); + + setup(); + + insert_data(); + + logoff(); + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(sb2))); + memset((dvoid *)colsptr->c_indp, 0, MAX_ROWS_PER_INSERT * sizeof(sb2)); + colsptr->c_rlen = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rlen, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_rcode = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rcode, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_buf = + (ub1 *)malloc((size_t)(MAX_ROWS_PER_INSERT*colsptr->c_size)); + memset((dvoid *)colsptr->c_buf, 0, MAX_ROWS_PER_INSERT * colsptr->c_size); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + +/* GOTCHA!!! - need to pass in zeroes for mal and cal parameters when + running a regular insert. Set it to non-zero when using plsql */ + if (obndra(&cda, (text *)":col1", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)0, (ub4 *)0, + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + colp *colsptr; + sword colindex; + sword numinsert; /* number of rows to insert on the current pass */ + + row_count = 0; + while (row_count < numrows) + { + + colsptr = cols; + numinsert = numrows - row_count < MAX_ROWS_PER_INSERT ? + numrows - row_count : MAX_ROWS_PER_INSERT; + + for (colindex = 0; colindex < NUMCOLS; colsptr++, colindex++) + initialize_data(colsptr->c_buf, colsptr->c_size, colsptr->c_rlen, + numinsert); + + /* using offset zero - we want all the rows right away */ + if (oexn(&cda, numinsert, 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + row_count += numinsert; + } + +} + +/* + * Function: initialize_data + * + * Description: This routine generates data for insertion + * + */ +void initialize_data(arr, len, flen, numinsert) +ub1 *arr; +sword len; +ub2 *flen; +sword numinsert; +{ + + static int pass = 0; + sword colindex; /* index */ + sword numchars; /* number of characters to extract */ + text *str = (text *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + + for (colindex = 0; colindex < numinsert; colindex++) + { + numchars = (pass * MAX_ROWS_PER_INSERT) + colindex + 1; + memcpy((dvoid *)(arr + colindex*len), (dvoid *)str, numchars); + *(arr + colindex*len + numchars ) = '\0'; /* null terminate */ + printf("iteration %d string is %s length is %d\n", + pass, arr + colindex *len, + strlen((char *)(arr + colindex *len))); + +/* GOTCHA!! - The null must be found within the length specified so add one */ +/* or just use the max length allowed for the array element */ + + *(flen + colindex) = strlen((char *)(arr + colindex*len)) + 1; + /* *(flen + colindex) = 30; <--- or use this */ + } + + pass++; + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci14.sql b/oci14.sql new file mode 100644 index 0000000..43514a8 --- /dev/null +++ b/oci14.sql @@ -0,0 +1,27 @@ +rem +rem $Header: oci14.sql 11-oct-2006.15:55:33 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci14.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci14.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci14tab (col1 varchar2(30)); + +commit; diff --git a/oci15.c b/oci15.c new file mode 100644 index 0000000..77fd0f9 --- /dev/null +++ b/oci15.c @@ -0,0 +1,393 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci15.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array insert with user prompt on each pass + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + whe 10/20/99 - #1039217: add int for static variable pass + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 09/11/97 - increase response buffer size to 3 + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ +/* + * Name: oci15.c + * + * Description: This program performs an array insert one column using + * an INSERT statement. + * Always inserting 5 rows at a time. + * + * Based on: oci14.c + * Changes: user to press enter after each cycle + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows to insert + * + * oci15 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows inserted so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); +void initialize_data(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci15tab (col1) values (:col1)"; + +#define NUMCOLS 1 /* number of columns returned by above query */ +#define MAX_ROWS_PER_INSERT 5 /* 5 rows max per insert */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {MAX_NAME_LENGTH+1, SQLT_STR} + }; + + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + sb4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: where numrows is the number of \ +rows the user wants to insert \n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + if (numrows > 26) + { + printf("Please input a number under 26\n"); + do_exit(OCI_EXIT_FAILURE); + } + printf("\n Total number of rows to be inserted is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(sb2))); + memset((dvoid *)colsptr->c_indp, 0, MAX_ROWS_PER_INSERT * sizeof(sb2)); + colsptr->c_rlen = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rlen, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_rcode = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rcode, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_buf = + (ub1 *)malloc((size_t)(MAX_ROWS_PER_INSERT*colsptr->c_size)); + memset((dvoid *)colsptr->c_buf, 0, MAX_ROWS_PER_INSERT * colsptr->c_size); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + +/* GOTCHA!!! - need to pass in zeroes for mal and cal parameters when + running a regular insert. Set it to non-zero when using plsql */ + if (obndra(&cda, (text *)":col1", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)0, (ub4 *)0, + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + colp *colsptr; + sword colindex; + sword numinsert; /* number of rows to insert on the current pass */ + text response[3]; + + row_count = 0; + while (row_count < numrows) + { + + colsptr = cols; + numinsert = numrows - row_count < MAX_ROWS_PER_INSERT ? + numrows - row_count : MAX_ROWS_PER_INSERT; + + for (colindex = 0; colindex < NUMCOLS; colsptr++, colindex++) + initialize_data(colsptr->c_buf, colsptr->c_size, colsptr->c_rlen, + numinsert); + + /* using offset zero - we want all the rows right away */ + if (oexn(&cda, numinsert, 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n Do a select * from the table in another window \n"); + printf(" Then press return to continue -->"); + gets((char *)response); + + row_count += numinsert; + } + +} + +/* + * Function: initialize_data + * + * Description: This routine generates data for insertion + * + */ +void initialize_data(arr, len, flen, numinsert) +ub1 *arr; +sword len; +ub2 *flen; +sword numinsert; +{ + + static int pass = 0; + sword colindex; /* index */ + sword numchars; /* number of characters to extract */ + text *str = (text *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + + for (colindex = 0; colindex < numinsert; colindex++) + { + numchars = (pass * MAX_ROWS_PER_INSERT) + colindex + 1; + memcpy((dvoid *)(arr + colindex*len), (dvoid *)str, numchars); + *(arr + colindex*len + numchars ) = '\0'; /* null terminate */ + printf("iteration %d string is %s length is %d\n", + pass, arr + colindex *len, + strlen((char *)(arr + colindex *len))); + +/* GOTCHA!! - The null must be found within the length specified so add one */ +/* or just use the max length allowed for the array element */ + + *(flen + colindex) = strlen((char *)(arr + colindex*len)) + 1; + /* *(flen + colindex) = 30; <--- or use this */ + } + + pass++; + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} + diff --git a/oci15.sql b/oci15.sql new file mode 100644 index 0000000..e6a3cbd --- /dev/null +++ b/oci15.sql @@ -0,0 +1,27 @@ +rem +rem $Header: oci15.sql 11-oct-2006.15:55:33 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci15.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci15.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci15tab (col1 varchar2(30)); + +commit; diff --git a/oci16.c b/oci16.c new file mode 100644 index 0000000..eb10036 --- /dev/null +++ b/oci16.c @@ -0,0 +1,432 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci16.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array insert with autocommit on/off demonstration + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + whe 10/20/99 - #1039217: add int for static variable pass + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 09/11/97 - increase response buffer size to 3 + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci16.c + * + * Description: This program performs an array insert one column using + * an INSERT statement. + * Always inserting 5 rows at a time. + * User presses enter at each cycle. Autocommit is turned + * at each odd pass and turned on at each even pass + * + * Based on: oci15.c + * Changes: user to press enter after each cycle + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows to insert + * + * oci16 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * Commit On - ocon + * Commit Off- ocof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows inserted so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); +void initialize_data(); +void toggle_autocommit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci16tab (col1) values (:col1)"; + +#define NUMCOLS 1 /* number of columns returned by above query */ +#define MAX_ROWS_PER_INSERT 5 /* 5 rows max per insert */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {MAX_NAME_LENGTH+1, SQLT_STR} + }; + + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + sb4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: where numrows is the number of \ +rows the user wants to insert \n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + if (numrows > 26) + { + printf("Please input a number under 26\n"); + do_exit(OCI_EXIT_FAILURE); + } + printf("\n Total number of rows to be inserted is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(sb2))); + memset((dvoid *)colsptr->c_indp, 0, MAX_ROWS_PER_INSERT * sizeof(sb2)); + colsptr->c_rlen = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rlen, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_rcode = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rcode, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_buf = + (ub1 *)malloc((size_t)(MAX_ROWS_PER_INSERT*colsptr->c_size)); + memset((dvoid *)colsptr->c_buf, 0, MAX_ROWS_PER_INSERT * colsptr->c_size); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + +/* GOTCHA!!! - need to pass in zeroes for mal and cal parameters when + running a regular insert. Set it to non-zero when using plsql */ + if (obndra(&cda, (text *)":col1", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)0, (ub4 *)0, + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + colp *colsptr; + sword colindex; + sword numinsert; /* number of rows to insert on the current pass */ + text response[3]; + + row_count = 0; + while (row_count < numrows) + { + + toggle_autocommit(); + + colsptr = cols; + numinsert = numrows - row_count < MAX_ROWS_PER_INSERT ? + numrows - row_count : MAX_ROWS_PER_INSERT; + + for (colindex = 0; colindex < NUMCOLS; colsptr++, colindex++) + initialize_data(colsptr->c_buf, colsptr->c_size, colsptr->c_rlen, + numinsert); + + /* using offset zero - we want all the rows right away */ + if (oexn(&cda, numinsert, 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n Do a select * from the table in another window \n"); + printf(" Then press return to continue -->"); + gets((char *)response); + + row_count += numinsert; + } + +} + +/* + * Function: initialize_data + * + * Description: This routine generates data for insertion + * + */ +void initialize_data(arr, len, flen, numinsert) +ub1 *arr; +sword len; +ub2 *flen; +sword numinsert; +{ + + static int pass = 0; + sword colindex; /* index */ + sword numchars; /* number of characters to extract */ + text *str = (text *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + + for (colindex = 0; colindex < numinsert; colindex++) + { + numchars = (pass * MAX_ROWS_PER_INSERT) + colindex + 1; + memcpy((dvoid *)(arr + colindex*len), (dvoid *)str, numchars); + *(arr + colindex*len + numchars ) = '\0'; /* null terminate */ + printf("iteration %d string is %s length is %d\n", + pass, arr + colindex *len, + strlen((char *)(arr + colindex *len))); + +/* GOTCHA!! - The null must be found within the length specified so add one */ +/* or just use the max length allowed for the array element */ + + *(flen + colindex) = strlen((char *)(arr + colindex*len)) + 1; + /* *(flen + colindex) = 30; <--- or use this */ + } + + pass++; + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} + + +/* + * Function: logoff + * + * Description: This routine toggles between turning autocommit off and on + * with each pass. + * + */ +void toggle_autocommit() +{ + + static sword odd_pass = 1; + + if ((odd_pass % 2 ) == 0) + { + if (ocon(&lda)) + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + } + else + { + if (ocof(&lda)) + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + } + odd_pass++; +} diff --git a/oci16.sql b/oci16.sql new file mode 100644 index 0000000..016fa16 --- /dev/null +++ b/oci16.sql @@ -0,0 +1,28 @@ +rem +rem $Header: oci16.sql 11-oct-2006.15:55:34 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci16.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci16.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci16tab (col1 varchar2(30)); + +commit; + diff --git a/oci17.c b/oci17.c new file mode 100644 index 0000000..0519ef7 --- /dev/null +++ b/oci17.c @@ -0,0 +1,433 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci17.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array insert with demonstration of commit/rollback + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + whe 10/20/99 - #1039217: add int for static variable pass + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 09/11/97 - increase response buffer size to 3 + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci17.c + * + * Description: This program performs an array insert one column using + * an INSERT statement. + * Always inserting 5 rows at a time. + * User presses enter at each cycle. Commit and rollback + * on every other pass. + * + * Based on: oci15.c + * Changes: user to press enter after each cycle + * added ocom and orol calls + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows to insert + * + * oci17 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * Commit - ocom + * Rollback - orol + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows inserted so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); +void initialize_data(); +void toggle_com_rol(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci17tab (col1) values (:col1)"; + +#define NUMCOLS 1 /* number of columns returned by above query */ +#define MAX_ROWS_PER_INSERT 5 /* 5 rows max per insert */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {MAX_NAME_LENGTH+1, SQLT_STR} + }; + + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + sb4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: where numrows is the number of \ +rows the user wants to insert \n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + if (numrows > 26) + { + printf("Please input a number under 26\n"); + do_exit(OCI_EXIT_FAILURE); + } + printf("\n Total number of rows to be inserted is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statment */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(sb2))); + memset((dvoid *)colsptr->c_indp, 0, MAX_ROWS_PER_INSERT * sizeof(sb2)); + colsptr->c_rlen = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rlen, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_rcode = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rcode, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_buf = + (ub1 *)malloc((size_t)(MAX_ROWS_PER_INSERT*colsptr->c_size)); + memset((dvoid *)colsptr->c_buf, 0, MAX_ROWS_PER_INSERT * colsptr->c_size); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + +/* GOTCHA!!! - need to pass in zeroes for mal and cal parameters when + running a regular insert. Set it to non-zero when using plsql */ + if (obndra(&cda, (text *)":col1", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)0, (ub4 *)0, + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + colp *colsptr; + sword colindex; + sword numinsert; /* number of rows to insert on the current pass */ + text response[3]; + + row_count = 0; + while (row_count < numrows) + { + + toggle_com_rol(); + + colsptr = cols; + numinsert = numrows - row_count < MAX_ROWS_PER_INSERT ? + numrows - row_count : MAX_ROWS_PER_INSERT; + + for (colindex = 0; colindex < NUMCOLS; colsptr++, colindex++) + initialize_data(colsptr->c_buf, colsptr->c_size, colsptr->c_rlen, + numinsert); + + /* using offset zero - we want all the rows right away */ + if (oexn(&cda, numinsert, 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n Do a select * from the table in another window \n"); + printf(" Then press return to continue -->"); + gets((char *)response); + + row_count += numinsert; + } + +} + +/* + * Function: initialize_data + * + * Description: This routine generates data for insertion + * + */ +void initialize_data(arr, len, flen, numinsert) +ub1 *arr; +sword len; +ub2 *flen; +sword numinsert; +{ + + static int pass = 0; + sword colindex; /* index */ + sword numchars; /* number of characters to extract */ + text *str = (text *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + + for (colindex = 0; colindex < numinsert; colindex++) + { + numchars = (pass * MAX_ROWS_PER_INSERT) + colindex + 1; + memcpy((dvoid *)(arr + colindex*len), (dvoid *)str, numchars); + *(arr + colindex*len + numchars ) = '\0'; /* null terminate */ + printf("iteration %d string is %s length is %d\n", + pass, arr + colindex *len, + strlen((char *)(arr + colindex *len))); + +/* GOTCHA!! - The null must be found within the length specified so add one */ +/* or just use the max length allowed for the array element */ + + *(flen + colindex) = strlen((char *)(arr + colindex*len)) + 1; + /* *(flen + colindex) = 30; <--- or use this */ + } + + pass++; + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} + + +/* + * Function: toggle_com_rol + * + * Description: This routine toggles between rollback and commit calls + * with each pass. + * + */ +void toggle_com_rol() +{ + + static sword odd_pass = 1; + + if ((odd_pass % 2 ) == 0) + { + if (orol(&lda)) + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + } + else + { + if (ocom(&lda)) + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + } + odd_pass++; +} diff --git a/oci17.sql b/oci17.sql new file mode 100644 index 0000000..2cfffe1 --- /dev/null +++ b/oci17.sql @@ -0,0 +1,27 @@ +rem +rem $Header: oci17.sql 11-oct-2006.15:55:34 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci17.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci17.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci17tab (col1 varchar2(30)); + +commit; diff --git a/oci18.c b/oci18.c new file mode 100644 index 0000000..9a62cac --- /dev/null +++ b/oci18.c @@ -0,0 +1,417 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci18.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array insert via PL/SQL function + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + whe 10/20/99 - #1039217: add int for static variable pass + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci18.c + * + * Description: This program performs an array insert one column using + * an PLSQL FUNCTION. + * Always inserting 5 rows at a time. + * + * Based on: oci14.c + * Changes: made it a function + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows to insert + * + * oci18 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows inserted so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); +void initialize_data(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"\ + begin \ + :retval := oci18pkg.oci18func(:col1, :numins);\ + end;"; + +#define NUMCOLS 1 /* number of columns returned by above query */ +#define MAX_ROWS_PER_INSERT 5 /* 5 rows max per insert */ + +uword numinsert; /* number of rows to insert on the current pass */ +uword retval; /* return value from function */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {MAX_NAME_LENGTH+1, SQLT_STR} + }; + + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + sb4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: where numrows is the number of \ +rows the user wants to insert \n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + if (numrows > 26) + { + printf("Please input a number under 26\n"); + do_exit(OCI_EXIT_FAILURE); + } + printf("\n Total number of rows to be inserted is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statment */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + /* bind the scalar */ + + if (obndra(&cda, (text *)":numins", -1, + (ub1 *)&numinsert, (sword)sizeof(numinsert), + SQLT_INT, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":retval", -1, + (ub1 *)&retval, (sword)sizeof(retval), + SQLT_INT, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(sb2))); + memset((dvoid *)colsptr->c_indp, 0, MAX_ROWS_PER_INSERT * sizeof(sb2)); + colsptr->c_rlen = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rlen, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_rcode = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rcode, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_buf = + (ub1 *)malloc((size_t)(MAX_ROWS_PER_INSERT*colsptr->c_size)); + memset((dvoid *)colsptr->c_buf, 0, MAX_ROWS_PER_INSERT * colsptr->c_size); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + +/* GOTCHA!!! - need to pass in zeroes for mal and cal parameters when + running a regular insert. Set it to non-zero when using plsql */ + if (obndra(&cda, (text *)":col1", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)MAX_ROWS_PER_INSERT, (ub4 *)&(colsptr->c_curlen), + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + colp *colsptr; + sword colindex; + + row_count = 0; + while (row_count < numrows) + { + + colsptr = cols; + numinsert = numrows - row_count < MAX_ROWS_PER_INSERT ? + numrows - row_count : MAX_ROWS_PER_INSERT; + + for (colindex = 0; colindex < NUMCOLS; colsptr++, colindex++) + { + initialize_data(colsptr->c_buf, colsptr->c_size, colsptr->c_rlen, + numinsert); + colsptr->c_curlen = numinsert; + } + + /* using offset zero - we want all the rows right away */ + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf(" Number of rows processed so far is %d\n", retval); + + row_count += numinsert; + } + +} + +/* + * Function: initialize_data + * + * Description: This routine generates data for insertion + * + */ +void initialize_data(arr, len, flen, numinsert) +ub1 *arr; +sword len; +ub2 *flen; +sword numinsert; +{ + + static int pass = 0; + sword colindex; /* index */ + sword numchars; /* number of characters to extract */ + text *str = (text *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + + for (colindex = 0; colindex < numinsert; colindex++) + { + numchars = (pass * MAX_ROWS_PER_INSERT) + colindex + 1; + memcpy((dvoid *)(arr + colindex*len), (dvoid *)str, numchars); + *(arr + colindex*len + numchars ) = '\0'; /* null terminate */ + printf("iteration %d string is %s length is %d\n", + pass, arr + colindex *len, + strlen((char *)(arr + colindex *len))); + +/* GOTCHA!! - The null must be found within the length specified so add one */ +/* or just use the max length allowed for the array element */ + + *(flen + colindex) = strlen((char *)(arr + colindex*len)) + 1; + /* *(flen + colindex) = 30; <--- or use this */ + } + + pass++; + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci18.sql b/oci18.sql new file mode 100644 index 0000000..e7fd007 --- /dev/null +++ b/oci18.sql @@ -0,0 +1,63 @@ +rem +rem $Header: oci18.sql 11-oct-2006.15:55:34 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci18.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci18.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci18tab (col1 varchar2(30)); + +create or replace package oci18pkg as + + type char_array is table of varchar2(30) index by binary_integer; + + function oci18func( + col1 in char_array, -- array to put cname in + numins in integer) + return integer; + +end; +/ + +create or replace package body oci18pkg as + + + function oci18func( + col1 in char_array, + numins in integer + ) return integer is retval integer; + + begin + + for i in 1..numins loop + insert into oci18tab values (col1(i)); + end loop; + commit; + + retval := numins; + return(retval); + + end; + +end; +/ + +commit; + diff --git a/oci19.c b/oci19.c new file mode 100644 index 0000000..c9b7f18 --- /dev/null +++ b/oci19.c @@ -0,0 +1,403 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci19.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array insert with multiple retries + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + whe 10/20/99 - #1039217: add int for static variable pass + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + echen 03/11/97 - no stderr + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci19.c + * + * Description: This program performs an array insert one column using + * an INSERT statement. + * Always inserting 5 rows at a time. + * If one of the rows fails, retry the insert with the next + * row (offset) + * + * Based on: oci14.c + * Changes: added offset call + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows to insert + * + * oci19 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows inserted so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); +void initialize_data(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci19tab (col1) values (:col1)"; + +#define NUMCOLS 1 /* number of columns returned by above query */ +#define MAX_ROWS_PER_INSERT 5 /* 5 rows max per insert */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {MAX_NAME_LENGTH+1, SQLT_STR} + }; + + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + sb4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: where numrows is the number of \ +rows the user wants to insert \n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + if (numrows > 26) + { + printf("Please input a number under 26\n"); + do_exit(OCI_EXIT_FAILURE); + } + printf("\n Total number of rows to be inserted is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(sb2))); + memset((dvoid *)colsptr->c_indp, 0, MAX_ROWS_PER_INSERT * sizeof(sb2)); + colsptr->c_rlen = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rlen, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_rcode = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rcode, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_buf = + (ub1 *)malloc((size_t)(MAX_ROWS_PER_INSERT*colsptr->c_size)); + memset((dvoid *)colsptr->c_buf, 0, MAX_ROWS_PER_INSERT * colsptr->c_size); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + +/* GOTCHA!!! - need to pass in zeroes for mal and cal parameters when + running a regular insert. Set it to non-zero when using plsql */ + if (obndra(&cda, (text *)":col1", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)0, (ub4 *)0, + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + colp *colsptr; + sword colindex; + sword numinsert; /* number of rows to insert on the current pass */ + sword offset; /* offset for oexn call */ + + row_count = 0; + while (row_count < numrows) + { + + colsptr = cols; + numinsert = numrows - row_count < MAX_ROWS_PER_INSERT ? + numrows - row_count : MAX_ROWS_PER_INSERT; + + for (colindex = 0; colindex < NUMCOLS; colsptr++, colindex++) + initialize_data(colsptr->c_buf, colsptr->c_size, colsptr->c_rlen, + numinsert); + + offset = -1; /* first time oexn will have offset 0 */ + while (offset < numinsert) + { + offset++; + if (oexn(&cda, numinsert, offset)) + { + err_report(&cda); + } + + offset += cda.rpc; + + /* this case checks for the last row that failed insertion */ + if (offset + 1 == numinsert) + break; + + if (offset < numinsert) + printf("retrying with offset %d\n", offset + 1); + } + + row_count += numinsert; + } + +} + +/* + * Function: initialize_data + * + * Description: This routine generates data for insertion + * + */ +void initialize_data(arr, len, flen, numinsert) +ub1 *arr; +sword len; +ub2 *flen; +sword numinsert; +{ + + static int pass = 0; + sword colindex; /* index */ + sword numchars; /* number of characters to extract */ + text *str = (text *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + + for (colindex = 0; colindex < numinsert; colindex++) + { + numchars = (pass * MAX_ROWS_PER_INSERT) + colindex + 1; + memcpy((dvoid *)(arr + colindex*len), (dvoid *)str, numchars); + *(arr + colindex*len + numchars ) = '\0'; /* null terminate */ + printf("iteration %d string is %s length is %d\n", + pass, arr + colindex *len, + strlen((char *)(arr + colindex *len))); + +/* GOTCHA!! - The null must be found within the length specified so add one */ +/* or just use the max length allowed for the array element */ + + *(flen + colindex) = strlen((char *)(arr + colindex*len)) + 1; + /* *(flen + colindex) = 30; <--- or use this */ + } + + pass++; + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + printf("%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci19.sql b/oci19.sql new file mode 100644 index 0000000..df0950a --- /dev/null +++ b/oci19.sql @@ -0,0 +1,30 @@ +rem +rem $Header: oci19.sql 11-oct-2006.15:55:34 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci19.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci19.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci19tab (col1 varchar2(30) unique); +insert into oci19tab values ('AB'); +insert into oci19tab values ('ABCDEFG'); +insert into oci19tab values ('ABCDEFGHIJ'); +insert into oci19tab values ('ABCDEFGHIJKLMNO'); +commit; diff --git a/oci20.c b/oci20.c new file mode 100644 index 0000000..81e3ba7 --- /dev/null +++ b/oci20.c @@ -0,0 +1,415 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci20.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests OOPT call + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + whe 10/20/99 - #1039217: add int for static variable pass + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + echen 03/11/97 - no stderr + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci20.c + * + * Description: This program performs an array insert one column using + * an INSERT statement. + * Always inserting 5 rows at a time. + * If one of the rows fails, retry the insert with the next + * row (offset) + * Adding a nonblocking oopt call if table is locked + * + * Based on: oci19.c + * Changes: added offset call + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows to insert + * Lock table in another window before running this program + * + * oci20 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows inserted so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); +void initialize_data(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci20tab (col1) values (:col1)"; + +#define NUMCOLS 1 /* number of columns returned by above query */ +#define MAX_ROWS_PER_INSERT 5 /* 5 rows max per insert */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {MAX_NAME_LENGTH+1, SQLT_STR} + }; + + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + sb4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: where numrows is the number of \ +rows the user wants to insert \n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + if (numrows > 26) + { + printf("Please input a number under 26\n"); + do_exit(OCI_EXIT_FAILURE); + } + printf("\n Total number of rows to be inserted is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(sb2))); + memset((dvoid *)colsptr->c_indp, 0, MAX_ROWS_PER_INSERT * sizeof(sb2)); + colsptr->c_rlen = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rlen, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_rcode = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rcode, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_buf = + (ub1 *)malloc((size_t)(MAX_ROWS_PER_INSERT*colsptr->c_size)); + memset((dvoid *)colsptr->c_buf, 0, MAX_ROWS_PER_INSERT * colsptr->c_size); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + +/* GOTCHA!!! - need to pass in zeroes for mal and cal parameters when + running a regular insert. Set it to non-zero when using plsql */ + if (obndra(&cda, (text *)":col1", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)0, (ub4 *)0, + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +#define ROLLBACK_TXN 0 /* rollback entire transaction of non-fatal error */ + /* as documented, this behavior does not exist anymore */ +#define WAIT_OPTION 4 /* don't block for resources */ + + if (oopt(&cda, ROLLBACK_TXN, WAIT_OPTION)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + colp *colsptr; + sword colindex; + sword numinsert; /* number of rows to insert on the current pass */ + sword offset; /* offset for oexn call */ + + row_count = 0; + while (row_count < numrows) + { + + colsptr = cols; + numinsert = numrows - row_count < MAX_ROWS_PER_INSERT ? + numrows - row_count : MAX_ROWS_PER_INSERT; + + for (colindex = 0; colindex < NUMCOLS; colsptr++, colindex++) + initialize_data(colsptr->c_buf, colsptr->c_size, colsptr->c_rlen, + numinsert); + + offset = -1; /* first time oexn will have offset 0 */ + while (offset < numinsert) + { + offset++; + if (oexn(&cda, numinsert, offset)) + { + err_report(&cda); + } + + offset += cda.rpc; + + /* this case checks for the last row that failed insertion */ + if (offset + 1 == numinsert) + break; + + if (offset < numinsert) + printf("retrying with offset %d\n", offset + 1); + } + + row_count += numinsert; + } + +} + +/* + * Function: initialize_data + * + * Description: This routine generates data for insertion + * + */ +void initialize_data(arr, len, flen, numinsert) +ub1 *arr; +sword len; +ub2 *flen; +sword numinsert; +{ + + static int pass = 0; + sword colindex; /* index */ + sword numchars; /* number of characters to extract */ + text *str = (text *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + + for (colindex = 0; colindex < numinsert; colindex++) + { + numchars = (pass * MAX_ROWS_PER_INSERT) + colindex + 1; + memcpy((dvoid *)(arr + colindex*len), (dvoid *)str, numchars); + *(arr + colindex*len + numchars ) = '\0'; /* null terminate */ + printf("iteration %d string is %s length is %d\n", + pass, arr + colindex *len, + strlen((char *)(arr + colindex *len))); + +/* GOTCHA!! - The null must be found within the length specified so add one */ +/* or just use the max length allowed for the array element */ + + *(flen + colindex) = strlen((char *)(arr + colindex*len)) + 1; + /* *(flen + colindex) = 30; <--- or use this */ + } + + pass++; + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + printf("%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci20.sql b/oci20.sql new file mode 100644 index 0000000..d775d5a --- /dev/null +++ b/oci20.sql @@ -0,0 +1,30 @@ +rem +rem $Header: oci20.sql 11-oct-2006.15:55:34 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci20.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci20.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci20tab (col1 varchar2(30) unique); +insert into oci20tab values ('AB'); +insert into oci20tab values ('ABCDEFG'); +insert into oci20tab values ('ABCDEFGHIJ'); +insert into oci20tab values ('ABCDEFGHIJKLMNO'); +commit; diff --git a/oci21.c b/oci21.c new file mode 100644 index 0000000..f2f5043 --- /dev/null +++ b/oci21.c @@ -0,0 +1,278 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci21.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests non-blocking operations by changing a blocking connection to + non-blocking + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 09/11/97 - comment out printf when blocked + ehayes 05/29/97 - Fix olint errors + emendez 06/16/97 - + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci21.c + * + * Description: This program performs a "long" running hardcoded insert + * and demonstrates the use of non-blocking calls. + * + * Based on: - + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. Program requires no arguments. + * This demo assumes the existence of the alias inst1_nonblock + * in your tnsnames.ora file to access a non-blocking + * protocol + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * Nonblocking - onbtst, onbclr, onbset + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +#define BLOCKED -3123 +#define SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci21tab (col1)\ + SELECT a.col1 \ + FROM oci21tab a, oci21tab b"; + +main(argc, argv) +eword argc; +text **argv; +{ + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (onbset(&lda)) /* make the connection non-blocking */ + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + + if (onbtst(&lda)) /* verify that it is non-blocking */ + { + printf("connection is still blocking!!!\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + ub1 done = 0; + static ub1 printed = FALSE; /* just print blocked message once */ + while (!done) + { + switch(oexec(&cda)) + { + case BLOCKED:/* will come through here multiple times, print msg once */ +/* + if (!printed) + printf("Blocked - do something else while SQL stmt executes...\n"); + printed = TRUE; +*/ + break; + case SUCCESS: + done = 1; + break; + default: + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); /* get out of application */ + } + + } + + if (onbclr(&lda)) /* clear the non-blocking status of the connection */ + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", + -1, (text*)"inst1_nonblock" , -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci21.sql b/oci21.sql new file mode 100644 index 0000000..1a61513 --- /dev/null +++ b/oci21.sql @@ -0,0 +1,40 @@ +rem +rem $Header: oci21.sql 11-oct-2006.15:55:35 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci21.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci21.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci21tab (col1 varchar2(30)); +insert into oci21tab values ('A'); +insert into oci21tab values ('AB'); +insert into oci21tab values ('ABC'); +insert into oci21tab values ('ABCD'); +insert into oci21tab values ('ABCDE'); +insert into oci21tab values ('ABCDEF'); +insert into oci21tab values ('ABCDEFG'); +insert into oci21tab values ('ABCDEFGH'); +insert into oci21tab values ('ABCDEFGHI'); +insert into oci21tab values ('ABCDEFGHIJ'); +insert into oci21tab values ('ABCDEFGHIJK'); +insert into oci21tab values ('ABCDEFGHIJKL'); + +commit; + diff --git a/oci22.c b/oci22.c new file mode 100644 index 0000000..68b2561 --- /dev/null +++ b/oci22.c @@ -0,0 +1,293 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci22.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests non-blocking connections + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 09/11/97 - comment out printf when blocked + emendez 06/16/97 - + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci22.c + * + * Description: This program performs a "long" running hardcoded insert + * and demonstrates the use of non-blocking calls. + * + * Based on: oci21.c + * Changes: modified login to non-blocking + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. Program requires no arguments. + * This demo assumes the existence of the alias inst1_nonblock + * in your tnsnames.ora file to access a non-blocking + * protocol + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog use nonblocking argument + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * Nonblocking - onbtst, onbclr + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +#define BLOCKED -3123 +#define SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci22tab (col1)\ + SELECT a.col1 \ + FROM oci22tab a, oci22tab b"; + +main(argc, argv) +eword argc; +text **argv; +{ + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (onbtst(&lda)) + { + printf("connection is still blocking!!!\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + ub1 done = 0; + static ub1 printed = FALSE; /* just print blocked message once */ + while (!done) + { + switch(oexec(&cda)) + { + case BLOCKED:/* will come through here multiple times, print msg once */ +/* + if (!printed) + printf("Blocked - do something else while SQL stmt executes...\n"); + printed = TRUE; +*/ + break; + case SUCCESS: + done = 1; + break; + default: + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); /* get out of application */ + } + + } + + if (onbclr(&lda)) /* clear the non-blocking status of the connection */ + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + ub1 done = 0; + static ub1 logprint = FALSE; /* just print blocked logon once */ + while (!done) + { + switch (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, + (text *)"OCITEST", -1, + (text *)"inst1_nonblock", -1, (ub4)OCI_LM_NBL)) + { + + case BLOCKED:/* will come through here multiple times, print msg once */ +/* + if (!logprint) + printf("blocked - keep trying to log on\n"); + logprint = TRUE; +*/ + break; + case SUCCESS: + printf("logged on\n"); + done = 1; + break; + default: + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci22.sql b/oci22.sql new file mode 100644 index 0000000..8d0d2df --- /dev/null +++ b/oci22.sql @@ -0,0 +1,40 @@ +rem +rem $Header: oci22.sql 11-oct-2006.15:55:35 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci22.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci22.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci22tab (col1 varchar2(30)); +insert into oci22tab values ('A'); +insert into oci22tab values ('AB'); +insert into oci22tab values ('ABC'); +insert into oci22tab values ('ABCD'); +insert into oci22tab values ('ABCDE'); +insert into oci22tab values ('ABCDEF'); +insert into oci22tab values ('ABCDEFG'); +insert into oci22tab values ('ABCDEFGH'); +insert into oci22tab values ('ABCDEFGHI'); +insert into oci22tab values ('ABCDEFGHIJ'); +insert into oci22tab values ('ABCDEFGHIJK'); +insert into oci22tab values ('ABCDEFGHIJKL'); + +commit; + diff --git a/oci23.c b/oci23.c new file mode 100644 index 0000000..6e3a825 --- /dev/null +++ b/oci23.c @@ -0,0 +1,297 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci23.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests describe function + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci23.c + * + * Description: This program illustrates how to do a describe on a query + * + * Based on: + * Changes: + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires NO arguments + * + * oci23 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - none + * Describe - odescr + * Define - none + * Execute - none + * Fetch - none + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void dump_data(); +void do_exit(); +void do_describe(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT one, two, three, four FROM oci23tab"; + +main(argc, argv) +eword argc; +text **argv; +{ + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + do_describe(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: do_describe + * + * Description: This routine actually describes a sql statement and prints + * the information pertaining to it. + * + */ +void do_describe() +{ + +#define COL_SIZE 20 +#define NUM_SELECT_ITEMS 4 + +sword items = NUM_SELECT_ITEMS; /* number of select items */ +sword colindex; +sb4 *dbsize; /* maximum size of column */ +sb2 *dbtype; /* internal column datatype */ +sb1 *column_name; /* buffer to store column names */ +sb4 *col_buf_len; /* length of column */ +sb4 *display_size; /* maximum display size */ +sb2 *precision; /* precision */ +sb2 *scale; /* scale */ +sb2 *nullok; /* column can have null values in it * + + /* allocate the needed storage */ + + dbsize = (sb4 *)malloc((ub4)(items * sizeof(sb4))); + dbtype = (sb2 *)malloc((ub4)(items * sizeof(sb2))); + column_name = (sb1 *)malloc((ub4)(items * sizeof(sb1) * COL_SIZE)); + col_buf_len = (sb4 *)malloc((ub4)(items * sizeof(sb4))); + display_size = (sb4 *)malloc((ub4)(items * sizeof(sb4))); + precision = (sb2 *)malloc((ub4)(items * sizeof(sb2))); + scale = (sb2 *)malloc((ub4)(items * sizeof(sb2))); + nullok = (sb2 *)malloc((ub4)(items * sizeof(sb2))); + + for (colindex = 0; colindex < items; colindex++) + { + + /* Have to initialize length, otherwise nothing is returned */ + *(col_buf_len + colindex) = COL_SIZE; + + if (odescr(&cda, colindex + 1, + dbsize + colindex, dbtype + colindex, + column_name + (COL_SIZE * colindex), col_buf_len + colindex, + display_size + colindex, precision + colindex, + scale + colindex, nullok + colindex)) + { + err_report(&cda); + do_exit (OCI_EXIT_FAILURE); + } + + } + + printf("printing out results of the describe \n"); + + for (colindex = 0; colindex < items; colindex++) + { + printf("\n\n\nInformation from desc for column %d\n\n", colindex + 1); + + printf("Column Maximum Size is %d\n", *(dbsize + colindex)); + printf("Column Type is %d\n", *(dbtype + colindex)); + + printf("Column Name Length is %d\n", *(col_buf_len + colindex)); + *(column_name + (COL_SIZE*colindex) + *(col_buf_len+colindex))='\0'; + printf("Column Name is %s\n", + column_name + (COL_SIZE*colindex)); + + printf("Column Length is %d\n", *(col_buf_len + colindex)); + printf("Column Display Size is %d\n", *(display_size + colindex)); + printf("Column Precision is %d\n", *(precision + colindex)); + printf("Column Scale is %d\n", *(scale + colindex)); + printf("Column Nulls allowed is %d\n", *(nullok + colindex)); + + } + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci23.sql b/oci23.sql new file mode 100644 index 0000000..9f9bde9 --- /dev/null +++ b/oci23.sql @@ -0,0 +1,34 @@ +rem +rem $Header: oci23.sql 11-oct-2006.15:55:35 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci23.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci23.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem emendez 06/16/97 - +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +rem +rem Create a new user - call it ocitest +rem +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table oci23tab (one number not null, two long, three date, + four char(10)); + diff --git a/oci24.c b/oci24.c new file mode 100644 index 0000000..ffdd69a --- /dev/null +++ b/oci24.c @@ -0,0 +1,263 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci24.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests describe of a PL/SQL package + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + chliang 02/06/01 - merge request for porting exception #1593298. + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci24.c + * + * Description: This program illustrates how to do a describe on a procedure + * using odessp + * + * Based on: + * Changes: + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires NO arguments + * + * oci24 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - none + * Describe - odescr + * Define - none + * Execute - none + * Fetch - none + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ +#define ASIZE 15 + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup (); +void err_report(); +void do_exit(); +void do_describe(); + +/* odessp uses the object name directly, no SQL statement involved */ + +text *objname = (text *)"oci24pkg.oci24proc"; /* name of object */ + +main(argc, argv) +eword argc; +text **argv; +{ + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + do_describe(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: do_describe + * + * Description: This routine actually describes a sql statement and prints + * the information pertaining to it. + * + */ +void do_describe() +{ + + +ub2 ovrld[ASIZE]; /* overloading information */ +ub2 pos[ASIZE]; /* parameter position */ +ub2 level[ASIZE]; /* level for composite parameters */ +text argnm[ASIZE][MAX_NAME_LENGTH]; /* parameter names */ +ub2 arnlen[ASIZE]; /* length of parameter names */ +ub2 dtype[ASIZE]; /* Oracle datatype codes for parameters */ +ub1 defsup[ASIZE]; /* returns "default supplied" indicators */ +ub1 mode[ASIZE]; /* mode ie. IN, OUT, IN/OUT */ +ub4 dtsize[ASIZE]; /* lengths */ +sb2 prec[ASIZE]; /* precision, if a number */ +sb2 scale[ASIZE]; /* scale, if a number */ +ub1 radix[ASIZE]; /* radix, if a number */ +ub4 spare[ASIZE]; /* reserved, must be passed */ +ub4 array_size; /* size of the OUT arrays */ +ub2 i; /* counter */ + + array_size = ASIZE; /* gotcha - you need to input the array size */ + + + if (odessp(&lda, objname, -1, (ub1 *)0, 0, (ub1 *)0, 0, + ovrld, pos, level, (text **)argnm, arnlen, dtype, defsup, mode, + dtsize, prec, scale, radix, spare, &array_size)) + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("array contains information for %d entries \n", array_size); + + printf("Overload\tLevel\tPos\tprocName\tDatatype\n"); + for (i = 0; i < array_size; i++) + { + printf("%8d\t%5d\t%3d\t%.*s\t%16d\n", + ovrld[i], level[i], pos[i], arnlen[i], argnm[i], dtype[i]); + } +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci24.sql b/oci24.sql new file mode 100644 index 0000000..2728fc5 --- /dev/null +++ b/oci24.sql @@ -0,0 +1,52 @@ +rem +rem $Header: oci24.sql 11-oct-2006.15:55:35 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci24.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci24.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem svedala 09/11/98 - a "/" required after create package-bug 717842 +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table oci24tab (ename char(10), empno number, sal number); + +create or replace package oci24pkg as + +procedure oci24proc( + name in oci24tab.ename%type, + salary out oci24tab.sal%type); + +procedure oci24proc( + id_num in oci24tab.empno%type, + salary out oci24tab.sal%type); + +function oci24proc ( + name oci24tab.ename%type) return number; + +end oci24pkg; +/ + + diff --git a/oci25.c b/oci25.c new file mode 100644 index 0000000..b1d5077 --- /dev/null +++ b/oci25.c @@ -0,0 +1,246 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci25.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests DDL operations + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + ehayes 08/22/97 - + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ +/* + * Name: oci25.c + * + * Description: This program illustrates how to do DDL with oparse + * + * Based on: + * Changes: + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires NO arguments + * + * oci25 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse does the DDL for us + * Bind - none + * Describe - none + * Define - none + * Execute - none + * Fetch - none + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void dump_data(); +void do_exit(); +void do_describe(); + +/* SQL statement used in this program */ + +text *sqlstm1 = (text *)"CREATE TABLE test1 (col1 number)"; +text *sqlstm2 = (text *)"CREATE TABLE test2 (col1 number)"; +text *sqlstm3 = (text *)"CREATE TABLE test3 (col1 number)"; + +main(argc, argv) +eword argc; +text **argv; +{ + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +/* try creating test1 with a deferred parse but no execute */ + + if (oparse(&cda, sqlstm1, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +/* try creating test2 with a non-deferred parse */ + + if (oparse(&cda, sqlstm2, (sb4) -1, 0, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +/* try creating test3 with a deferred parse AND execute */ + + if (oparse(&cda, sqlstm3, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} + diff --git a/oci25.sql b/oci25.sql new file mode 100644 index 0000000..79a06b2 --- /dev/null +++ b/oci25.sql @@ -0,0 +1,35 @@ +rem +rem $Header: oci25.sql 11-oct-2006.15:55:35 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci25.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci25.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; +drop table test1; +drop table test2; +drop table test3; + diff --git a/oci_f.sed b/oci_f.sed new file mode 100644 index 0000000..2896625 --- /dev/null +++ b/oci_f.sed @@ -0,0 +1,86 @@ +# NAME +# oci_f.sed +# DESCRIPTION +# This sed script changes the OCI function and type names to long +# names +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/04/96 - Sreenivas Gollapudi - Added ComplexObjectComp +# +s/ocianyd/ocianyd/g +s/ociatch/OCIServerAttach/g +s/ociauth/OCISessionBegin/g +s/ocibda/OCIBindDynamic/g +s/ocibicfp/OCICallbackInBind/g +s/ociblobl/OCIBlobLocator/g +s/ociclobl/OCIClobLocator/g +s/ocibocfp/OCICallbackOutBind/g +s/ocidcfp/OCICallbackDefine/g +s/ocibndh/OCIBind/g +s/ocibndt/OCIBindObject/g +s/ocibreak/OCIBreak/g +s/ocibsa/OCIBindArrayOfStruct/g +s/ocicorh/OCIComplexObject/g +s/ocicord/OCIComplexObjectComp/g +s/ocicpw/OCIPasswordChange/g +s/ocidarr/OCIDefineArrayOfStruct/g +s/ociddf/OCIDefineDynamic/g +s/ocidfnh/OCIDefine/g +s/ocidndt/OCIDefineObject/g +s/ocidsca/OCIDescribeAny/g +s/ocidsch/OCIDescribe/g +s/ocidtch/OCIServerDetach/g +s/ocienvh/OCIEnv/g +s/ocierrh/OCIError/g +s/ociexec/OCIStmtExecute/g +s/ocifch/OCIStmtFetch/g +s/ocifcls/OCILobFileClose/g +s/ocifcrt/OCILobFileCreate/g +s/ocifdel/OCILobFileDelete/g +s/ocifdesc/OCIDescriptorFree/g +s/ocifhndl/OCIHandleFree/g +s/ocifopn/OCILobFileOpen/g +s/ocifreem/OCIMemoryFree/g +s/ocigattr/OCIAttrGet/g +s/ocigbp/OCIStmtGetBindInfo/g +s/ocigdesc/OCIDescriptorAlloc/g +s/ocigdr/OCIErrorGet/g +s/ocighndl/OCIHandleAlloc/g +s/ocigparm/OCIParamGet/g +s/ocisparm/OCIParamSet/g +s/ocigpi/OCIStmtGetPieceInfo/g +s/ociinit/OCIEnvInit/g +s/ocild2sv/OCILdaToSvcCtx/g +s/ocilfap/OCILobAppend/g +s/ocilfcp/OCILobCopy/g +s/ocilfer/OCILobErase/g +s/ocilfln/OCILobGetLength/g +s/ocilfrd/OCILobRead/g +s/ocilftr/OCILobTrim/g +s/ocilfwr/OCILobWrite/g +s/ocilobd/OCILobLocator/g +s/ocilobl/OCILobLocator/g +s/ocipard/OCIParam/g +s/ocipi/OCIInitialize/g +s/ocirefd/ocirefd/g +s/ocireq/OCIStmtPrepare/g +s/ociridd/OCIRowid/g +s/ocirs2sh/OCIResultSetToStmt/g +s/ocirstd/OCIResult/g +s/ocisattr/OCIAttrSet/g +s/ocisnad/OCISnapshot/g +s/ocispi/OCIStmtSetPieceInfo/g +s/ocisrvh/OCIServer/g +s/ocistmh/OCIStmt/g +s/ocisv2ld/OCISvcCtxToLda/g +s/ocisvch/OCISvcCtx/g +s/ocitac/OCISessionEnd/g +s/ocitxcm/OCITransCommit/g +s/ocitxdt/OCITransDetach/g +s/ocitxfgt/OCITransForget/g +s/ocitxnh/OCITrans/g +s/ocitxpre/OCITransPrepare/g +s/ocitxrl/OCITransRollback/g +s/ocitxst/OCITransStart/g +s/ociusrh/OCISession/g +s/ocivers/OCIServerVersion/g diff --git a/oci_m.sed b/oci_m.sed new file mode 100644 index 0000000..3dcb177 --- /dev/null +++ b/oci_m.sed @@ -0,0 +1,136 @@ +# NAME +# oci_m.sed +# DESCRIPTION +# This sed script changes the OCI macro names to long +# names +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/04/96 - Sreenivas Gollapudi - Added OCI_STM and OCI_TX stuff +# 10/21/96 - Peter Vasterd - TOPROW -> PREFETCH +# +s/OCI_ATTR_ENVCTXT/OCI_ATTR_ENV/g +s/OCI_ATTR_SRVRCTXT/OCI_ATTR_SERVER/g +s/OCI_ATTR_TXCTXT/OCI_ATTR_TRANS/g +s/OCI_ATTR_USERCTXT/OCI_ATTR_SESSION/g +s/OCI_ATTR_FUNCODE/OCI_ATTR_FNCODE/g +s/OCI_ATTR_NBLMODE/OCI_ATTR_NONBLOCKING_MODE/g +s/OCI_ATTR_ROWCNT/OCI_ATTR_ROW_COUNT/g +s/OCI_ATTR_TOPRCNT/OCI_ATTR_PREFETCH_ROWS/g +s/OCI_ATTR_NSTD_RCNT/OCI_ATTR_NESTED_ROW_COUNT/g +s/OCI_ATTR_TOP_RMSZ/OCI_ATTR_PREFETCH_MEMORY/g +s/OCI_ATTR_NSTD_RMSZ/OCI_ATTR_NESTED_PREFETCH_MEMORY/g +s/OCI_ATTR_CHRCNT/OCI_ATTR_CHAR_COUNT/g +s/OCI_ATTR_PARMCNT/OCI_ATTR_PARAM_COUNT/g +s/OCI_ATTR_STMTYP/OCI_ATTR_STMT_TYPE/g +s/OCI_ATTR_TXLOCK/OCI_ATTR_TRANS_LOCK/g +s/OCI_ATTR_TXNAME/OCI_ATTR_TRANS_NAME/g +s/OCI_ATTR_CHRSETID/OCI_ATTR_CHARSET_ID/g +s/OCI_ATTR_CHRSETFORM/OCI_ATTR_CHARSET_FORM/g +s/OCI_ATTR_CHRSET/OCI_ATTR_CHARSET/g +s/OCI_ATTR_MAXDATASZ/OCI_ATTR_MAXDATA_SIZE/g +s/OCI_ATTR_OPTSIZE/OCI_ATTR_CACHE_OPT_SIZE/g +s/OCI_ATTR_MAXSIZE/OCI_ATTR_CACHE_MAX_SIZE/g +s/OCI_ATTR_ALLOCDUR/OCI_ATTR_ALLOC_DURATION/g +s/OCI_ATTR_PINDUR/ OCI_ATTR_PIN_DURATION/g +s/OCI_ATTR_CORTYP/OCI_ATTR_COMPLEXOBJECTCOMP_TYPE/g +s/OCI_ATTR_CORLVL/OCI_ATTR_COMPLEXOBJECTCOMP_LEVEL/g +s/OCI_HTYPE_BND/OCI_HTYPE_BIND/g +s/OCI_HTYPE_DFN/OCI_HTYPE_DEFINE/g +s/OCI_HTYPE_DSC/OCI_HTYPE_DESCRIBE/g +s/OCI_HTYPE_ENV/OCI_HTYPE_ENV/g +s/OCI_HTYPE_ERR/OCI_HTYPE_ERROR/g +s/OCI_HTYPE_SRV/OCI_HTYPE_SERVER/g +s/OCI_HTYPE_STM/OCI_HTYPE_STMT/g +s/OCI_HTYPE_SVC/OCI_HTYPE_SVCCTX/g +s/OCI_HTYPE_TXN/OCI_HTYPE_TRANS/g +s/OCI_HTYPE_COR/OCI_HTYPE_COMPLEXOBJECT/g +s/OCI_HTYPE_USR/OCI_HTYPE_SESSION/g +s/OCIATCH/OCI_FNCODE_SERVERATTACH/g +s/OCIAUTH/OCI_FNCODE_SESSIONBEGIN/g +s/OCIBDA/OCI_FNCODE_BINDDYNAMIC/g +s/OCIBNDH/OCI_FNCODE_BIND/g +s/OCIBNDN/OCI_FNCODE_STMTBINDBYNAME/g +s/OCIBNDP/OCI_FNCODE_STMTBINDBYPOS/g +s/OCIBNDT/OCI_FNCODE_BINDOBJECT/g +s/OCIBREAK/OCI_FNCODE_SVCCTXBREAK/g +s/OCIBSA/OCI_FNCODE_BINDARRAYOFSTRUCT/g +s/OCIBSVT/OCI_FNCODE_BINDRECORD/g +s/OCICPW/OCI_FNCODE_PASSWORDCHANGE/g +s/OCIDARR/OCI_FNCODE_DEFINEARRAYOFSTRUCT/g +s/OCIDDF/OCI_FNCODE_DEFINEDYNAMIC/g +s/OCIDEFN/OCI_FNCODE_DEFINE/g +s/OCIDNDT/OCI_FNCODE_DEFINEOBJECT/g +s/OCIDSCA/OCI_FNCODE_DESCRIBEANY/g +s/OCIEXEC/OCI_FNCODE_STMTEXECUTE/g +s/OCIFCH/OCI_FNCODE_STMTFETCH/g +s/OCIFCLS/OCI_FNCODE_LOBCLOSEFILE/g +s/OCIFCRT/OCI_FNCODE_LOBCREATEFILE/g +s/OCIFDEL/OCI_FNCODE_LOBDELFILE/g +s/OCIFDESC/OCI_FNCODE_DESCRIPTORFREE/g +s/OCIFHNDL/OCI_FNCODE_HANDLEFREE/g +s/OCIFOPN/OCI_FNCODE_LOBOPENFILE/g +s/OCIFREEM/OCI_FNCODE_MEMORYFREE/g +s/OCIGATTR/OCI_FNCODE_ATTRGET/g +s/OCIGBP/OCI_FNCODE_STMTGETBIND/g +s/OCIGDESC/OCI_FNCODE_DESCRIPTORALLOC/g +s/OCIGDR/OCI_FNCODE_ERRORGET/g +s/OCIGHNDL/OCI_FNCODE_HANDLEALLOC/g +s/OCIGPARM/OCI_FNCODE_PARAMGET/g +s/OCIGPI/OCI_FNCODE_STMTGETPIECEINFO/g +s/OCIINIT/OCI_FNCODE_ENVINIT/g +s/OCILD2SV/OCI_FNCODE_LDATOSVCCTX/g +s/OCILFAP/OCI_FNCODE_LOBAPPEND/g +s/OCILFCP/OCI_FNCODE_LOBCOPY/g +s/OCILFER/OCI_FNCODE_LOBERASE/g +s/OCILFLN/OCI_FNCODE_LOBGETLENGTH/g +s/OCILFRD/OCI_FNCODE_LOBREAD/g +s/OCILFTR/OCI_FNCODE_LOBTRIM/g +s/OCILFWR/OCI_FNCODE_LOBWRITE/g +s/OCIPI/OCI_FNCODE_INITIALIZE/g +s/OCIREQ/OCI_FNCODE_STMTPREPARE/g +s/OCIRS2SH/OCI_FNCODE_RESULTSETTOSTMT/g +s/OCISATTR/OCI_FNCODE_ATTRSET/g +s/OCISPI/OCI_FNCODE_STMTSETPIECEINFO/g +s/OCISV2LD/OCI_FNCODE_SVCCTXTOLDA/g +s/OCITAC/OCI_FNCODE_SESSIONEND/g +s/OCITXCM/OCI_FNCODE_TRANSCOMMIT/g +s/OCITXDT/OCI_FNCODE_TRANSDETACH/g +s/OCITXFGT/OCI_FNCODE_TRANSFORGET/g +s/OCITXPRE/OCI_FNCODE_TRANSPREPARE/g +s/OCITXRL/OCI_FNCODE_TRANSROLLBACK/g +s/OCITXST/OCI_FNCODE_TRANSSTART/g +s/OCIVERS/OCI_FNCODE_SERVERVERSION/g +s/OCI_FILE_RDWR/OCI_FILE_READWRITE/g +s/OCI_FILE_RDONLY/OCI_FILE_READONLY/g +s/SQLT_CFIL/SQLT_CFILE/g +s/SQLT_BFIL/SQLT_BFILE/g +s/OCI_STM_SELECT/OCI_STMT_SELECT/g +s/OCI_STM_UPDATE/OCI_STMT_UPDATE/g +s/OCI_STM_DELETE/OCI_STMT_DELETE/g +s/OCI_STM_INSERT/OCI_STMT_INSERT/g +s/OCI_STM_DROP/OCI_STMT_DROP/g +s/OCI_STM_ALTER/OCI_STMT_ALTER/g +s/OCI_STM_BEGIN/OCI_STMT_BEGIN/g +s/OCI_STM_DEC/OCI_STMT_DECLARE/g +s/OCI_TX_OLD/OCI_TRANS_OLD/g +s/OCI_TX_NEW/OCI_TRANS_NEW/g +s/OCI_TX_JOIN/OCI_TRANS_JOIN/g +s/OCI_TX_RESUME/OCI_TRANS_RESUME/g +s/OCI_TX_STARTMASK/OCI_TRANS_STARTMASK/g +s/OCI_TX_READONLY/OCI_TRANS_READONLY/g +s/OCI_TX_READWRITE/OCI_TRANS_READWRITE/g +s/OCI_TX_SERIALIZABLE/OCI_TRANS_SERIALIZABLE/g +s/OCI_TX_ISOLMASK/OCI_TRANS_ISOLMASK/g +s/OCI_TX_LOOSE/OCI_TRANS_LOOSE/g +s/OCI_TX_TIGHT/OCI_TRANS_TIGHT/g +s/OCI_TX_TYPEMASK/OCI_TRANS_TYPEMASK/g +s/OCI_TX_NOMIGRATE/OCI_TRANS_NOMIGRATE/g +s/OCI_TX_TWOPHASE/OCI_TRANS_TWOPHASE/g +s/OCI_DTYPE_PARM/OCI_DTYPE_PARAM/g +s/OCI_DTYPE_COR/OCI_DTYPE_COMPLEXOBJECTCOMP/g +s/OCI_DTYPE_RDD/OCI_DTYPE_ROWID/g +s/OCI_SB2_INDP/OCI_SB2_IND_PTR/g +s/OCI_IN_PARAMETER/OCI_PARAM_IN/g +s/OCI_OUT_PARAMETER/OCI_PARAM_OUT/g +s/OCISQLSTATESZ/OCI_SQLSTATE_SIZE/g +s/OCIMAXMSGSZ/OCI_ERROR_MAXMSG_SIZE/g diff --git a/ociaqarraydeq.c b/ociaqarraydeq.c new file mode 100644 index 0000000..f149130 --- /dev/null +++ b/ociaqarraydeq.c @@ -0,0 +1,237 @@ +/* Copyright (c) 2003, 2007, Oracle. All rights reserved. */ + +/* + + NAME + ociaqarraydeq.c - + + DESCRIPTION + + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + + aqdemo09.sql (present in the $ORACLE_HOME/rdbms/demo directory) has to be + run as SYS to set up the required queue tables, queues, subscribers etc. + + aqdemo10.sql (present in the $ORACLE_HOME/rdbms/demo directory) has to then + be run to enqueue some messages into the queue, so that they can be + dequeued by this program.. + + ociaqarrayenq.c - enqueues a batch of 10 msgs into my_queue + ociaqarraydeq.c - dequeues a batch of 10 msgs from my_queue + + aqdemo12.sql (present in the $ORACLE_HOME/rdbms/demo directory) has to be + run as SYS to clean up all objects. + + MODIFIED (MM/DD/YY) + dprasann 04/05/07 - lowercase username/password + azhao 03/27/06 - fix 4993505 + rbhyrava 04/05/04 - linux porting + ekarichk 12/18/03 - bug3328852: missing prototypes + aahluwal 10/17/03 - aahluwal_create_arrenqdeq_demos + aahluwal 10/07/03 - Creation + +*/ + +#include +#include +#include +#include + +#ifndef OCI_ORACLE +#include +#endif + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +struct message +{ + OCIString *data; +}; +typedef struct message message; + +struct null_message +{ + OCIInd null_adt; + OCIInd null_data; +}; +typedef struct null_message null_message; + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ +static void checkerr( OCIError *errhp, sword status); + +static void checkerr( OCIError *errhp, sword status) +{ + text errbuf[512]; + ub4 buflen; + sb4 errcode; + + if (status == OCI_SUCCESS) return; + + switch (status) + { + case OCI_SUCCESS_WITH_INFO: + printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + printf("Error - %s\n", errbuf); + break; + case OCI_INVALID_HANDLE: + printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("Error - OCI_CONTINUE\n"); + + break; + default: + printf("Error - %d\n", status); + break; + } +} + +int main(int argc, char *argv[]) +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCISession *usrhp; + dvoid *tmp; + message *mesgp[100]; + int i, j, k; + null_message *nmesgp[100]; + ub4 priority = 0; + OCIAQDeqOptions *deqopt = (OCIAQDeqOptions *)0; + ub4 iters = 10; + OCIType *mesg_tdo = (OCIType *) 0; + ub4 batch_size = iters; + ub4 deq_size = batch_size; + + printf("session start\n"); + /* establish a session */ + + OCIInitialize((ub4) OCI_OBJECT, (dvoid *)0, (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *,dvoid * ,size_t)) 0, (dvoid (*)(dvoid *,dvoid *)) 0 ); + + + OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &envhp, (ub4) OCI_HTYPE_ENV, + 52, (dvoid **) &tmp); + + OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp); + + printf("server attach\n"); + OCIServerAttach( srvhp, errhp, (text *) 0, (sb4) 0, (ub4) OCI_DEFAULT); + + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp); + + /* set attribute server context in the service context */ + OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *)srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp); + + /* allocate a user context handle */ + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"aquser", (ub4)strlen("aquser"), + OCI_ATTR_USERNAME, errhp); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"aquser", (ub4)strlen("aquser"), + OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, OCI_CRED_RDBMS, + OCI_DEFAULT)); + + OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, OCI_ATTR_SESSION, errhp); + + /* get descriptor for dequeue options */ + checkerr(errhp, OCIDescriptorAlloc(envhp, (dvoid **)&deqopt, + OCI_DTYPE_AQDEQ_OPTIONS, 0, + (dvoid **)0)); + + printf("deq options set\n"); + /* set dequeue options - for consumer name, wait and navigation */ + checkerr(errhp, OCIAttrSet(deqopt, OCI_DTYPE_AQDEQ_OPTIONS, + (dvoid *)"SUB1", + (ub4)strlen("SUB1"), + OCI_ATTR_CONSUMER_NAME, errhp)); + + for (k=0 ; k < iters ; k++) + { + mesgp[k] = (message *)0; + nmesgp[k] = (null_message *)0; + } + + printf("check message tdo\n"); + checkerr(errhp, OCITypeByName(envhp, errhp, svchp, + (CONST text *)"AQUSER", (ub4)strlen("AQUSER"), + (CONST text *)"MESSAGE", (ub4)strlen("MESSAGE"), (text *)0, 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &mesg_tdo)); + + + k=0; + + while (k < iters) + { + deq_size = batch_size; + checkerr(errhp, OCIAQDeqArray(svchp, errhp, + (text *)"AQUSER.MY_QUEUE", + (OCIAQDeqOptions *)deqopt, + &deq_size, (OCIAQMsgProperties **)0, mesg_tdo, + (dvoid **)mesgp, + (dvoid **)nmesgp,(OCIRaw **)0, (void *)0, + (OCICallbackAQDeq)0, 0)); + k+=(int) batch_size; + } + printf("%i messages dequeued\n", k); + + for (j=0; jdata)); + } + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + printf("dequeue committed\n"); + + checkerr(errhp, OCISessionEnd ( svchp, errhp, usrhp, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIServerDetach( srvhp, errhp, (ub4) OCI_DEFAULT)); + return 0; +} + + +/* end of file ociaqarraydeq.c */ + diff --git a/ociaqarrayenq.c b/ociaqarrayenq.c new file mode 100644 index 0000000..a902358 --- /dev/null +++ b/ociaqarrayenq.c @@ -0,0 +1,250 @@ +/* Copyright (c) 2003, 2007, Oracle. All rights reserved. */ + +/* + + NAME + ociaqarrayenq.c - + + DESCRIPTION + + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + aqdemo09.sql (present in the $ORACLE_HOME/rdbms/demo directory) has to be + run after connecting as SYS to set up the required queue tables, queues, + subscribers etc. + + ociaqarrayenq.c - enqueues a batch of 10 msgs into my_queue + ociaqarraydeq.c - dequeues a batch of 10 msgs from my_queue + + aqdemo12.sql (present in the $ORACLE_HOME/rdbms/demo directory) has to be + run as SYS to clean up all objects. + + MODIFIED (MM/DD/YY) + dprasann 04/05/07 - lowercase username/password + dprasann 02/15/06 - bug 4993505 + rbhyrava 04/05/04 - linux porting + aahluwal 10/17/03 - aahluwal_create_arrenqdeq_demos + aahluwal 10/07/03 - Creation + +*/ + +#include +#include +#include +#include + +#ifdef WIN64 +#include +#endif + +#ifndef OCI_ORACLE +#include +#endif + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +struct message +{ + OCIString *data; +}; +typedef struct message message; + +struct null_message +{ + OCIInd null_adt; + OCIInd null_data; +}; +typedef struct null_message null_message; + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ + +static void checkerr( OCIError *errhp, sword status); + +static void checkerr( OCIError *errhp, sword status) +{ + text errbuf[512]; + ub4 buflen; + sb4 errcode; + + if (status == OCI_SUCCESS) return; + + switch (status) + { + case OCI_SUCCESS_WITH_INFO: + printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + printf("Error - %s\n", errbuf); + break; + case OCI_INVALID_HANDLE: + printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("Error - OCI_CONTINUE\n"); + break; + default: + printf("Error - %d\n", status); + break; + } +} + +int main(int argc, char *argv[]) +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCISession *usrhp; + dvoid *tmp; + OCIType *mesg_tdo = (OCIType *) 0; + message mesg[100]; + message *mesgp[100]; + null_message nmesg[100]; + null_message *nmesgp[100]; + int i, j, k; + OCIInd ind[100]; + dvoid *indptr[100]; + ub4 priority; + OCIAQEnqOptions *enqopt = (OCIAQEnqOptions *)0; + OCIAQMsgProperties *msgprop= (OCIAQMsgProperties *)0; + ub4 wait = 1; + ub4 navigation = OCI_DEQ_NEXT_MSG; + ub4 iters = 10; + text *qname ; + text mesgdata[30]; + ub4 payload_size = 5; + text *payload = (text *)0; + ub4 batch_size = iters; + ub4 enq_size = 2; + char repeat_char = '0'; + + printf("session start\n"); + /* establish a session */ + + OCIInitialize((ub4) OCI_OBJECT, (dvoid *)0, (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *,dvoid * ,size_t)) 0, (dvoid (*)(dvoid *,dvoid *)) 0 ); + + OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &envhp, (ub4) OCI_HTYPE_ENV, + 52, (dvoid **) &tmp); + + OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp); + + printf("server attach\n"); + OCIServerAttach( srvhp, errhp, (text *) 0, (sb4) 0, (ub4) OCI_DEFAULT); + + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp); + + /* set attribute server context in the service context */ + OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *)srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp); + + /* allocate a user context handle */ + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"aquser", (ub4)strlen("aquser"), + OCI_ATTR_USERNAME, errhp); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"aquser", (ub4)strlen("aquser"), + OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, OCI_CRED_RDBMS, + OCI_DEFAULT)); + + OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, OCI_ATTR_SESSION, errhp); + + /* get descriptor for enqueue options */ + checkerr(errhp, OCIDescriptorAlloc(envhp, (dvoid **)&enqopt, + OCI_DTYPE_AQENQ_OPTIONS, 0, + (dvoid **)0)); + + printf("enq options set\n"); + /* set enqueue options - for consumer name, wait and navigation */ + + /* construct null terminated payload string */ + payload = (text *)malloc(payload_size+1); + + for (k=0 ; k < batch_size ; k++) + { + indptr[k] = &ind[k]; + mesgp[k] = &mesg[k]; + nmesgp[k] = &nmesg[k]; + nmesg[k].null_adt = nmesg[k].null_data = OCI_IND_NOTNULL; + mesg[k].data = (OCIString *)0; + + for (j=0 ; j < payload_size ; j++) + payload[j] = (text)repeat_char; + payload[payload_size] = (text)'\0'; + + OCIStringAssignText(envhp, errhp, (const oratext *)payload, + (ub4)strlen((const char *)payload), &(mesg[k].data)); + printf("Message #%i has payload: \"%s\"\n", k, payload); + repeat_char++; + } + + printf("check message tdo\n"); + checkerr(errhp, OCITypeByName(envhp, errhp, svchp, + (CONST text *)"AQUSER", (ub4)strlen("AQUSER"), + (CONST text *)"MESSAGE", (ub4)strlen("MESSAGE"), (text *)0, 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &mesg_tdo)); + + k=0; + + while (k < iters) + { + enq_size = batch_size; + checkerr(errhp, OCIAQEnqArray(svchp, errhp, + (dvoid *)"AQUSER.MY_QUEUE", + (OCIAQEnqOptions *)0, &enq_size, + (OCIAQMsgProperties **)0, mesg_tdo, + (dvoid **)&mesgp, + (dvoid **)&nmesgp, (OCIRaw **)0, + (void *)0, (OCICallbackAQEnq) 0, 0)); + k+=(int)batch_size; + } + printf("%i messages enqueued\n", k); + + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + printf("enqueue committed\n"); + + checkerr(errhp, OCISessionEnd ( svchp, errhp, usrhp, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIServerDetach( srvhp, errhp, (ub4) OCI_DEFAULT)); + + return 0; +} + +/* end of file ociaqarrayenq.c */ + diff --git a/ociaqdemo00.c b/ociaqdemo00.c new file mode 100644 index 0000000..dab80c0 --- /dev/null +++ b/ociaqdemo00.c @@ -0,0 +1,304 @@ +#ifdef RCSID +static char *RCSid = + "$Header: ociaqdemo00.c 27-mar-2006.22:31:21 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + ociaqdemo00.c - + + DESCRIPTION + ociaqdemo00.c enqueues 100 messages into the input_queue. (10 messages are + enqueued every 3 seconds to a maximum of 100 messages) + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + aqdemo00.sql (present in the $ORACLE_HOME/rdbms/demo directory) has + to be run first as user SYS to set up the required queue tables, + queues, subscribers etc. + + ociaqdemo00.c enqueues 100 messages into the input_queue. + ociaqdemo01.c dequeues messages by blocking on prop_queue for agent "prog3" + ociaqdemo02.c listens on input_queue and dequeues messages for agents + "prog1" and "prog2". + + + MODIFIED (MM/DD/YY) + azhao 03/27/06 - fix 4993505 + lzhao 04/16/04 - nt lrg + rbhyrava 04/05/04 - linux porting + ekarichk 12/18/03 - bug3328852: missing prototypes + rbhyrava 11/14/00 - rename newaqdemo00 + mrhodes 01/25/00 - make sleep call nt compatible + bnainani 09/23/99 - Bug 996772: change order of freeing handles + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + kmeiyyap 06/30/99 - free handles + kmeiyyap 06/29/99 - free descriptor + kmeiyyap 10/06/98 - oci enqueue + kmeiyyap 10/06/98 - Creation + +*/ +/* for WINDOWS compatibility of 'sleep' call */ +#if defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32) +#include +#define sleep(x) Sleep(1000*(x)) +#endif + +#include + +#ifndef OCI_ORACLE +#include +#endif + +#include +#include +#include + +static void checkerr( OCIError *errhp, sword status); + +static void checkerr( OCIError *errhp, sword status) +{ + text errbuf[512]; + ub4 buflen; + sb4 errcode; + + if (status == OCI_SUCCESS) return; + + switch (status) + { + case OCI_SUCCESS_WITH_INFO: + printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + printf("Error - %s\n", errbuf); + exit(1); + case OCI_INVALID_HANDLE: + printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("Error - OCI_CONTINUE\n"); + break; + default: + printf("Error - %d\n", status); + break; + } +} + +void clean_up(OCIEnv *envhp, + OCISvcCtx *svchp, + OCIServer *srvhp, + OCIError *errhp, + OCISession *usrhp, + OCIAQMsgProperties *msgprop) +{ + /* free the message properties decriptor */ + checkerr(errhp, OCIDescriptorFree((dvoid *)msgprop, + OCI_DTYPE_AQMSG_PROPERTIES)); + + /* detach from the server */ + checkerr(errhp, OCISessionEnd(svchp, errhp, usrhp, OCI_DEFAULT)); + checkerr(errhp, OCIServerDetach(srvhp, errhp, (ub4)OCI_DEFAULT)); + + if (usrhp) + (void) OCIHandleFree((dvoid *) usrhp, (ub4) OCI_HTYPE_SESSION); + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + if (srvhp) + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV); + +} + +struct message +{ + OCINumber id; + OCIString *city; + OCINumber priority; +}; +typedef struct message message; + +struct null_message +{ + OCIInd null_adt; + OCIInd null_id; + OCIInd null_city; + OCIInd null_priority; +}; +typedef struct null_message null_message; + + + +int main() +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCISession *usrhp; + + dvoid *tmp; + OCIType *mesg_tdo = (OCIType *) 0; + OCIAQMsgProperties *msgprop = (OCIAQMsgProperties *)0; + message msg; + null_message nmsg; + message *mesg = &msg; + null_message *nmesg = &nmsg; + int i; + int priority; + + /* Standard OCI initialization */ + + OCIInitialize((ub4) OCI_OBJECT, (dvoid *)0, (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *,dvoid * ,size_t)) 0, (dvoid (*)(dvoid *,dvoid *)) 0 ); + + OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &envhp, + (ub4) OCI_HTYPE_ENV, 52, (dvoid **) &tmp); + + OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + /* allocate a error report handle */ + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, 52, (dvoid **) &tmp); + + /* allocate a server context handle */ + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, 52, (dvoid **) &tmp); + + /* Create an assocaition between the server and the oci application */ + OCIServerAttach( srvhp, errhp, (text *) 0, (sb4) 0, (ub4) OCI_DEFAULT); + + /* allocate a service context handle */ + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, 52, (dvoid **) &tmp); + + /* set attribute server context in the service context */ + OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *)srvhp, + (ub4) 0 , (ub4) OCI_ATTR_SERVER, (OCIError *) errhp); + + /* allocate a user session handle */ + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0); + + OCIAttrSet( (dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, (dvoid *)"aquser", + (ub4)strlen("aquser"), OCI_ATTR_USERNAME, errhp); + + + OCIAttrSet( (dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"aquser", (ub4)strlen("aquser"), + OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, OCI_CRED_RDBMS, + OCI_DEFAULT)); + + OCIAttrSet( (dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, OCI_ATTR_SESSION, errhp); + + checkerr(errhp, OCITypeByName(envhp, errhp, svchp, + (CONST text *)"AQUSER", (ub4)strlen("AQUSER"), + (CONST text *)"MESSAGE", (ub4)strlen("MESSAGE"), (text *)0, 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &mesg_tdo)); + + checkerr(errhp, OCIDescriptorAlloc(envhp, (dvoid **)&msgprop, + OCI_DTYPE_AQMSG_PROPERTIES, 0, (dvoid **)0)); + + printf("Enqueueing messages ...\n"); + /* enqueue 100 messages into input_queue */ + for (i = 1; i <= 100; i++) + { + mesg->city = (OCIString *)0; + priority = i%3 + 1; + + checkerr(errhp, OCINumberFromInt(errhp, &i, sizeof(i), 0, &mesg->id)); + checkerr(errhp, OCINumberFromInt(errhp, &priority, + sizeof(priority), 0, &mesg->priority)); + + /* Set the priority in message property */ + checkerr(errhp, OCIAttrSet(msgprop, OCI_DTYPE_AQMSG_PROPERTIES, + (dvoid *)&priority, sizeof(ub4), OCI_ATTR_PRIORITY, errhp)); + + if (i%3 == 0) + { + checkerr(errhp, OCIStringAssignText(envhp, errhp, + (CONST text *)"BELMONT", (ub4)strlen("BELMONT"), + &mesg->city)); + + nmesg->null_adt = nmesg->null_id = 0; + nmesg->null_city = nmesg->null_priority = 0; + } + else if (i%4 == 0) + { + checkerr(errhp, OCIStringAssignText(envhp, errhp, + (CONST text *)"REDWOOD SHORES", (ub4)strlen("REDWOOD SHORES"), + &mesg->city)); + + nmesg->null_adt = nmesg->null_id = 0; + nmesg->null_city = nmesg->null_priority = 0; + } + else if (i%2 == 0) + { + checkerr(errhp, OCIStringAssignText(envhp, errhp, + (CONST text *)"SUNNYVALE", (ub4)strlen("SUNNYVALE"), + &mesg->city)); + + nmesg->null_adt = nmesg->null_id = 0; + nmesg->null_city = nmesg->null_priority = 0; + } + else + { + checkerr(errhp, OCIStringAssignText(envhp, errhp, + (CONST text *)"BURLINGAME", (ub4)strlen("BURLINGAME"), + &mesg->city)); + + nmesg->null_adt = nmesg->null_id = 0; + nmesg->null_city = nmesg->null_priority = 0; + } + + + /* Enqueue the message */ + checkerr(errhp, OCIAQEnq(svchp, errhp, + (text *) "aquser.input_queue", (OCIAQEnqOptions *)0, + (OCIAQMsgProperties *)msgprop, + mesg_tdo, (dvoid **)&mesg, (dvoid **)&nmesg, (OCIRaw **)0, 0)); + + if ((i %10) == 0) + { + printf("Enqueueing messages %2d through %2d...\n", i-9, i); + sleep(3); + } + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + } + clean_up(envhp, svchp, srvhp, errhp, usrhp, msgprop); + printf("Done.\n"); + exit (0); +} + + +/* end of file ociaqdemo00.c */ + diff --git a/ociaqdemo01.c b/ociaqdemo01.c new file mode 100644 index 0000000..4da549f --- /dev/null +++ b/ociaqdemo01.c @@ -0,0 +1,344 @@ +#ifdef RCSID +static char *RCSid = + "$Header: ociaqdemo01.c 27-mar-2006.23:11:40 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + ociaqdemo01.c - + + DESCRIPTION + + This program dequeues messages by blocking on prop_queue for + approximately 2 minutes on behalf of agent "prog3". The contents + of the messages are inserted into prog3_processed_data table. + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + azhao 03/27/06 - fix 4993505 + rbhyrava 04/05/04 - linux porting + ekarichk 12/18/03 - bug3328852: missing prototypes + bnainani 09/23/99 - Bug 996772: change order of freeing handles + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + kmeiyyap 06/30/99 - free handles + kmeiyyap 06/29/99 - free descriptor + kmeiyyap 10/07/98 - added wait time for dequeue + kmeiyyap 10/06/98 - oci enqueue + kmeiyyap 10/06/98 - Creation + +*/ + +#ifndef OCI_ORACLE +#include +#endif + +#include +#include +#include +#include + +static void checkerr(OCIError *errhp, sword status); + +static void checkerr(OCIError *errhp, sword status) +{ + text errbuf[512]; + ub4 buflen; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + printf("Error - %s\n", errbuf); + exit(1); + case OCI_INVALID_HANDLE: + printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + +struct message +{ + OCINumber id; + OCIString *city; + OCINumber priority; +}; +typedef struct message message; + +struct null_message +{ + OCIInd null_adt; + OCIInd null_id; + OCIInd null_city; + OCIInd null_priority; +}; +typedef struct null_message null_message; + +static void clean_up( OCIEnv *envhp, + OCISvcCtx *svchp, + OCIServer *srvhp, + OCIError *errhp, + OCIStmt *stmthp, + OCISession *usrhp, + OCIAQDeqOptions *deqopt, + message *mesg) ; + +static void clean_up( OCIEnv *envhp, + OCISvcCtx *svchp, + OCIServer *srvhp, + OCIError *errhp, + OCIStmt *stmthp, + OCISession *usrhp, + OCIAQDeqOptions *deqopt, + message *mesg) +{ + /* free dequeue options descriptor */ + checkerr(errhp, OCIDescriptorFree((dvoid *)deqopt, + OCI_DTYPE_AQDEQ_OPTIONS)); + /* free message buffer */ + if (mesg) + checkerr(errhp, OCIObjectFree(envhp, errhp, (dvoid *)mesg, + OCI_OBJECTFREE_FORCE)); + + /* detach from the server */ + checkerr(errhp, OCISessionEnd(svchp, errhp, usrhp, OCI_DEFAULT)); + checkerr(errhp, OCIServerDetach(srvhp, errhp, (ub4)OCI_DEFAULT)); + + if (usrhp) + (void) OCIHandleFree((dvoid *) usrhp, (ub4) OCI_HTYPE_SESSION); + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + if (srvhp) + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + if (stmthp) + (void) OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT); + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV); + + return; +} + +int main() +{ + + OCIEnv *envhp; + OCIServer *srvhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCIStmt *stmthp; + OCISession *usrhp; + + dvoid *tmp; + OCIType *mesg_tdo = (OCIType *) 0; + OCIAQDeqOptions *deqopt = (OCIAQDeqOptions *)0; + message *mesg = (message *)0; + null_message *nmesg = (null_message *)0; + int i; + sb4 navigation = OCI_DEQ_FIRST_MSG; + ub4 wait = 120; + OCIBind *bndhp[3]; + sword status; + sword retval; + text *sqlstmt01; + int id; + int priority; + text *city; + text errbuf[512]; + sb4 errcode; + + + + /* Standard OCI Initialization */ + + OCIInitialize((ub4) OCI_OBJECT, (dvoid *)0, (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *,dvoid * ,size_t)) 0, (dvoid (*)(dvoid *,dvoid *)) 0 ); + + OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &envhp, + (ub4) OCI_HTYPE_ENV, 52, (dvoid **) &tmp); + + OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + /* allocate a error report handle */ + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, 52, (dvoid **) &tmp); + + /* allocate a server context handle */ + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, 52, (dvoid **) &tmp); + + /* Create an assocaition between the server and the oci application */ + OCIServerAttach( srvhp, errhp, (text *) 0, (sb4) 0, (ub4) OCI_DEFAULT); + + /* allocate a service context handle */ + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, 52, (dvoid **) &tmp); + + + /* set attribute server context in the service context */ + OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *)srvhp, + (ub4) 0, (ub4) OCI_ATTR_SERVER, (OCIError *) errhp); + + /* allocate a user session handle */ + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"aquser", (ub4)strlen("aquser"), + OCI_ATTR_USERNAME, errhp); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"aquser", (ub4)strlen("aquser"), + OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, OCI_CRED_RDBMS, + OCI_DEFAULT)); + + OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, OCI_ATTR_SESSION, errhp); + + /* Allocate a statement handle */ + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, 52, (dvoid **) &tmp); + + checkerr(errhp, OCITypeByName(envhp, errhp, svchp, + (CONST text *)"AQUSER", (ub4)strlen("AQUSER"), + (CONST text *)"MESSAGE", (ub4)strlen("MESSAGE"), (text *)0, 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &mesg_tdo)); + + + checkerr(errhp, OCIDescriptorAlloc(envhp, (dvoid **)&deqopt, + OCI_DTYPE_AQDEQ_OPTIONS, 0, (dvoid **)0)); + + /* set wait time of 120 seconds in dequeue option */ + checkerr(errhp, OCIAttrSet(deqopt, OCI_DTYPE_AQDEQ_OPTIONS, + (dvoid *) &wait, 0, OCI_ATTR_WAIT, errhp)); + + /* set navigation to OCI_DEQ_FIRST_MSG in dequeue option */ + checkerr(errhp, OCIAttrSet(deqopt, OCI_DTYPE_AQDEQ_OPTIONS, + (dvoid *)&navigation, sizeof(sb4), + OCI_ATTR_NAVIGATION, errhp)); + + + /* set consumer name to prog3 in dequeue option*/ + checkerr(errhp, OCIAttrSet(deqopt, OCI_DTYPE_AQDEQ_OPTIONS, + (dvoid *)"PROG3", (ub4)strlen("prog3"), + OCI_ATTR_CONSUMER_NAME, errhp)); + + printf("Dequeuing messages ...\n"); + + while(1) + { + printf("Waiting for messages ...\n"); + retval = OCIAQDeq(svchp, errhp, + (text *)"aquser.prop_queue", + deqopt, (OCIAQMsgProperties *)0, mesg_tdo, + (dvoid **)&mesg, + (dvoid **)&nmesg, + (OCIRaw **)0, 0); + if (retval == OCI_ERROR) + { + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, + &errcode, errbuf, (ub4) sizeof(errbuf), + (ub4) OCI_HTYPE_ERROR); + + /* if no more messages to dequeue exit */ + if (errcode == 25228) + { + clean_up(envhp, svchp, srvhp, errhp, stmthp, usrhp, deqopt, + mesg); + printf("No more messages\n"); + exit(1); + } + else + { + printf("PROB HERE?\n"); + checkerr(errhp, retval); + } + } + else + { + checkerr(errhp, retval); + } + + + /* update the tables */ + checkerr(errhp, OCINumberToInt(errhp, &mesg->id, sizeof(id), + OCI_NUMBER_SIGNED, (dvoid *)&id)); + city = OCIStringPtr(envhp, mesg->city); + checkerr(errhp, OCINumberToInt(errhp, &mesg->priority, + sizeof(priority), OCI_NUMBER_SIGNED, (dvoid *)&priority)); + + printf("\tDequeueing message - id: %d\n", id); + printf("\tInserted message info into table PROG3_PROCESSED_DATA\n"); + sqlstmt01 = (text *)"INSERT INTO PROG3_PROCESSED_DATA \ + VALUES (:id, :city, :priority)"; + + /* prepare the statement */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, sqlstmt01, + (ub4)strlen((char *)sqlstmt01), (ub4)OCI_NTV_SYNTAX, + (ub4)OCI_DEFAULT)); + + /* binding placeholders in the insert statement */ + + checkerr(errhp, OCIBindByName(stmthp, &bndhp[0], errhp, + (text *) ":id", -1, (dvoid *) &id, sizeof(id), + SQLT_INT, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4) 0, (ub4 *)0, + OCI_DEFAULT)); + + checkerr(errhp, OCIBindByName(stmthp, &bndhp[1], errhp, + (text *)":city", -1, (dvoid *)city, (sb4)strlen((const signed char *)city)+1, + SQLT_STR, (dvoid *)0, (ub2 *)0, (ub2 *) 0, (ub4) 0, (ub4 *)0, + OCI_DEFAULT)); + + checkerr(errhp, OCIBindByName(stmthp, &bndhp[2], errhp, + (text *) ":priority", -1, (dvoid *) &priority, sizeof(priority), + SQLT_INT, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, + OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL , OCI_DEFAULT)); + + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + } + exit(0); +} + +/* end of file ociaqdemo01.c */ + diff --git a/ociaqdemo02.c b/ociaqdemo02.c new file mode 100644 index 0000000..24df617 --- /dev/null +++ b/ociaqdemo02.c @@ -0,0 +1,550 @@ +#ifdef RCSID +static char *RCSid = + "$Header: ociaqdemo02.c 05-apr-2007.05:15:14 dprasann Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 2007, Oracle. All rights reserved. +*/ + +/* + + NAME + ociaqdemo02.c - + + DESCRIPTION + + This program listens on input_queue for approxmately 2 minutes on behalf + of two agents, "prog1" and "prog2". When there are messages for the agents + in input_queue, the messages are dequeued and message contents are + inserted into appropriate tables (messages for "prog1" is inserted into + prog1_processed_data. messages for "prog2" is inserted into + prog2_processed_data.) + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + dprasann 04/05/07 - lowercase username/password + azhao 03/27/06 - fix 4993505 + rbhyrava 04/05/04 - linux porting + ekarichk 12/18/03 - bug3328852: missing prototypes + lzhao 06/25/01 - comp warning fix + bnainani 09/23/99 - Bug 996772: change order of freeing handles + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + kmeiyyap 06/30/99 - free memory buffer + kmeiyyap 06/29/99 - remove time.h include file + kmeiyyap 11/14/98 - fix gettimeofday parameters + kmeiyyap 10/07/98 - handle timeout error + kmeiyyap 10/06/98 - listen on queue + kmeiyyap 10/06/98 - Creation + +*/ + +#ifndef OCI_ORACLE +#include +#endif + +#include +#include +#include +#include + +/* general OCI context */ +struct oci_ctx +{ + OCIEnv *envhp; /* Environment handle */ + OCISvcCtx *svchp; /* Service context handle */ + OCIServer *srvhp; /* Server handles */ + OCIError *errhp; /* Error handle */ + OCITrans *txnhp; /* Transaction handle */ + OCISession *usrhp; /* User handle */ + char server[40]; /* Server system id */ + OCIStmt *stmthp; /* Statement handle */ +}; +typedef struct oci_ctx oci_ctx; + + +/* dequeue context */ +struct deq_ctx +{ + OCIAQDeqOptions *dopt; + OCIAQMsgProperties *msgprop; + OCIType *mesg_tdo; +}; +typedef struct deq_ctx deq_ctx; + +struct message +{ + OCINumber id; + OCIString *city; + OCINumber priority; +}; +typedef struct message message; + +struct null_message +{ + OCIInd null_adt; + OCIInd null_id; + OCIInd null_city; + OCIInd null_priority; +}; +typedef struct null_message null_message; + +static void checkerr( + OCIError *errhp, + sword status) ; + +static void update_table( oci_ctx *ctx, + text *appname, + message *mesg); + +static void clean_up( oci_ctx ctx, + deq_ctx dctx, + message *mesg, + OCIAQAgent **agent_list); + +static void SetAgent( OCIAQAgent *agent, + text *appname, + text *queue, + OCIError *errhp); + +static text *GetAgent( OCIAQAgent *agent, + OCIError *errhp, + text *qname); + +static void init_ctx( oci_ctx *ctx, + text *username, + text *password ); + +static void setup_dequeue( + oci_ctx *octx, + deq_ctx *dqctx, + text *message_type); + +static void update_table( oci_ctx *ctx, + text *appname, + message *mesg); + +static void checkerr( OCIError *errhp, + sword status) +{ + text errbuf[512]; + ub4 buflen; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + printf("Error - %s\n", errbuf); + exit(1); + case OCI_INVALID_HANDLE: + printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +static void clean_up( oci_ctx ctx, + deq_ctx dctx, + message *mesg, + OCIAQAgent **agent_list) +{ + int i; + for(i = 0; i < 2; i++) + { + checkerr(ctx.errhp, OCIDescriptorFree(agent_list[i], + OCI_DTYPE_AQAGENT)); + } + + /* free dequeue options descriptor */ + checkerr(ctx.errhp, OCIDescriptorFree((dvoid *)dctx.dopt, + OCI_DTYPE_AQDEQ_OPTIONS)); + checkerr(ctx.errhp, OCIDescriptorFree((dvoid *)dctx.msgprop, + OCI_DTYPE_AQMSG_PROPERTIES)); + /* free message buffer */ + if (mesg) + checkerr(ctx.errhp, OCIObjectFree(ctx.envhp, ctx.errhp, + (dvoid *)mesg, OCI_OBJECTFREE_FORCE)); + + /* detach from the server */ + checkerr(ctx.errhp, OCISessionEnd(ctx.svchp, ctx.errhp, + ctx.usrhp, OCI_DEFAULT)); + checkerr(ctx.errhp, OCIServerDetach(ctx.srvhp, ctx.errhp, (ub4)OCI_DEFAULT)); + + /* free handles */ + if (ctx.usrhp) + (void) OCIHandleFree((dvoid *) ctx.usrhp, (ub4) OCI_HTYPE_SESSION); + if (ctx.svchp) + (void) OCIHandleFree((dvoid *) ctx.svchp, (ub4) OCI_HTYPE_SVCCTX); + if (ctx.srvhp) + (void) OCIHandleFree((dvoid *) ctx.srvhp, (ub4) OCI_HTYPE_SERVER); + if (ctx.errhp) + (void) OCIHandleFree((dvoid *) ctx.errhp, (ub4) OCI_HTYPE_ERROR); + if (ctx.stmthp) + (void) OCIHandleFree((dvoid *) ctx.stmthp, (ub4) OCI_HTYPE_STMT); + if (ctx.envhp) + (void) OCIHandleFree((dvoid *) ctx.envhp, (ub4) OCI_HTYPE_ENV); + return; +} + + +/* set agent into descriptor */ +static void SetAgent( OCIAQAgent *agent, + text *appname, + text *queue, + OCIError *errhp) +{ + /* Set agent name */ + checkerr(errhp, OCIAttrSet(agent, OCI_DTYPE_AQAGENT, + appname ? (dvoid *)appname : (dvoid *)"", + appname ? (ub4)strlen((const char *)appname) : 0, + OCI_ATTR_AGENT_NAME, errhp)); + + /* Set agent address */ + checkerr(errhp, OCIAttrSet(agent, OCI_DTYPE_AQAGENT, + queue ? (dvoid *)queue : (dvoid *)"", + queue ? (ub4)strlen((const char *)queue) : 0, + OCI_ATTR_AGENT_ADDRESS, errhp)); +} + + +/* get agent from descriptor */ +static text *GetAgent( OCIAQAgent *agent, + OCIError *errhp, + text *qname) +{ + text *appname; + text *queue; + ub4 appsz; + ub4 queuesz; + + if (!agent ) + { + printf("agent was NULL \n"); + return (text *)"agent was NULL"; + } + checkerr(errhp, OCIAttrGet(agent, OCI_DTYPE_AQAGENT, + (dvoid *)&appname, &appsz, OCI_ATTR_AGENT_NAME, errhp)); + checkerr(errhp, OCIAttrGet(agent, OCI_DTYPE_AQAGENT, + (dvoid *)&queue, &queuesz, OCI_ATTR_AGENT_ADDRESS, errhp)); + if (!appsz) + printf("agent name: NULL\n"); + + if (!queuesz) + printf("agent address: NULL\n"); + + memcpy((dvoid *)qname, (dvoid *)queue, (size_t)queuesz); + + qname[queuesz] = '\0'; + + return qname; +} + + +/* Initialize the OCI context */ + +static void init_ctx( oci_ctx *ctx, + text *username, + text *password ) +{ + dvoid *tmp; + + OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &ctx->envhp, + (ub4) OCI_HTYPE_ENV, 52, (dvoid **) &tmp); + + OCIEnvInit( &ctx->envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + /* allocate a error report handle */ + OCIHandleAlloc((dvoid *) ctx->envhp, (dvoid **) &ctx->errhp, + (ub4) OCI_HTYPE_ERROR, 52, (dvoid **) &tmp); + + /* allocate a server context handle */ + OCIHandleAlloc( (dvoid *) ctx->envhp, (dvoid **) &ctx->srvhp, + (ub4) OCI_HTYPE_SERVER, 52, (dvoid **) &tmp); + + /* Create an assocaition between the server and the oci application */ + OCIServerAttach(ctx->srvhp, ctx->errhp, (text *) 0, (sb4) 0, + (ub4) OCI_DEFAULT); + + /* allocate a service context handle */ + OCIHandleAlloc( (dvoid *) ctx->envhp, (dvoid **) &ctx->svchp, + (ub4) OCI_HTYPE_SVCCTX, 52, (dvoid **) &tmp); + + /* set attribute server context in the service context */ + OCIAttrSet( (dvoid *) ctx->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *)ctx->srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) ctx->errhp); + + /* allocate a user session handle */ + OCIHandleAlloc((dvoid *)ctx->envhp, (dvoid **)&ctx->usrhp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0); + + OCIAttrSet(ctx->usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)username, (ub4)strlen((const signed char *)username), + OCI_ATTR_USERNAME, ctx->errhp); + + + OCIAttrSet(ctx->usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)password, (ub4)strlen((const signed char *)password), + OCI_ATTR_PASSWORD, ctx->errhp); + + checkerr(ctx->errhp, OCISessionBegin(ctx->svchp, ctx->errhp, ctx->usrhp, + OCI_CRED_RDBMS, OCI_DEFAULT)); + + OCIAttrSet(ctx->svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)ctx->usrhp, (ub4)0, OCI_ATTR_SESSION, ctx->errhp); + + /* Allocate a statement handle */ + OCIHandleAlloc( (dvoid *) ctx->envhp, (dvoid **) &ctx->stmthp, + (ub4) OCI_HTYPE_STMT, (size_t)0, (dvoid **) 0); + +} + + +/* set up the context for dequeue */ +static void setup_dequeue( + oci_ctx *octx, + deq_ctx *dqctx, + text *message_type) +{ + ub4 navigation = OCI_DEQ_FIRST_MSG; + OCIDescribe *dschp = (OCIDescribe *)0; + OCIParam *type_param = (OCIParam *)0; + + dqctx->dopt = (OCIAQDeqOptions *)0; + dqctx->msgprop = (OCIAQMsgProperties *)0; + dqctx->mesg_tdo = (OCIType *)0; + + /* message properties descriptor */ + checkerr(octx->errhp, + OCIDescriptorAlloc(octx->envhp, (dvoid **) &dqctx->msgprop, + OCI_DTYPE_AQMSG_PROPERTIES, 0, (dvoid **)0)); + + /* dequeue options descriptor */ + checkerr(octx->errhp, + OCIDescriptorAlloc(octx->envhp, (dvoid **) &dqctx->dopt, + OCI_DTYPE_AQDEQ_OPTIONS, 0, (dvoid **)0)); + + /* set navigation in dequeue options */ + checkerr(octx->errhp, OCIAttrSet(dqctx->dopt, OCI_DTYPE_AQDEQ_OPTIONS, + (dvoid *)&navigation, 0, + OCI_ATTR_NAVIGATION, octx->errhp)); + + + /* get TOID */ + checkerr(octx->errhp, OCIHandleAlloc((dvoid *) octx->envhp, + (dvoid **)&dschp, (ub4) OCI_HTYPE_DESCRIBE, (size_t) 0, (dvoid **) 0)); + + + checkerr(octx->errhp, OCIDescribeAny(octx->svchp, octx->errhp, + (dvoid *)message_type, (ub4)strlen((const signed char *)message_type), + OCI_OTYPE_NAME, 0, OCI_PTYPE_TYPE, dschp)); + + /* get the type descriptor */ + checkerr(octx->errhp, OCIAttrGet((dvoid *)dschp, + (ub4)OCI_HTYPE_DESCRIBE, (dvoid *)&type_param, + (ub4 *)0, (ub4)OCI_ATTR_PARAM, (OCIError *)octx->errhp)); + + + /* get the tdo of the type */ + checkerr(octx->errhp, OCIAttrGet((dvoid *)type_param, + (ub4)OCI_DTYPE_PARAM, (dvoid *)&dqctx->mesg_tdo, + (ub4 *)0, (ub4)OCI_ATTR_TDO, (OCIError *)octx->errhp)); +} + +static void update_table( oci_ctx *ctx, + text *appname, + message *mesg) +{ + + text *sqlstmt01; + OCIBind *bndhp[3]; + int id; + int priority; + text *city; + + if (strcmp((const signed char *)appname, "PROG1") == 0 ) + { + sqlstmt01 = (text *)"INSERT INTO PROG1_PROCESSED_DATA \ + VALUES (:id, :city, :priority)"; + } + else if (strcmp((const signed char *)appname, "PROG2") == 0) + { + sqlstmt01 = (text *)"INSERT INTO PROG2_PROCESSED_DATA \ + VALUES (:id, :city, :priority)"; + } + + checkerr(ctx->errhp, OCINumberToInt(ctx->errhp, &mesg->id, sizeof(id), + OCI_NUMBER_SIGNED, (dvoid *)&id)); + city = OCIStringPtr(ctx->envhp, mesg->city); + checkerr(ctx->errhp, OCINumberToInt(ctx->errhp, &mesg->priority, + sizeof(priority), OCI_NUMBER_SIGNED, (dvoid *)&priority)); + + printf("\tDequeueing message - id: %d for %s\n", id, appname); + if (strcmp((const signed char *)appname, "PROG1") == 0) + printf("\tInserting message info into table PROG1_PROCESSED_DATA\n"); + else if (strcmp((const signed char *)appname, "PROG2") == 0) + printf("\tInserting message info into table PROG2_PROCESSED_DATA\n"); + + /* prepare the statement */ + checkerr(ctx->errhp, OCIStmtPrepare(ctx->stmthp, ctx->errhp, sqlstmt01, + (ub4)strlen((char *)sqlstmt01), (ub4)OCI_NTV_SYNTAX, + (ub4)OCI_DEFAULT)); + + /* binding placeholders in the insert statement */ + + checkerr(ctx->errhp, OCIBindByName(ctx->stmthp, &bndhp[0], ctx->errhp, + (text *) ":id", -1, (dvoid *) &id, sizeof(id), SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4) 0, (ub4 *)0, OCI_DEFAULT)); + + checkerr(ctx->errhp, OCIBindByName(ctx->stmthp, &bndhp[1], ctx->errhp, + (text *)":city",-1,(dvoid *)city, + (sb4)strlen((const signed char *)city)+1, SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *) 0, (ub4) 0, (ub4 *)0, OCI_DEFAULT)); + + checkerr(ctx->errhp, OCIBindByName(ctx->stmthp, &bndhp[2], ctx->errhp, + (text *)":priority", -1, (dvoid *) &priority, sizeof(priority), + SQLT_INT, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, + OCI_DEFAULT)); + + checkerr(ctx->errhp, OCIStmtExecute(ctx->svchp, ctx->stmthp, ctx->errhp, + (ub4)1 , (ub4) 0, (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL , + OCI_DEFAULT)); + +} + +int main() +{ + oci_ctx ctx; + deq_ctx dctx; + OCIAQAgent *agent_list[2]; + OCIAQAgent *agent = (OCIAQAgent *)0; + OCIRaw *msgID = (OCIRaw *)0; + text type_name[61] = "AQUSER.MESSAGE"; + OCIDescribe *dschp = (OCIDescribe *)0; + OCIParam *type_param = (OCIParam *)0; + OCIType *mesg_tdo = (OCIType *)0; + message *mesg = (message *)0; + null_message nmsg; + null_message *nmesg = &nmsg; + text qname[61]; + ub4 i; + sword retval; + text *appname; + ub4 appsz; + text errbuf[512]; + sb4 errcode; + + OCIInitialize((ub4) OCI_OBJECT, (dvoid *)0, (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *,dvoid * ,size_t)) 0, (dvoid (*)(dvoid *,dvoid *)) 0 ); + + init_ctx(&ctx, (oratext *)"aquser",(oratext *) "aquser"); + + /* allocate agent handles */ + for (i = 0; i < 2; i++) + { + checkerr(ctx.errhp, OCIDescriptorAlloc(ctx.envhp, + (dvoid **)&agent_list[i], OCI_DTYPE_AQAGENT, 0, (dvoid **)0)); + } + + + SetAgent(agent_list[0], (oratext *)"prog1",(oratext *) "aquser.input_queue", ctx.errhp); + SetAgent(agent_list[1],(oratext *) "prog2", (oratext *)"aquser.input_queue", ctx.errhp); + + setup_dequeue(&ctx, &dctx, (oratext *)"AQUSER.MESSAGE"); + + printf("Listening and dequeuing messages ...\n"); + + while(1) + { + printf("Listening for messages for PROG1 and PROG2...\n"); + + retval = OCIAQListen(ctx.svchp, ctx.errhp, agent_list, 2, 120, &agent, + 0); + if (retval == OCI_ERROR) + { + OCIErrorGet ((dvoid *) ctx.errhp, (ub4) 1, (text *) NULL, + &errcode, errbuf, (ub4) sizeof(errbuf), + (ub4) OCI_HTYPE_ERROR); + + /* if listen call timed out, continue listen */ + if (errcode == 25254) + { + printf("No more messages\n"); + clean_up(ctx, dctx, mesg, agent_list); + exit(1); + } + else + checkerr(ctx.errhp, retval); + } + else + { + checkerr(ctx.errhp, retval); + } + + GetAgent(agent, ctx.errhp, qname); + + checkerr(ctx.errhp, OCIAttrGet(agent, OCI_DTYPE_AQAGENT, + (dvoid *)&appname, &appsz, OCI_ATTR_AGENT_NAME, ctx.errhp)); + + if (strcmp((const signed char *)appname, "PROG1") == 0) + { + /* set consumer name to prog1 */ + checkerr(ctx.errhp, OCIAttrSet(dctx.dopt, OCI_DTYPE_AQDEQ_OPTIONS, + (dvoid *)"PROG1", (ub4)strlen("PROG1"), + OCI_ATTR_CONSUMER_NAME, ctx.errhp)); + } + else if (strcmp((const signed char *)appname, "PROG2") == 0) + { + /* set consumer name to prog1 */ + checkerr(ctx.errhp, OCIAttrSet(dctx.dopt, OCI_DTYPE_AQDEQ_OPTIONS, + (dvoid *)"PROG2", (ub4)strlen("PROG2"), + OCI_ATTR_CONSUMER_NAME, ctx.errhp)); + } + + checkerr(ctx.errhp, OCIAQDeq(ctx.svchp, ctx.errhp, + (text *)qname, dctx.dopt, + dctx.msgprop, dctx.mesg_tdo, + (dvoid **)&mesg, (dvoid **)&nmesg, &msgID, 0)); + + update_table(&ctx, appname, mesg); + + checkerr(ctx.errhp, OCITransCommit(ctx.svchp, ctx.errhp, (ub4) 0)); + + } + exit(0); +} + + +/* end of file ociaqdemo02.c */ + diff --git a/ociucb.c b/ociucb.c new file mode 100644 index 0000000..249e9f8 --- /dev/null +++ b/ociucb.c @@ -0,0 +1,146 @@ +#ifdef RCSID +static char *RCSid = + "$Header: ociucb.c 14-jul-99.13:40:30 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + ociucb.c - OCI - User Call Back + + DESCRIPTION + Contains the defintion of ociucbInit and ociucbEnvCallback routines. + + The ociucbInit routine is called by OCI to initialize the shared library. + The ociucbEnvCallback routine is called by OCIEnvInit if ORA_OCI_UCBPKG + environment variable is set and OCIInitialize is not called with a mode of + OCI_ENV_NO_UCB. + + PUBLIC FUNCTION(S) + ociucbInit - OCI Shared Library Callback Main Function + ociucbEnvCallback - OCI ENVironment handle CALLBACK + + PRIVATE FUNCTION(S) + None yet. + + RETURNS + NA + + NOTES + + + MODIFIED (MM/DD/YY) + slari 09/10/99 - bg989981: remove envCallback from ociucbInit + slari 08/30/99 - provide ociucbInit + slari 08/23/99 - add OCIUcb in call to OCIEnvCallback + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + slari 04/12/98 - change message for OCIEnvCallback + slari 03/17/98 - add comments + slari 02/12/98 - user callback file to provide code for OCIEnvCallback + slari 02/12/98 - Creation + +*/ + + + +#include +#include +#include +#include + + + /* the forward declaration must be done so that + OCIShareLibInit can be passed a pointer to this function + */ + +sword ociucbEnvCallback(OCIEnv *env, ub4 mode, size_t xtramemsz, dvoid *usrmemp, + OCIUcb *ucbDesc); + + + +/*--------------------------------- ociucbInit ---------------------------------*/ + +/* + NAME: + ociucbInit - OCI Shared Library CallBack Main function + + PARAMETERS: + meta - The metacontext + libCtx - The context for this package + argfmt - The package argument format + argc - The number of arguments passed + argv - The arguments to the package + + DESCRIPTION: + This is called by OCI to load and initialize the shared library + (package). + + The OCI shared library initialization is done by passing all the + parameters passed to the the shared library initialization function to + the OCISharedLibInit function. User's environment callback function of + type OCIEnvCallbackType is also passed to the OCISharedLibInit call. + + + RETURNS: + the return code from OCISharedLibInit function. + + NOTES: +*/ + +sword ociucbInit(metaCtx, libCtx, argfmt, argc, argv) +dvoid * metaCtx; /* The metacontext */ +dvoid * libCtx; /* The context for this program or package if you + have previously been called. */ +ub4 argfmt; /* What am I supposed to do? */ +sword argc; /* argc if I am being called as a program */ +dvoid * argv[]; /* argv if I am being called as a program */ +{ + return (OCISharedLibInit(metaCtx, libCtx, argfmt, argc, argv, + ociucbEnvCallback)); +} + + +/*--------------------------------- ociucbEnvCallback -----------------------*/ + +/* + NAME: + ociucbEnvCallback - OCI ENVironment handle CALLBACK + + DESCRIPTION: + This function is called by the OCIEnvInit function at the end after it + has allocated and intialized the environment handle. + + PARAMETERS + env - The newly created environment handle + mode - The mode passed to the OCIEnvInit call + xtramemsz - The xtramemsz passed to the OCIEnvInit call + usrmemp - Pointer to additional memory allocated for user memory + requested + ucbDesc - OCIUcb descriptor + + RETURNS: + Success/Error Code + + NOTES: +*/ + + +sword ociucbEnvCallback(env, mode, xtramemsz, usrmemp, ucbDesc) +OCIEnv *env; +ub4 mode; +size_t xtramemsz; +dvoid *usrmemp; +OCIUcb *ucbDesc; +{ + printf("ociucbEnvCallback called.\n"); + + return OCI_CONTINUE; +} + + + +/* end of file ociucb.c */ + diff --git a/ociucb.mk b/ociucb.mk new file mode 100644 index 0000000..3e25488 --- /dev/null +++ b/ociucb.mk @@ -0,0 +1,32 @@ +# +# Makefile for building callback shared library +# +# To link user callback DLL: +# +# make -f ociucb.mk user_callback SHARED_LIBNAME=libname +# OBJS="user.o ..." +# e.g. make -f ociucb.mk user_callback SHARED_LIBNAME=ociucb.so.1.0 \ +# OBJS=ociucb.o +# +# +# +# +# NOTE: 1. ORACLE_HOME must be either: +# . set in the user's environment +# . passed in on the command line +# . defined in a modified version of this makefile +# +# 2. Look in the platform specific documentation for information +# about environment variables that need to be properly +# defined (e.g. LD_LIBRARY_PATH in Solaris). +# + +include $(ORACLE_HOME)/rdbms/lib/env_rdbms.mk + +.SUFFIXES: .o + +.c.o: + $(C2O) + +user_callback: $(OBJS) + $(BUILD_USERCALLBACK) diff --git a/ociucb32.mk b/ociucb32.mk new file mode 100644 index 0000000..e39f236 --- /dev/null +++ b/ociucb32.mk @@ -0,0 +1,32 @@ +# +# Makefile for building callback shared library +# +# To link user callback DLL: +# +# make -f ociucb32.mk user_callback SHARED_LIBNAME=libname +# OBJS="user.o ..." +# e.g. make -f ociucb32.mk user_callback SHARED_LIBNAME=ociucb.so.1.0 \ +# OBJS=ociucb.o +# +# +# +# +# NOTE: 1. ORACLE_HOME must be either: +# . set in the user's environment +# . passed in on the command line +# . defined in a modified version of this makefile +# +# 2. Look in the platform specific documentation for information +# about environment variables that need to be properly +# defined (e.g. LD_LIBRARY_PATH in Solaris). +# + +include $(ORACLE_HOME)/rdbms/lib/env_rdbms.mk + +.SUFFIXES: .o + +.c.o: + $(C2O32) + +user_callback: $(OBJS) + $(BUILD_USERCALLBACK32) diff --git a/olsdemo.sql b/olsdemo.sql new file mode 100644 index 0000000..505d915 --- /dev/null +++ b/olsdemo.sql @@ -0,0 +1,748 @@ +Rem +Rem $Header: olsdemo.sql 29-may-2007.01:55:55 srramara Exp $ +Rem +Rem olsdemo.sql +Rem +Rem Copyright (c) 2001, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem olsdemo.sql - Oracle Label Security demo +Rem +Rem DESCRIPTION +Rem Builds Oracle Label Security demonstration labels and tables +Rem +Rem NOTES +Rem Executing user must have DBA and LBAC_DBA roles +Rem Install with NUMERIC labels assumed +Rem First clean up previous install using olsdrp.sql +Rem +Rem MODIFIED (MM/DD/YY) +Rem srramara 05/29/07 - passwd case sensitivity changes +Rem vpesati 01/21/02 - modify label function +Rem vpesati 01/18/02 - change to varchar2, trim blank padding +Rem snamudur 10/17/01 - For adding orderby clause +Rem gmurphy 02/02/01 - Merged gmurphy_ols_2rdbms +Rem vpesati 01/18/01 - oracle label security demo +Rem vpesati 01/18/01 - Created +Rem + +spool olsdemo.log +rem ==================================================================== +rem Building Oracle Label Security demo +rem ==================================================================== + +rem ==================================================================== +rem Create admin users and demo owner +rem ==================================================================== + +CONNECT SYSTEM/manager; +CREATE USER "HR_ADMIN" IDENTIFIED BY "HR_ADMIN"; +GRANT CONNECT, RESOURCE, SELECT_CATALOG_ROLE TO HR_ADMIN; + +CREATE USER "DEFENSE_ADMIN" IDENTIFIED BY "DEFENSE_ADMIN"; +GRANT CONNECT, RESOURCE, SELECT_CATALOG_ROLE TO DEFENSE_ADMIN; + +CREATE USER "SA_DEMO" IDENTIFIED BY "SA_DEMO"; +GRANT CONNECT, RESOURCE, SELECT_CATALOG_ROLE TO SA_DEMO; + +rem ==================================================================== +rem Connect as LBACSYS to grant authorization to SA_DEMO +rem ==================================================================== + +CONNECT LBACSYS/lbacsys + +GRANT EXECUTE ON sa_components TO SA_DEMO WITH GRANT OPTION; +GRANT EXECUTE ON sa_user_admin TO SA_DEMO WITH GRANT OPTION; +GRANT EXECUTE ON sa_user_admin TO SA_DEMO WITH GRANT OPTION; +GRANT EXECUTE ON sa_label_admin TO SA_DEMO WITH GRANT OPTION; +GRANT EXECUTE ON sa_policy_admin TO SA_DEMO WITH GRANT OPTION; +GRANT EXECUTE ON sa_audit_admin TO SA_DEMO WITH GRANT OPTION; + +GRANT LBAC_DBA TO SA_DEMO; +GRANT EXECUTE ON sa_sysdba TO SA_DEMO; +GRANT EXECUTE ON to_lbac_data_label TO SA_DEMO; + +CONNECT SA_DEMO/SA_DEMO +rem ==================================================================== +rem Creating Employee Policy: 'human_resources' +rem ==================================================================== + +EXECUTE SA_SYSDBA.CREATE_POLICY('human_resources','hr_label'); +GRANT HUMAN_RESOURCES_DBA TO HR_ADMIN; + +GRANT EXECUTE ON sa_components TO HR_ADMIN; +GRANT EXECUTE ON sa_user_admin TO HR_ADMIN; +GRANT EXECUTE ON sa_user_admin TO HR_ADMIN; +GRANT EXECUTE ON sa_label_admin TO HR_ADMIN; +GRANT EXECUTE ON sa_policy_admin TO HR_ADMIN; +GRANT EXECUTE ON sa_audit_admin TO HR_ADMIN; + +rem ==================================================================== +rem Creating DEFENSE Policy: 'defense' +rem ==================================================================== +EXECUTE SA_SYSDBA.CREATE_POLICY('defense','defense_label'); +GRANT DEFENSE_DBA TO DEFENSE_ADMIN; + +GRANT EXECUTE ON sa_components TO DEFENSE_ADMIN; +GRANT EXECUTE ON sa_user_admin TO DEFENSE_ADMIN; +GRANT EXECUTE ON sa_user_admin TO DEFENSE_ADMIN; +GRANT EXECUTE ON sa_label_admin TO DEFENSE_ADMIN; +GRANT EXECUTE ON sa_policy_admin TO DEFENSE_ADMIN; +GRANT EXECUTE ON sa_audit_admin TO DEFENSE_ADMIN; + +rem ==================================================================== +rem Creating Demo Tables: Dept, Emp and URLTable +rem +rem The Department Table will be the standard Department table +rem with no Secure Access Policy Protections. +rem +rem The Emp Table will be Protected by Secure Access and +rem Labels with a Rules Based Policy. +rem +rem The URLTable Table will be Protected by Secure Access +rem and rely on explicit Labeling +rem +rem ==================================================================== +rem Creating Secure Access Definitions to Support Label Policies +rem ==================================================================== + +rem ==================================================================== +rem Creating Levels, Compartments and Groups for Emp table +rem ==================================================================== + +CONNECT HR_ADMIN/HR_ADMIN + +EXECUTE SA_COMPONENTS.CREATE_LEVEL('human_resources',50,'L3','Level 3'); +EXECUTE SA_COMPONENTS.CREATE_LEVEL('human_resources',30,'L2','Level 2'); +EXECUTE SA_COMPONENTS.CREATE_LEVEL('human_resources',10,'L1','Level 1'); + +EXECUTE SA_COMPONENTS.CREATE_COMPARTMENT('human_resources',100,'M','MANAGEMENT'); +EXECUTE SA_COMPONENTS.CREATE_COMPARTMENT('human_resources',110,'E','EMPLOYEE'); + +EXECUTE SA_COMPONENTS.CREATE_GROUP('human_resources',10,'D10','DEPARTMENT 10'); +EXECUTE SA_COMPONENTS.CREATE_GROUP('human_resources',20,'D20','DEPARTMENT 20'); +EXECUTE SA_COMPONENTS.CREATE_GROUP('human_resources',30,'D30','DEPARTMENT 30'); +EXECUTE SA_COMPONENTS.CREATE_GROUP('human_resources',40,'D40','DEPARTMENT 40'); + +EXECUTE SA_USER_ADMIN.SET_USER_PRIVS('human_resources','sa_demo','FULL'); +EXECUTE SA_USER_ADMIN.SET_USER_PRIVS('human_resources','hr_admin','FULL,PROFILE_ACCESS'); + + +rem ==================================================================== +rem Creating Dept Table +rem ==================================================================== + +CONNECT SA_DEMO/SA_DEMO + +CREATE TABLE SA_DEMO.DEPT ( + DEPTNO NUMBER(2) NOT NULL, + DNAME VARCHAR2(14), + LOC VARCHAR2(13), + CONSTRAINT DEPT_PRIMARY_KEY PRIMARY KEY (DEPTNO)); + +GRANT SELECT, INSERT, UPDATE, DELETE ON DEPT to PUBLIC; + +rem ==================================================================== +rem Populating Dept table +rem ==================================================================== + +INSERT INTO SA_DEMO.DEPT VALUES (10,'ACCOUNTING','NEW YORK'); +INSERT INTO SA_DEMO.DEPT VALUES (20,'RESEARCH','DALLAS'); +INSERT INTO SA_DEMO.DEPT VALUES (30,'SALES','CHICAGO'); +INSERT INTO SA_DEMO.DEPT VALUES (40,'OPERATIONS','BOSTON'); + +COMMIT; + +rem ==================================================================== +rem Creating Emp Table +rem ==================================================================== + +CREATE TABLE SA_DEMO.EMP ( + EMPNO NUMBER(4) NOT NULL, + ENAME VARCHAR2(10), + JOB VARCHAR2(9), + MGR NUMBER(4), + HIREDATE DATE, + SAL NUMBER(7,2), + COMM NUMBER(7,2), + DEPTNO NUMBER(2) NOT NULL, + CONSTRAINT EMP_PRIMARY_KEY PRIMARY KEY (EMPNO)); + +GRANT SELECT, INSERT, UPDATE, DELETE ON EMP TO PUBLIC; + +rem ==================================================================== +rem Creating Rules Based Label Policy for EMP Table +rem ==================================================================== + +CREATE OR REPLACE FUNCTION sa_demo.gen_emp_label + (Job varchar2, + Deptno number, + Total_sal number) + Return LBACSYS.LBAC_LABEL +as + i_label varchar2(80); +Begin + /* Determine Class Level */ + if total_sal > 2000 then + i_label := 'L3:'; + elsif total_sal >1000 then + i_label := 'L2:'; + else + i_label := 'L1:'; + end if; + + /* Determine Compartment */ + IF TRIM(' ' from UPPER(Job)) in ('MANAGER','PRESIDENT') then + i_label := i_label||'M:'; + else + i_label := i_label||'E:'; + end if; + /* Determine Groups */ + i_label := i_label||'D'||to_char(deptno); + return TO_LBAC_DATA_LABEL('human_resources',i_label); +End; +/ + +SHOW ERRORS + +rem ==================================================================== +rem Populating Emp Table +rem ==================================================================== + +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7839,'KING','PRESIDENT',NULL,'17-NOV-81',5000,NULL,10); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7698,'BLAKE','MANAGER',7839,'1-MAY-81',2850,NULL,30); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7782,'CLARK','MANAGER',7839,'9-JUN-81',2450,NULL,10); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7566,'JONES','MANAGER',7839,'2-APR-81',2975,NULL,20); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7654,'MARTIN','SALESMAN',7698,'28-SEP-81',1250,1400,30); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7499,'ALLEN','SALESMAN',7698,'20-FEB-81',1600,300,30); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7844,'TURNER','SALESMAN',7698,'8-SEP-81',1500,0,30); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7900,'JAMES','CLERK',7698,'3-DEC-81',950,NULL,30); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7521,'WARD','SALESMAN',7698,'22-FEB-81',1250,500,30); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7902,'FORD','ANALYST',7566,'3-DEC-81',3000,NULL,20); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7369,'SMITH','CLERK',7902,'17-DEC-80',800,NULL,20); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7788,'SCOTT','ANALYST',7566,'09-DEC-82',3000,NULL,20); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7876,'ADAMS','CLERK',7788,'12-JAN-83',1100,NULL,20); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7934,'MILLER','CLERK',7782,'23-JAN-82',1300,NULL,10); +COMMIT; + +rem ==================================================================== +rem Apply HR policy to EMP to add HR_LABEL colulmn +rem Specify NO_CONTROL to disable policy enforcement +rem HR_ADMIN is authorized to apply policies, not SA_DEMO +rem ==================================================================== + +CONNECT HR_ADMIN/HR_ADMIN + +BEGIN + SA_POLICY_ADMIN.APPLY_TABLE_POLICY('human_resources', + 'sa_demo','emp','no_control'); +END; +/ + +rem ==================================================================== +rem Initialize hr_label to 'L1' for existing data. +rem Note: if label is NULL and policy is ENABLED, +rem then no access will be allowed. +rem ==================================================================== + +UPDATE SA_DEMO.EMP SET hr_label = CHAR_TO_LABEL('human_resources','L1'); +COMMIT; + +rem ==================================================================== +rem Remove policy and re-apply with LABEL FUNCTION specified +rem ==================================================================== + +BEGIN + SA_POLICY_ADMIN.REMOVE_TABLE_POLICY('human_resources','sa_demo','emp'); + SA_POLICY_ADMIN.APPLY_TABLE_POLICY ( + POLICY_NAME => 'human_resources', + SCHEMA_NAME => 'sa_demo', + TABLE_NAME => 'emp', + TABLE_OPTIONS => 'READ_CONTROL,WRITE_CONTROL,CHECK_CONTROL', + LABEL_FUNCTION => 'sa_demo.gen_emp_label(:new.job,:new.deptno,:new.sal)', + PREDICATE => NULL); +END; +/ + +rem ==================================================================== +rem Now force an Update to Relabel the data with rules in place. +rem ==================================================================== + +UPDATE SA_DEMO.EMP SET deptno=deptno; +COMMIT; + +col hr_label format a15 +SELECT empno, sal, deptno, label_to_char(hr_label) AS hr_label FROM SA_DEMO.EMP; + +rem ==================================================================== +rem Displaying generated labels +rem ==================================================================== + +COLUMN policy_name FORMAT A15 +COLUMN label FORMAT A15 +SELECT * FROM DBA_SA_LABELS WHERE policy_name='HUMAN_RESOURCES' + ORDER BY POLICY_NAME, LABEL_TAG; + +rem ==================================================================== +rem Now re-apply policy with READ, WRITE, and CHECK_CONTROL enforcement +rem ==================================================================== + +BEGIN + SA_POLICY_ADMIN.REMOVE_TABLE_POLICY('human_resources','sa_demo','emp'); + SA_POLICY_ADMIN.APPLY_TABLE_POLICY ( + POLICY_NAME => 'human_resources', + SCHEMA_NAME => 'sa_demo', + TABLE_NAME => 'emp', + TABLE_OPTIONS => 'READ_CONTROL,WRITE_CONTROL,CHECK_CONTROL', + LABEL_FUNCTION => 'sa_demo.gen_emp_label(:new.job,:new.deptno,:new.sal)', + PREDICATE => NULL); +END; +/ + +rem ==================================================================== +rem Create Trusted Function compute average salary +rem ==================================================================== + +CONNECT SA_DEMO/SA_DEMO + +CREATE OR REPLACE FUNCTION sa_demo.average_sal +RETURN NUMBER IS + a NUMBER; +BEGIN + SELECT avg(sal) INTO a FROM emp; + RETURN a; +END; +/ +GRANT EXECUTE ON average_sal TO PUBLIC; + + +CONNECT HR_ADMIN/HR_ADMIN +EXECUTE SA_USER_ADMIN.SET_PROG_PRIVS('Human_resources','sa_demo','average_sal','READ'); + +rem ==================================================================== +rem Creating Levels, Compartments and Groups for URLTABLE table +rem ==================================================================== + +CONNECT DEFENSE_ADMIN/DEFENSE_ADMIN + +EXECUTE SA_COMPONENTS.CREATE_LEVEL('defense',500,'TS','TOP SECRET'); +EXECUTE SA_COMPONENTS.CREATE_LEVEL('defense',300,'SE','SECRET'); +EXECUTE SA_COMPONENTS.CREATE_LEVEL('defense',100,'UN','UNCLASSIFIED'); + +EXECUTE SA_COMPONENTS.CREATE_COMPARTMENT('defense',100,'US_SPCL','United States Special Data'); +EXECUTE SA_COMPONENTS.CREATE_COMPARTMENT('defense',200,'US_ONLY','United States Only Data'); + +EXECUTE SA_COMPONENTS.CREATE_GROUP('defense',10,'COAL','Coalition'); +EXECUTE SA_COMPONENTS.CREATE_GROUP('defense',11,'US','United States','COAL'); +EXECUTE SA_COMPONENTS.CREATE_GROUP('defense',12,'CA','Canada','COAL'); +EXECUTE SA_COMPONENTS.CREATE_GROUP('defense',13,'UK','United Kingdom','COAL'); +EXECUTE SA_COMPONENTS.CREATE_GROUP('defense',14,'AU','Austrailia','COAL'); + +rem ==================================================================== +rem Creating Table URLTable +rem This example includes the DEFENSE_LABEL in the design +rem ==================================================================== + +CONNECT SA_DEMO/SA_DEMO +CREATE TABLE SA_DEMO.URLTABLE( + ITEM_NUMBER NUMBER, + FILE_NAME VARCHAR2(2000), + CRITERION VARCHAR2(500) Not Null, + TYPEDATA VARCHAR2(100) Not Null, + NOTATION VARCHAR2(2000) Not Null, + RLABEL NUMBER, + OWNER VARCHAR2(30), + LAST_UPDATED DATE, + DEFENSE_LABEL NUMBER(10) NOT NULL, + CONSTRAINT URL_PRIMARY_KEY PRIMARY KEY (ITEM_NUMBER)); + +GRANT SELECT, UPDATE, DELETE, INSERT ON URLTABLE TO PUBLIC; + +rem ==================================================================== +rem Add Explicit Security Labels to support the DEFENSE Policy +rem ==================================================================== + +CONNECT DEFENSE_ADMIN/DEFENSE_ADMIN +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',1100,'UN:US_SPCL:'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',2100,'SE:US_SPCL:'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',2110,'SE:US_SPCL:US'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',2120,'SE:US_SPCL:US,CA'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',2130,'SE:US_SPCL:US,CA,UK,AU'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',2140,'SE:US_SPCL:COAL'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',3110,'TS:US_SPCL:US'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',2200,'SE:US_ONLY:'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',3200,'TS:US_ONLY:'); + +rem ==================================================================== +rem Displaying created labels +rem ==================================================================== + +COLUMN policy_name FORMAT A12 +COLUMN label FORMAT A25 +SELECT * FROM DBA_SA_LABELS WHERE policy_name='DEFENSE' + ORDER BY POLICY_NAME, LABEL_TAG; + +rem ==================================================================== +rem Inserted data into table with Explicit label included in statement. +rem ==================================================================== + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(5, +'http://security.us.oracle.com:80/demo_images/sbox.gif', +'UAV Imagery', +'SAR', +'Sensor Box US Demo36 Data', +char_to_label('defense','SE:US_SPCL:US')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(6, +'http://security.us.oracle.com:80/demo_images/image_nyc14.jpg', +'JSTARS Imagery', +'Imagery', +'Korona imagery minefield', +char_to_label('defense','SE:US_SPCL:US')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(7, +'http://security.us.oracle.com:80/demo_images/radar_sumara_russia.gif', +'JSTARS Imagery', +'SAR', +'Terrorist training camp', +char_to_label('defense','SE:US_SPCL:US,CA')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(8, +'http://security.us.oracle.com:80/demo_images/radar_rondonia_brazil.gif', +'UAV Imagery', +'SAR', +'UAV detects probable WMD storage sites', +char_to_label('defense','SE:US_SPCL:US,CA')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(9, +'http://security.us.oracle.com:80/demo_images/p0086.gif', +'Triggers', +'19.06.073', +'Mine Recovery and exploit, mine image', +char_to_label('defense','SE:US_SPCL:US,CA,UK,AU')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(10, +'http://security.us.oracle.com:80/demo_images/p0392.gif', +'Triggers', +'19.06.073', +'Mine Profile for Recovery', +char_to_label('defense','SE:US_SPCL:US,CA,UK,AU')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(11, +'http://security.us.oracle.com:80/demo_images/nyc.jpg', +'JSTARS Imagery', +'SAR', +'Potential Rendezvous sites', +char_to_label('defense','TS:US_SPCL:US')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(12, +'http://security.us.oracle.com:80/demo_images/track.gif', +'Triggers', +'19.01.276', +'Track Data DEFENSE Day3 from COP, Demo85', +char_to_label('defense','TS:US_SPCL:US')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(13, +'http://security.us.oracle.com:80/demo_images/sigs0014.gif', +'Triggers', +'19.01.112', +'Pull for OPS primary image GBS Misson planning', +char_to_label('defense','UN:US_SPCL:')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(14, +'http://security.us.oracle.com:80/demo_images/sigs0060.gif', +'Triggers', +'19.01.112', +'Misson planning, SIGS imagery from Sensor Box', +char_to_label('defense','UN:US_SPCL:')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(15, +'http://security.us.oracle.com:80/demo_images/sigs0081.gif', +'Triggers', +'22.01.112', +'SIGS Imagery for coalition planning, from Sensor Box', +char_to_label('defense','SE:US_SPCL:')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(16, +'http://security.us.oracle.com:80/demo_images/coalition_sar_day1.gif', +'UAV Imagery', +'SAR', +'Coalition UAV SAR for DEFENSE97 day3 US Demo85', +char_to_label('defense','SE:US_SPCL:')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(21, +'http://security.us.oracle.com:80/demo_images/photo_c130_hercules.jpg', +'Transport', +'Photo', +'C-130 Hercules kicking up a lot of dust', +char_to_label('defense','SE:US_SPCL:COAL')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(22, +'http://security.us.oracle.com:80/demo_images/photo_f14_tomcat.jpg', +'Fighter', +'Photo', +'In-flight view of an F-14 Tomcat escorting a pair of Russian bombers', +char_to_label('defense','SE:US_SPCL:COAL')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(17, +'http://security.us.oracle.com:80/demo_images/sigs0271.gif', +'UAV Imagery', +'SAR', +'Coalition DEFENSE97 day3 Kartuna Tank Platoon', +char_to_label('defense','SE:US_ONLY:')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(18, +'http://security.us.oracle.com:80/demo_images/sar.gif', +'UAV Imagery', +'SAR', +'US Demo85 SAR data', +char_to_label('defense','SE:US_ONLY:')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(19, +'http://security.us.oracle.com:80/demo_images/onslow.gif', +'Triggers', +'19.01.085', +'METOC Amphibious Opernations Area Forecast, Onslow Beach', +char_to_label('defense','TS:US_ONLY:')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(20, +'http://security.us.oracle.com:80/demo_images/nyc.jpg', +'UAV Imagery', +'Photo', +'Kartuna field operations HQ', +char_to_label('defense','TS:US_ONLY:')); +rem ==================================================================== +rem Apply Secure Acess DEFENSE policy to URLTABLE +rem ==================================================================== + +Begin + SA_POLICY_ADMIN.APPLY_TABLE_POLICY ( + POLICY_NAME => 'defense', + SCHEMA_NAME => 'sa_demo', + TABLE_NAME => 'urltable', + TABLE_OPTIONS => 'ALL_CONTROL', + LABEL_FUNCTION => NULL, + PREDICATE => NULL); +End; +/ + +rem ==================================================================== +rem Create Secure Access User Accounts +rem ==================================================================== +CONNECT SYSTEM/manager; + +CREATE USER "PRES" IDENTIFIED BY "SA"; +CREATE USER "MD10" IDENTIFIED BY "SA"; +CREATE USER "ED10" IDENTIFIED BY "SA"; +CREATE USER "ED20" IDENTIFIED BY "SA"; + +CREATE USER "UN_SP" IDENTIFIED BY "SA"; +CREATE USER "SE_SP" IDENTIFIED BY "SA"; +CREATE USER "TS_SP" IDENTIFIED BY "SA"; +CREATE USER "SE_US" IDENTIFIED BY "SA"; +CREATE USER "SE_CA" IDENTIFIED BY "SA"; +CREATE USER "SE_UK" IDENTIFIED BY "SA"; +CREATE USER "SE_AU" IDENTIFIED BY "SA"; +CREATE USER "SE_CO" IDENTIFIED BY "SA"; +CREATE USER "TS_US" IDENTIFIED BY "SA"; +CREATE USER "SE_USO" IDENTIFIED BY "SA"; +CREATE USER "TS_USO" IDENTIFIED BY "SA"; + + +rem ==================================================================== +rem Set User Labels For HUMAN_RESOURCES Policy +rem ==================================================================== +CONNECT HR_ADMIN/HR_ADMIN + +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('human_resources','PRES','L3:M,E'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('human_resources','MD10','L3:M,E:D10'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('human_resources','ED10','L3:E:D10'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('human_resources','ED20','L3:E:D20'); + +EXECUTE SA_USER_ADMIN.ALTER_COMPARTMENTS('human_resources','PRES','E',sa_utl.read_only); + +rem ==================================================================== +rem Set User Labels For DEFENSE Policy +rem ==================================================================== +CONNECT DEFENSE_ADMIN/DEFENSE_ADMIN + +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','UN_SP','UN:US_SPCL:'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','SE_SP','SE:US_SPCL:'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','TS_SP','TS:US_SPCL:'); + +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','SE_US','SE:US_SPCL:US'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','SE_CA','SE:US_SPCL:CA'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','SE_UK','SE:US_SPCL:UK'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','SE_AU','SE:US_SPCL:AU'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','SE_CO','SE:US_SPCL:COAL'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','TS_US','TS:US_SPCL:US'); + +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','SE_USO','SE:US_ONLY:'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','TS_USO','TS:US_ONLY:'); + +EXECUTE SA_USER_ADMIN.ALTER_COMPARTMENTS('defense','SE_CA','US_SPCL',sa_utl.read_only); +EXECUTE SA_USER_ADMIN.ALTER_COMPARTMENTS('defense','SE_UK','US_SPCL',sa_utl.read_only); +EXECUTE SA_USER_ADMIN.ALTER_COMPARTMENTS('defense','SE_AU','US_SPCL',sa_utl.read_only); +EXECUTE SA_USER_ADMIN.ALTER_GROUPS('defense','SE_CA','CA',sa_utl.read_only); +EXECUTE SA_USER_ADMIN.ALTER_GROUPS('defense','SE_UK','UK',sa_utl.read_only); +EXECUTE SA_USER_ADMIN.ALTER_GROUPS('defense','SE_AU','AU',sa_utl.read_only); + +rem ==================================================================== +rem Set User PRIVILEGES For DEFENSE Policy +rem ==================================================================== + +EXECUTE SA_USER_ADMIN.SET_USER_PRIVS('defense','defense_admin','full,profile_access'); +EXECUTE SA_USER_ADMIN.SET_USER_PRIVS('defense','se_co','compaccess,writeacross'); +EXECUTE SA_USER_ADMIN.SET_USER_PRIVS('defense','Se_sp','compaccess,writeacross,writeup,writedown'); + + +rem ==================================================================== +rem Check data dictionary views and other functionality +rem ==================================================================== + +COLUMN NOTATION FORMAT A50 +COLUMN LABEL FORMAT A25 +COLUMN POLICY_NAME FORMAT A15 +COLUMN USER_NAME FORMAT A15 +COLUMN USER_PRIVILEGES FORMAT A30 + +SET PAGESIZE 80 +SET ECHO ON +rem ==================================================================== +rem Display Secure Access data dictionary views +rem ==================================================================== + +CONNECT HR_ADMIN/HR_ADMIN + +SELECT * FROM DBA_SA_POLICIES +ORDER BY policy_name; + +SELECT * FROM DBA_SA_LABELS +ORDER BY policy_name, label_tag; + +SELECT * FROM DBA_SA_USERS +ORDER BY policy_name, user_name; + +SELECT * FROM DBA_SA_PROG_PRIVS +ORDER BY policy_name, schema_name, program_name; + +SELECT * FROM DBA_SA_SCHEMA_POLICIEs +ORDER BY policy_name, schema_name; + +SELECT * FROM DBA_SA_TABLE_POLICIES +ORDER BY policy_name, schema_name, table_name; + +rem ==================================================================== +rem Use average_sal Trusted Function +rem HR_ADMIN has FULL privilege +rem ==================================================================== + +SELECT avg(sal) FROM SA_DEMO.EMP; + +rem ==================================================================== +rem ED10 has NO privileges +rem ==================================================================== + +EXECUTE SA_SESSION.SET_ACCESS_PROFILE('human_resources','ED10'); +SELECT avg(sal) FROM SA_DEMO.EMP; + +rem ==================================================================== +rem average_sal function has READ privilege +rem ==================================================================== +SET SERVEROUTPUT ON +DECLARE averg NUMBER; +BEGIN + averg := sa_demo.average_sal; + DBMS_OUTPUT.PUT_LINE('Average is ' || averg); +END; +/ +SET SERVEROUTPUT OFF + +rem ==================================================================== +rem Retrieve different results as different users +rem ==================================================================== + +CONNECT DEFENSE_ADMIN/DEFENSE_ADMIN + +SET PAGESIZE 0 + +rem ==================================================================== +rem DEFENSE_ADMIN as FULL and PROFILE_ACCESS privilege +rem ==================================================================== + +SELECT * FROM USER_SA_SESSION +WHERE policy_name='DEFENSE'; +SELECT label_to_char(defense_label) as label, notation FROM SA_DEMO.URLTABLE; + +EXECUTE SA_SESSION.SET_ACCESS_PROFILE('defense','ts_us'); +SELECT * FROM USER_SA_SESSION +WHERE policy_name='DEFENSE'; +SELECT label_to_char(defense_label) as label, notation FROM SA_DEMO.URLTABLE; + +EXECUTE SA_SESSION.SET_ACCESS_PROFILE('defense','se_ca'); +SELECT * FROM USER_SA_SESSION +WHERE policy_name='DEFENSE'; +SELECT label_to_char(defense_label) as label, notation FROM SA_DEMO.URLTABLE; + +EXECUTE SA_SESSION.SET_ACCESS_PROFILE('defense','un_sp'); +SELECT * FROM USER_SA_SESSION +WHERE policy_name='DEFENSE'; +SELECT label_to_char(defense_label) as label, notation FROM SA_DEMO.URLTABLE; + + +rem ==================================================================== +rem Demo Build ..... Complete +rem Review olsdemo.log file +rem ==================================================================== + +spool off diff --git a/olsdrp.sql b/olsdrp.sql new file mode 100644 index 0000000..b688ca6 --- /dev/null +++ b/olsdrp.sql @@ -0,0 +1,61 @@ +Rem +Rem $Header: olsdrp.sql 29-may-2007.01:56:44 srramara Exp $ +Rem +Rem olsdrp.sql +Rem +Rem Copyright (c) 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem olsdrp.sql - Drop Oracle Label Security demo +Rem +Rem DESCRIPTION +Rem Drops Oracle Label Security demonstration policies, tables and users +Rem +Rem NOTES +Rem Run this script before olsdemo to clean up previous demo installs +Rem +Rem MODIFIED (MM/DD/YY) +Rem srramara 05/29/07 - passwd case sensitivity changes +Rem gmurphy 02/02/01 - Merged gmurphy_ols_2rdbms +Rem vpesati 01/18/01 - oracle label security demo drop script +Rem vpesati 01/18/01 - Created +Rem + +rem ==================================================================== +rem Dropping HUMAN_RESOURCES and DEFENSE policies +rem ==================================================================== + +CONNECT SA_DEMO/SA_DEMO +EXECUTE SA_SYSDBA.DROP_POLICY('human_resources'); +EXECUTE SA_SYSDBA.DROP_POLICY('defense'); + +rem ==================================================================== +rem Dropping SA_DEMO, HR_ADMIN, DEFENSE_ADMIN and other users +rem ==================================================================== + +CONNECT SYSTEM/manager as sysdba; +DROP USER SA_DEMO CASCADE; +DROP USER HR_ADMIN CASCADE; +DROP USER DEFENSE_ADMIN CASCADE; + +DROP USER PRES CASCADE; +DROP USER MD10 CASCADE; +DROP USER ED10 CASCADE; +DROP USER ED20 CASCADE; + +DROP USER UN_SP CASCADE; +DROP USER SE_SP CASCADE; +DROP USER TS_SP CASCADE; +DROP USER SE_US CASCADE; +DROP USER SE_CA CASCADE; +DROP USER SE_UK CASCADE; +DROP USER SE_AU CASCADE; +DROP USER SE_CO CASCADE; +DROP USER TS_US CASCADE; +DROP USER SE_USO CASCADE; +DROP USER TS_USO CASCADE; + + +rem ==================================================================== +rem Drop Demo ..... Complete +rem ==================================================================== diff --git a/ori_f.sed b/ori_f.sed new file mode 100644 index 0000000..e13bffd --- /dev/null +++ b/ori_f.sed @@ -0,0 +1,35 @@ +# NAME +# ori_f.sed +# DESCRIPTION +# This sed script changes the ORI function and type names to long +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/16/96 - Peter Vasterd - Add changes from Calvin +s/oricfls/OCICacheFlush/g +s/origbgu/OCIDurationBegin/g +s/origedu/OCIDurationEnd/g +s/origpdr/OCIDurationGetParent/g +s/orioapn/OCIObjectArrayPin/g +s/oricfre/OCICacheFree/g +s/oriocpy/OCIObjectCopy/g +s/oricrfs/OCICacheRefresh/g +s/oricunp/OCICacheUnpin/g +s/oriogex/OCIObjectExists/g +s/oriogfl/OCIObjectFlushStatus/g +s/oriogns/OCIObjectGetInd/g +s/oriogor/OCIObjectGetObjectRef/g +s/oriogtb/OCIObjectPinTable/g +s/oriogtr/OCIObjectGetTypeRef/g +s/orionew/OCIObjectNew/g +s/oriofls/OCIObjectFlush/g +s/oriofre/OCIObjectFree/g +s/oriolck/OCIObjectLock/g +s/oriordl/OCIObjectMarkDeleteByRef/g +s/oriopin/OCIObjectPin/g +s/oriopdl/OCIObjectMarkDelete/g +s/oriorfs/OCIObjectRefresh/g +s/oriounp/OCIObjectUnpin/g +s/orioupd/OCIObjectMarkUpdate/g +s/orioupz/OCIObjectPinCountReset/g +s/oridset/OCIObjectSetAttr/g +s/oridget/OCIObjectGetAttr/g diff --git a/orl_f.sed b/orl_f.sed new file mode 100644 index 0000000..d3192cc --- /dev/null +++ b/orl_f.sed @@ -0,0 +1,128 @@ +# NAME +# orl_f.sed +# DESCRIPTION +# This sed script changes the ORL function and type +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/10/96 - Peter Vasterd - Merge Calvins' stuff +s/gye_orldat/OCIDateYYYY/g +s/mon_orldat/OCIDateMM/g +s/day_orldat/OCIDateDD/g +s/time_orldat/OCIDateTime/g +s/orldtmhh/OCITimeHH/g +s/orldtmmm/OCITimeMI/g +s/orldtmss/OCITimeSS/g +s/orldgye/OCIDateYYYY/g +s/orldmon/OCIDateMM/g +s/orlday/OCIDateDD/g +s/orldtime/OCIDateTime/g +s/orlbl/OCILobLocator/g +s/orlblen/OCILobLength/g +s/orlbmo/OCILobMode/g +s/orlboff/OCILobOffset/g +s/orlcapp/OCICollAppend/g +s/orlcase/OCICollAssignElem/g +s/orlcasg/OCICollAssign/g +s/orlccit/OCIIterCreate/g +s/orlcdit/OCIIterDelete/g +s/orlcget/OCICollGetElem/g +s/orlcicur/OCIIterGetCurrent/g +s/orlciit/OCIIterInit/g +s/orlcinxt/OCIIterNext/g +s/orlciprv/OCIIterPrev/g +s/orlcitr/OCIIter/g +s/orlcmax/OCICollMax/g +s/orlcol/OCIColl/g +s/orlcsiz/OCICollSize/g +s/orlctrm/OCICollTrim/g +s/orld2s/OCIDateToText/g +s/orldadd/OCIDateAddDays/g +s/orldadm/OCIDateAddMonths/g +s/orldat/OCIDate/g +s/orldtm/OCITime/g +s/orldbtw/OCIDateDaysBetween/g +s/orldchk/OCIDateCheck/g +s/orldcmp/OCIDateCompare/g +s/orldlst/OCIDateLastDay/g +s/orldndy/OCIDateNextDay/g +s/orlds2d/OCIDateFromText/g +s/orldsys/OCIDateSysDate/g +s/orldz2z/OCIDateZoneToZone/g +s/orllasg/OCILobAssign/g +s/orllequ/OCILobIsEqual/g +s/orllgcid/OCILobCharSet/g +s/orllgnm/OCILobFileGetName/g +s/orllgsz/OCILobLocatorSize/g +s/orllnul/OCILobIsNull/g +s/orllsnm/OCILobFileSetName/g +s/orln2i/OCINumberToInt/g +s/orln2r/OCINumberToReal/g +s/orln2s/OCINumberToText/g +s/orlnabs/OCINumberAbs/g +s/orlnacos/OCINumberArcCos/g +s/orlnadd/OCINumberAdd/g +s/orlnasg/OCINumberAssign/g +s/orlnasin/OCINumberArcSin/g +s/orlnatan/OCINumberArcTan/g +s/orlnatn2/OCINumberTanToArc/g +s/orlnbex/OCINumberExp/g +s/orlncel/OCINumberCeil/g +s/orlncmp/OCINumberCompare/g +s/orlncos/OCINumberCos/g +s/orlncsh/OCINumberHypCos/g +s/orlndiv/OCINumberDiv/g +s/orlnexp/OCINumberPower/g +s/orlnflr/OCINumberFloor/g +s/orlni2n/OCINumberFromInt/g +s/orlnini/OCINumberInit/g +s/orlnln/OCINumberLn/g +s/orlnlog/OCINumberLog/g +s/orlnmod/OCINumberMod/g +s/orlnmul/OCINumberMul/g +s/orlnneg/OCINumberNeg/g +s/orlnpwr/OCINumberIntPower/g +s/orlnr2n/OCINumberFromReal/g +s/orlnrou/OCINumberRound/g +s/orlns2n/OCINumberFromText/g +s/orlnsgn/OCINumberSign/g +s/orlnsin/OCINumberSin/g +s/orlnsnh/OCINumberHypSin/g +s/orlnsqr/OCINumberSqr/g +s/orlnsub/OCINumberSub/g +s/orlntan/OCINumberTan/g +s/orlntnh/OCINumberHypTan/g +s/orlntru/OCINumberTruncate/g +s/orlnum/OCINumber/g +s/orlnzer/OCINumberZero/g +s/orlr2h/OCIRefToHex/g +s/orlrasg/OCIRefAssign/g +s/orlraw/OCIRaw/g +s/orlrclr/OCIRefClear/g +s/orlrequ/OCIRefIsEqual/g +s/orlrh2r/OCIRefFromHex/g +s/orlrhsz/OCIRefHexSize/g +s/orlrnul/OCIRefIsNull/g +s/orltbl/OCITable/g +s/orltdel/OCITableDelete/g +s/orltexi/OCITableExists/g +s/orltfst/OCITableFirst/g +s/orltlst/OCITableLast/g +s/orltnxt/OCITableNext/g +s/orltprv/OCITablePrev/g +s/orltsiz/OCITableSize/g +s/orlvary/OCIArray/g +s/orlvass/OCIStringAssign/g +s/orlvasz/OCIStringAllocSize/g +s/orlvats/OCIStringAssignText/g +s/orlvgsp/OCIStringPtr/g +s/orlvgsz/OCIStringSize/g +s/orlvrsz/OCIStringResize/g +s/orlvstr/OCIString/g +s/orlwabr/OCIRawAssignBytes/g +s/orlwarr/OCIRawAssignRaw/g +s/orlwasz/OCIRawAllocSize/g +s/orlwgrp/OCIRawPtr/g +s/orlwgsz/OCIRawSize/g +s/orlwrsz/OCIRawResize/g +s/orlnpart/OCINumberPart/g +s/orldgye/OCIDateYYYY/g diff --git a/orl_m.sed b/orl_m.sed new file mode 100644 index 0000000..0d50202 --- /dev/null +++ b/orl_m.sed @@ -0,0 +1,28 @@ +# NAME +# orl_m.sed +# DESCRIPTION +# This sed script changes the ORLmacro names to long names +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/10/96 - Peter Vasterd - Merge Calvins stuff +# 11/09/96 - Peter Vasterd - Fix Order +s/ORLBMORO/OCI_LOBMODE_READONLY/g +s/ORLBMORW/OCI_LOBMODE_READWRITE/g +s/ORL_NUMSIZ/OCI_NUMBER_SIZE/g +s/ORLTUB/OCI_NUMBER_UNSIGNED/g +s/ORLTSB/OCI_NUMBER_SIGNED/g +s/ORLD_BDAL/OCI_DATE_DAY_BELOW_VALID/g +s/ORLD_BDA/OCI_DATE_INVALID_DAY/g +s/ORLD_BMOL/OCI_DATE_MONTH_BELOW_VALID/g +s/ORLD_BMO/OCI_DATE_INVALID_MONTH/g +s/ORLD_BYRL/OCI_DATE_YEAR_BELOW_VALID/g +s/ORLD_BYR/OCI_DATE_INVALID_YEAR/g +s/ORLD_BHRL/OCI_DATE_HOUR_BELOW_VALID/g +s/ORLD_BHR/OCI_DATE_INVALID_HOUR/g +s/ORLD_BMNL/OCI_DATE_MINUTE_BELOW_VALID/g +s/ORLD_BMN/OCI_DATE_INVALID_MINUTE/g +s/ORLD_BSCL/OCI_DATE_SECOND_BELOW_VALID/g +s/ORLD_BSC/OCI_DATE_INVALID_SECOND/g +s/ORLD_MSD/OCI_DATE_DAY_MISSING_FROM_1582/g +s/ORLD_YR0/OCI_DATE_YEAR_ZERO/g +s/ORLD_BDT/OCI_DATE_INVALID_FORMAT/g diff --git a/oro_f.sed b/oro_f.sed new file mode 100644 index 0000000..04701af --- /dev/null +++ b/oro_f.sed @@ -0,0 +1,19 @@ +# NAME +# oro_f.sed +# DESCRIPTION +# This sed script changes the ORO function and type to long names. +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/10/96 - Peter Vasterd - Merge Calvins' stuff +s/oroind/OCIInd/g +s/oroodt/OCIDuration/g +s/oroolm/OCILockOpt/g +s/oroomo/OCIMarkOpt/g +s/oroopo/OCIPinOpt/g +s/ororef/OCIRef/g +s/orooro/OCICoherency/g +s/orotc/OCITypeCode/g +s/orotec/OCITypeEncap/g +s/orotmf/OCITypeMethodFlag/g +s/orotpm/OCITypeParamMode/g +s/orotgo/OCITypeGetOpt/g diff --git a/oro_m.sed b/oro_m.sed new file mode 100644 index 0000000..8f14715 --- /dev/null +++ b/oro_m.sed @@ -0,0 +1,136 @@ +# NAME +# oro_m.sed +# DESCRIPTION +# This sed script changes the ORO macro names to long # names. +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/10/96 - Peter Vasterd - Merge Calvin's stuff +s/OROINDBNUL/OCI_IND_BADNULL/g +s/OROINDNNBL/OCI_IND_NOTNULLABLE/g +s/OROINDNNUL/OCI_IND_NOTNULL/g +s/OROINDNULL/OCI_IND_NULL/g +s/OROODTBEG/OCI_DURATION_BEGIN/g +s/OROODTCAL/OCI_DURATION_CALL/g +s/OROODTDFL/OCI_DURATION_DEFAULT/g +s/OROODTNUL/OCI_DURATION_NULL/g +s/OROODTPRE/OCI_DURATION_LAST/g +s/OROODTSES/OCI_DURATION_SESSION/g +s/OROODTSPC/OCI_DURATION_NEXT/g +s/OROODTTRA/OCI_DURATION_TRANS/g +s/OROOLMNUL/OCI_LOCK_NONE/g +s/OROOLMX/OCI_LOCK_X/g +s/OROOMODFL/OCI_MARK_DEFAULT/g +s/OROOMONON/OCI_MARK_NONE/g +s/OROOMOUPD/OCI_MARK_UPDATE/g +s/OROOPODFL/OCI_PIN_DEFAULT/g +s/OROOPOANY/OCI_PIN_ANY/g +s/OROOPOLST/OCI_PIN_LATEST/g +s/OROOROAWY/OCI_COHERENCY_ALWAYS/g +s/OROORONON/OCI_COHERENCY_NONE/g +s/OROORONUL/OCI_COHERENCY_NULL/g +s/OROTCAAT/OCI_TYPECODE_UNNAMEDADT/g +s/OROTCBFL/OCI_TYPECODE_BFILE/g +s/OROTCBLB/OCI_TYPECODE_BLOB/g +s/OROTCBYT/OCI_TYPECODE_SIGNED8/g +s/OROTCCFL/OCI_TYPECODE_CFILE/g +s/OROTCCLB/OCI_TYPECODE_CLOB/g +s/OROTCDAT/OCI_TYPECODE_DATE/g +s/OROTCDEC/OCI_TYPECODE_DECIMAL/g +s/OROTCDOM/OCI_TYPECODE_NAMEDCOLLECTION/g +s/OROTCDOU/OCI_TYPECODE_DOUBLE/g +s/OROTCFLO/OCI_TYPECODE_FLOAT/g +s/OROTCFSI/OCI_TYPECODE_CHAR/g +s/OROTCINT/OCI_TYPECODE_INTEGER/g +s/OROTCLAST/OCI_TYPECODE_LAST/g +s/OROTCLEX/OCI_TYPECODE_FIRSTCOMPLEX/g +s/OROTCLLAST/OCI_TYPECODE_LASTCOMPLEX/g +s/OROTCLON/OCI_TYPECODE_SIGNED32/g +s/OROTCMLS/OCI_TYPECODE_MLSLABEL/g +s/OROTCMST/OCI_TYPECODE_TABLE/g +s/OROTCNAT/OCI_TYPECODE_ADT/g +s/OROTCNUM/OCI_TYPECODE_NUMBER/g +s/OROTCOCT/OCI_TYPECODE_OCTET/g +s/OROTCPLAST/OCI_TYPECODE_LASTSCALAR/g +s/OROTCPRE/OCI_TYPECODE_FIRSTSCALAR/g +s/OROTCPTR/OCI_TYPECODE_PTR/g +s/OROTCRAW/OCI_TYPECODE_RAW/g +s/OROTCREA/OCI_TYPECODE_REAL/g +s/OROTCREF/OCI_TYPECODE_REF/g +s/OROTCSET/OCI_TYPECODE_SET/g +s/OROTCSHO/OCI_TYPECODE_SIGNED16/g +s/OROTCSML/OCI_TYPECODE_SMALLINT/g +s/OROTCUBY/OCI_TYPECODE_UNSIGNED8/g +s/OROTCULO/OCI_TYPECODE_UNSIGNED32/g +s/OROTCUSH/OCI_TYPECODE_UNSIGNED16/g +s/OROTCFAR/OCI_TYPECODE_FARRAY/g +s/OROTCVAR/OCI_TYPECODE_VARRAY/g +s/OROTCVSI/OCI_TYPECODE_VARCHAR2/g +s/OROTCVSO/OCI_TYPECODE_VARCHAR/g +s/OROTCS00/OCI_TYPECODE_SQL00/g +s/OROTCS01/OCI_TYPECODE_SQL01/g +s/OROTCS02/OCI_TYPECODE_SQL02/g +s/OROTCS03/OCI_TYPECODE_SQL03/g +s/OROTCP00/OCI_TYPECODE_PLSQL00/g +s/OROTCP01/OCI_TYPECODE_PLSQL01/g +s/OROTCP02/OCI_TYPECODE_PLSQL02/g +s/OROTCP03/OCI_TYPECODE_PLSQL03/g +s/OROTCP04/OCI_TYPECODE_PLSQL04/g +s/OROTCP05/OCI_TYPECODE_PLSQL05/g +s/OROTCP06/OCI_TYPECODE_PLSQL06/g +s/OROTCP07/OCI_TYPECODE_PLSQL07/g +s/OROTCP08/OCI_TYPECODE_PLSQL08/g +s/OROTCP09/OCI_TYPECODE_PLSQL09/g +s/OROTCP10/OCI_TYPECODE_PLSQL10/g +s/OROTDVAR/OCI_VARRAY_MAXSIZE/g +s/OROTDVST/OCI_STRING_MAXLEN/g +s/OROTECPUB/OCI_TYPEENCAP_PUBLIC/g +s/OROTECPVT/OCI_TYPEENCAP_PRIVATE/g +s/OROTMFCON/OCI_TYPEMETHOD_CONSTANT/g +s/OROTMFINL/OCI_TYPEMETHOD_INLINE/g +s/OROTMFCSTR/OCI_TYPEMETHOD_CONSTRUCTOR/g +s/OROTMFDSTR/OCI_TYPEMETHOD_DESTRUCTOR/g +s/OROTMFICO/OCI_METHOD_IS_CONSTANT/g +s/OROTMFICS/OCI_METHOD_IS_CONSTRUCTOR/g +s/OROTMFIDS/OCI_METHOD_IS_DESTRUCTOR/g +s/OROTMFIIN/OCI_METHOD_IS_INLINE/g +s/OROTMFIMP/OCI_METHOD_IS_MAP/g +s/OROTMFIOP/OCI_METHOD_IS_OPERATOR/g +s/OROTMFIOR/OCI_METHOD_IS_ORDER/g +s/OROTMFIRD/OCI_METHOD_IS_RNDS/g +s/OROTMFIRP/OCI_METHOD_IS_RNPS/g +s/OROTMFISL/OCI_METHOD_IS_SELFISH/g +s/OROTMFIVR/OCI_METHOD_IS_VIRTUAL/g +s/OROTMFIWD/OCI_METHOD_IS_WNDS/g +s/OROTMFIWP/OCI_METHOD_IS_WNPS/g +s/OROTMFMAP/OCI_TYPEMETHOD_MAP/g +s/OROTMFOP/OCI_TYPEMETHOD_OPERATOR/g +s/OROTMFOR/OCI_TYPEMETHOD_ORDER/g +s/OROTMFSLF/OCI_TYPEMETHOD_SELFISH/g +s/OROTMFRDS/OCI_TYPEMETHOD_RNDS/g +s/OROTMFRPS/OCI_TYPEMETHOD_RNPS/g +s/OROTMFVRT/OCI_TYPEMETHOD_VIRTUAL/g +s/OROTMFWDS/OCI_TYPEMETHOD_WNDS/g +s/OROTMFWPS/OCI_TYPEMETHOD_WNPS/g +s/OROTMFSCO/OCI_TYPEMETHOD_SET_CONSTANT/g +s/OROTMFSCS/OCI_TYPEMETHOD_SET_CONSTRUCTOR/g +s/OROTMFSDS/OCI_TYPEMETHOD_SET_DESTRUCTOR/g +s/OROTMFSIN/OCI_TYPEMETHOD_SET_INLINE/g +s/OROTMFSMP/OCI_TYPEMETHOD_SET_MAP/g +s/OROTMFSOP/OCI_TYPEMETHOD_SET_OPERATOR/g +s/OROTMFSOR/OCI_TYPEMETHOD_SET_ORDER/g +s/OROTMFSRD/OCI_TYPEMETHOD_SET_RNDS/g +s/OROTMFSRP/OCI_TYPEMETHOD_SET_RNPS/g +s/OROTMFSSL/OCI_TYPEMETHOD_SET_SELFISH/g +s/OROTMFSVR/OCI_TYPEMETHOD_SET_VIRTUAL/g +s/OROTMFSWD/OCI_TYPEMETHOD_SET_WNDS/g +s/OROTMFSWP/OCI_TYPEMETHOD_SET_WNPS/g +s/OROTNOPRE/OCI_NUMBER_DEFAULTPREC/g +s/OROTNOSCL/OCI_NUMBER_DEFAULTSCALE/g +s/OROTPMIO/OCI_TYPEPARAM_INOUT/g +s/OROTPMIN/OCI_TYPEPARAM_IN/g +s/OROTPMREF/OCI_TYPEPARAM_BYREF/g +s/OROTPMOUT/OCI_TYPEPARAM_OUT/g +s/OROTGOHDR/OCI_TYPEGET_HEADER/g +s/OROTGOALL/OCI_TYPEGET_ALL/g +s/OROCOSFN/OCI_COPY_NOREF/g + diff --git a/ort_f.sed b/ort_f.sed new file mode 100644 index 0000000..63bd6cd --- /dev/null +++ b/ort_f.sed @@ -0,0 +1,59 @@ +# NAME +# ort_f.sed +# DESCRIPTION +# This sed script changes the ORT function and type names to long names +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/10/96 - Peter Vasterd - Merge Calvins' stuff +s/ortado/OCITypeElem/g +s/ortgabi/OCITypeAttrNext/g +s/ortgabn/OCITypeAttrByName/g +s/ortganm/OCITypeElemName/g +s/ortgpnm/OCITypeElemName/g +s/ortgasqt/OCITypeElemExtTypeCode/g +s/ortgatc/OCITypeElemTypeCode/g +s/ortgcel/OCITypeCollElem/g +s/ortgcne/OCITypeCollSize/g +s/ortgcsqt/OCITypeCollExtTypeCode/g +s/ortgdttc/OCITypeCollTypeCode/g +s/ortgmbi/OCITypeMethodNext/g +s/ortgmbn/OCITypeMethodByName/g +s/ortgmen/OCITypeMethodEncap/g +s/ortgmfl/OCITypeMethodFlags/g +s/ortgmmap/OCITypeMethodMap/g +s/ortgmnm/OCITypeMethodName/g +s/ortgmno/OCITypeMethodOverload/g +s/ortgmnp/OCITypeMethodParams/g +s/ortgmor/OCITypeMethodOrder/g +s/ortgnp/OCITypeElemNumPrec/g +s/ortgns/OCITypeElemNumScale/g +s/ortgpa/OCITypeElemParameterizedType/g +s/ortgpbn/OCITypeParamByName/g +s/ortgpbp/OCITypeParamByPos/g +s/ortgpps/OCITypeParamPos/g +s/ortgpdv/OCITypeElemDefaultValue/g +s/ortgpmo/OCITypeElemParamMode/g +s/ortgptc/OCITypeElemTypeCode/g +s/ortgscform/OCITypeElemCharSetForm/g +s/ortgscid/OCITypeElemCharSetID/g +s/ortgsl/OCITypeElemLength/g +s/ortgtme/OCITypeName/g +s/ortgtna/OCITypeAttrs/g +s/ortgtnm/OCITypeMethods/g +s/ortgttc/OCITypeTypeCode/g +s/ortgtsch/OCITypeSchema/g +s/ortgtvn/OCITypeVersion/g +s/ortgpty/OCITypeElemType/g +s/ortifre/OCITypeIterFree/g +s/ortinew/OCITypeIterNew/g +s/ortiset/OCITypeIterSet/g +s/ortitr/OCITypeIter/g +s/ortmdo/OCITypeMethod/g +s/ortpdo/OCITypeElem/g +s/ortrdo/OCITypeElem/g +s/orttdo/OCIType/g +s/ortvini/OCITypeVTInit/g +s/ortvins/OCITypeVTInsert/g +s/ortvsel/OCITypeVTSelect/g +s/ortgatyp/OCITypeArrayByName/g +s/ortgaty/OCITypeElemType/g diff --git a/readpipe.c b/readpipe.c new file mode 100644 index 0000000..8eda286 --- /dev/null +++ b/readpipe.c @@ -0,0 +1,242 @@ +#ifdef RCSID +static char *RCSid = + "$Header: rdbms/demo/readpipe.c /main/9 2008/08/29 10:48:36 yitseng Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1991, 2008, Oracle. All rights reserved. +*/ + +/* + NAME + readpipe.c - read a server named pipe + NOTES + described in ORACLE7 Server Application Developer's Guide + MODIFIED (MM/DD/YY) + yitseng 08/29/08 - XbranchMerge yitseng_bug6273715 from st_rdbms_10.2 + yitseng 09/20/07 - bug6273715 + ppallapo 02/28/06 - Bug/5068904 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + bnnguyen 04/01/98 - bug487125 + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + emendez 04/07/94 - merge changes from branch 1.3.710.2 + gdoherty 04/06/94 - merge changes from branch 1.3.710.1 + emendez 02/02/94 - Fix for bug 157576 + gdoherty 01/31/94 - make oci header inclusion for ansi or k+r adaptive + rkooi 12/15/92 - add some comments + tssmith 12/15/92 - Added break in for(;;) loop + tssmith 12/12/92 - Creation +*/ + +/* + * readpipe.c + * + * This OCI program demonstrates how to read messages from + * a named pipe. This program can be run in + * a window or terminal session, and be used to print messages + * from a PL/SQL source program (an anonymous block or a + * stored procedure). + * + * This is very useful in debugging PL/SQL programs. + * + * First, you must create a PL/SQL package and package body that packs + * your message(s) and sends them to a named pipe. + * In the example below, two 'put' procedures are implemented, + * overloaded by type: VARCHAR2 and NUMBER. This you can extend + * as required for additional types. + * + * Store this package in the server in an appropriate schema, + * and grant execute privilege on it to the users who require it. + * + * You will need to grant execute privilege on the dbms_pipe package + * to the owner of the plsdbg package below. + * + * Note that this example uses only a single named pipe. It could + * be confusing if more than one PL/SQL program were writing to + * the same pipe (unless some identifying protocol is established). + * It would certainly be confusing if several OCI programs like + * the one below were reading the same pipe. + * + * Here is the example package: + * + * create or replace package plsdbg as + * -- the procedure put is overloaded for varchar strings + * -- and numbers. extend as needed. + * procedure put(info varchar2); + * procedure put(n number); + * end; + * / + * + * create or replace package body plsdbg as + * + * procedure put(info varchar2) is + * status integer; -- ret. val. required for the + * -- send_message function, not used here + * begin + * dbms_pipe.pack_message(info); + * status := dbms_pipe.send_message('ora$plsql_debug'); + * end; + * + * procedure put(n number) is + * chr varchar2(44); + * status integer; + * begin + * chr := to_char(n); + * dbms_pipe.pack_message(chr); + * status := dbms_pipe.send_message('ora$plsql_debug'); + * end; + * end; + * / + * + * In a PL/SQL program, you call plsdbg to write messages to the + * pipe 'ora$plsql_debug' like this: + * ... + * declare + * my_var integer; + * ... + * begin + * my_var := 42; + * ... -- program procedes until debug output is needed + * plsdbg.put('Hmm, my_var is--'); + * plsdbg.put(my_var); + * -- and the OCI program reading ora$plsql_debug will + * -- print the text message, and the value of my_var + * ... + */ + +#include +#include +#include + +/* These header files must be included for the + type information, and #defined constants. */ +#include +#include +#ifdef __STDC__ +#include +#else +#include +#endif + +/* demo constants and structs */ +#include + +/* Declare the CDA, LDA, and HDA. */ +Cda_Def lda; +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; + +/* Define a string that holds the anonymous PL/SQL block. + The block calls the DBMS_PIPE procedures to get messages + written to the pipe named ora$plsql_debug. */ + +#define GETNEXTITEM "\ +declare\ + s integer;\ + chr varchar2(200);\ +begin\ + chr := '';\ + s := dbms_pipe.receive_message('ora$plsql_debug');\ + if s = 0 then\ + dbms_pipe.unpack_message(chr);\ + end if;\ + :status := s;\ + :retval := chr;\ +end;" + +/* Error-handling function */ +void errrpt(); + + +main(argc, argv) +sword argc; +text **argv; +{ + text username[128]; + ub1 retval[132]; + sword status; + +/* Prepare username/password, from command line or + else use scott/tiger as the default if none given on + the command line. */ + + if (argc > 1) + strncpy((char *) username, (char *) argv[1], + (sword) sizeof (username) - 1); + else + strcpy((char *) username, "SCOTT/TIGER"); + +/* Connect to ORACLE. */ + if (orlon(&lda, (ub1 *)hda, username, -1, + (text *) 0, -1, 0)) + { + printf("Cannot connect as %s. Exiting...\n", username); + exit(1); + } + else + printf("connected\n"); + +/* Open the cursor -- must quit if we cannot. */ + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) + { + printf("Error opening cursor. Exiting...\n"); + exit(1); + } + +/* Parse the anonymous PL/SQL block. */ + if (oparse(&cda, (text *) GETNEXTITEM, + (sb4) -1, 0, (ub4) 2)) + { + errrpt(); + exit(1); + } + +/* Bind the status program variable. */ + if (obndrv(&cda, (text *) ":status", -1, (ub1 *) &status, + (sword) sizeof (sword), SQLT_INT, + -1, (sb2 *) 0, (text *) 0, -1, -1)) + { + errrpt(); + exit(1); + } + +/* Bind the return string (retval). */ + if (obndrv(&cda, (text *) ":retval", -1, (ub1 *) retval, + (sword) sizeof (retval), SQLT_STR, + -1, (sb2 *) 0, (text *) 0, -1, -1)) + { + errrpt(); + exit(1); + } + +/* Loop to look for print messages on the pipe */ + printf("listening...\n"); + for (;;) + { + if (oexec(&cda)) + { + errrpt(); + break; + } + + if (status != 0) + printf("Abnormal pipe status: %d\n\r", status); + else + printf("%s\n\r", retval); + } +} + + +/* Report errors. */ +void errrpt() +{ + sword rv; + text msg[1024]; + +/* use oerhms to get error messages longer than 70 characters */ + rv = oerhms(&lda, cda.rc, msg, (sword) sizeof (msg)); + printf("ORACLE ERROR\n"); + printf("%.*s\n", rv, msg); +} + + + diff --git a/resultcache.sql b/resultcache.sql new file mode 100644 index 0000000..3c584c5 --- /dev/null +++ b/resultcache.sql @@ -0,0 +1,169 @@ +Rem +Rem $Header: resultcache.sql 01-jun-2007.10:01:28 achaudhr Exp $ +Rem +Rem resultcache.sql +Rem +Rem Copyright (c) 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem resultcache.sql - Result Cache +Rem +Rem DESCRIPTION +Rem A demonstration of the Result Cache feature. +Rem +Rem NOTES +Rem Requires the Result Cache to be enabled. +Rem +Rem USAGE +Rem sqlplus /nolog @$ORACLE_HOME/rdbms/demo/resultcache.sql > rc.log +Rem +Rem MODIFIED (MM/DD/YY) +Rem achaudhr 05/31/07 - Split into Basic and Intemediate +Rem achaudhr 04/13/07 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 100 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 1000 +COL PLAN_TABLE_OUTPUT FOR A100 + +--- --------------------- --- +--- Basic Demonstration --- +--- --------------------- --- + +connect scott/tiger + +--- It's generally not possible to tell if the Result Cache was used by simply +--- looking at the output of a query, so we use a function with a side-effect to +--- detect a cache miss. + +--- Function used for detecting a cache miss (i.e. when the cache isn't used) +create or replace function CacheMiss return number DETERMINISTIC is +begin + dbms_output.put_line('CACHE MISS'); + return null; +end; +/ +set serveroutput on + +--- The first execution of a query will be a cache-miss +select /*+ result_cache */ * from dept where CacheMiss is null; + +--- But the second execution answers from the cache +select /*+ result_cache */ * from dept where CacheMiss is null; + +--- A query still sees its own changes (by bypassing the cache) +update dept set dname = rpad(dname, 12, '*'); +select /*+ result_cache */ * from dept where CacheMiss is null; + +--- Committing changes invalidates the result which can subsequently be re-cached +commit; +select /*+ result_cache */ * from dept where CacheMiss is null; +select /*+ result_cache */ * from dept where CacheMiss is null; + +-- A different session also uses the same cached result +connect / as sysdba +set serveroutput on + +alter session set current_schema = scott; + +select /*+ result_cache */ * -- Comments, +from dept -- spaces, +where CACHEMISS IS NULL -- and case don't matter. +/ + +--- Restore the dept table (to original values) +connect scott/tiger +update dept set dname = rtrim(dname, '*'); +commit; + +--- ---------------------------- --- +--- Intermediate Demonstration --- +--- ---------------------------- --- + +connect scott/tiger + +--- Verify that the queries will use the cache +explain plan for +select /*+ result_cache */ * from dept; + +set echo off +@$ORACLE_HOME/rdbms/admin/utlxpls +set echo on + +explain plan for +with e as +( +select /*+ result_cache */ deptno, count(*) emp_count +from emp +group by deptno +) +select dname, emp_count +from dept d, e +where e.deptno = d.deptno; + +set echo off +@$ORACLE_HOME/rdbms/admin/utlxpls +set echo on + +--- Cache each query's result and then scan (i.e. use) the cached result once +select /*+ result_cache */ * from dept; +/ + +with e as +( +select /*+ result_cache */ deptno, count(*) emp_count +from emp +group by deptno +) +select dname, emp_count +from dept d, e +where e.deptno = d.deptno; +/ + +--- Create a caching function and call it from sql +create or replace function EMP_COUNT(dno number) return number + result_cache relies_on (emp) +is + cnt number; +begin + select count(*) into cnt from emp where deptno = dno; + return cnt; +end; +/ + +select dname, EMP_COUNT(deptno) emp_count +from dept where dname = 'SALES'; +/ + +--- Invalidate the first query by modifying dept +update dept set loc = loc; +commit; + +connect / as sysdba + +--- View memory allocation and usage statistics +set serveroutput on +execute dbms_result_cache.memory_report +column name format a62 +column scan_count format 9999 +column statistic format a35 +select name statistic, value from v$result_cache_statistics; +select type, status, scan_count, namespace, name +from v$result_cache_objects +order by type, status, creation_timestamp; + +--- Flush the cache and verify that memory was released +execute dbms_result_cache.flush +execute dbms_result_cache.memory_report + +--- Finally, recreate dependencies (post-flush) +connect scott/tiger +select /*+ result_cache */ distinct loc from emp e, dept d +where e.deptno=d.deptno and CacheMiss is null; + +exit diff --git a/rman2.sh b/rman2.sh new file mode 100644 index 0000000..51c0786 --- /dev/null +++ b/rman2.sh @@ -0,0 +1,97 @@ +#!/bin/sh +# +# $Header: rman2.sh 26-jul-99.09:32:20 mjaeger Exp $ +# +# Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +# +# rman2.sh +# +# NAME +# rman2.sh - duplexed backup of archivelogs +# +# DESCRIPTION +# This shell script dynamically constructs an RMAN backup job and then +# executes it. It will backup the archivelogs, creating 2 copies +# of each archivelog. This is intended for 8.0.x versions of RMAN. With +# 8.1.3, the duplex feature makes this script unnecessary. +# +# NOTES +# Some customization is necessary. +# +# Set "freq" to be the frequency in hours with which you execute this +# script. If your rate of redolog generation is very high, then you +# might need to backup archivelogs every 2 hours. In this case, +# set freq=2. +# +# MODIFIED (MM/DD/YY) +# mjaeger 07/26/99 - bug 808870: OCCS: convert tabs, no long lines +# gpongrac 08/11/98 - Creation +# + +# Initialize connect string variables. Change these as necessary. + +target='target /' # default to "connect internal" +rcvcat='nocatalog' # default to nocatalog mode +#rcvcat='rcvcat rman/rman@rcat_db' + +freq=24 # The number of hours between executions of this script. + # Default to once every 24 hours (once a day). + # Change this as necessary. + +# Get the current time for constructing a fairly unique filename in /tmp: +time=`date '+%H%M%S'` + +# Construct filenames using $time for uniqueness: + +cmdfile=/tmp/rman$time.rcv +msglog=/tmp/rman$time.log + +# Get the current time-of-day in the format: +# YYYY MM DD HH24:MI:SS + +tod=`date '+%Y %m %d %H:%M:%S'` + +# +# CUSTOMIZATION: +# +# The RMAN script below should be customized as appropriate. +# Add "allocate channel" commands as needed so that the desired number of +# tape drives will be utilized. +# +# The format string can be changed if desired, but it must generate +# unique names. %u is usually good enough. +# +# The RMAN invocation should be customized with the target database +# SYS password and TNS alias. If you use a recovery catalog, replace +# "nocatalog" with "rcvcat", and follow it with the connect string +# for the recovery catalog. +# +# The "like" clause can be uncommented and edited to have RMAN backup +# only archivelogs whose filenames are LIKE the specified pattern. +# This can be used to backup only those archivelogs in a particular +# log_archive_dest. +# + +cat << EOF > $cmdfile +run { +allocate channel c1 type 'sbt_tape'; +allocate channel c2 type 'sbt_tape'; +# allocate additional channels as necessary +backup archivelog + from time="to_date('$tod', 'YYYY MM DD HH24:MI:SS')-$freq/24" + until time="to_date('$tod', 'YYYY MM DD HH24:MI:SS')" + # like 'primary_archivelog_destination_mount_point/%' + format='%u'; +backup archivelog + from time="to_date('$tod', 'YYYY MM DD HH24:MI:SS')-$freq/24" + until time="to_date('$tod', 'YYYY MM DD HH24:MI:SS')" + # like 'primary_archivelog_destination_mount_point/%' + format='%u' + delete input; +} +EOF + +rman $target $rcvcat cmdfile $cmdfile msglog $msglog + +exit # rman2.sh + diff --git a/ruldemo.sql b/ruldemo.sql new file mode 100644 index 0000000..b11bbbe --- /dev/null +++ b/ruldemo.sql @@ -0,0 +1,1034 @@ +Rem +Rem $Header: ruldemo.sql 14-dec-2006.09:36:47 ayalaman Exp $ +Rem +Rem ruldemo.sql +Rem +Rem Copyright (c) 2004, 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem ruldemo.sql - Rules Manager demo script +Rem +Rem DESCRIPTION +Rem This script demonstrates the use of Rules Manager in +Rem a few configurations. See the Application Developer's +Rem Guide - Rules Manager and Expression Filter for +Rem additional information. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ayalaman 12/14/06 - add demo for collection events +Rem ayalaman 11/15/04 - XPath expression example and rule descriptions +Rem ayalaman 11/02/04 - replace homeland security with law enforcement +Rem ayalaman 10/07/04 - ayalaman_bug-3922526 +Rem ayalaman 09/29/04 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +connect / as sysdba; +set serveroutput on; +drop user ruldemo cascade; +create user ruldemo identified by ruldemo; +grant connect, resource to ruldemo; +grant execute on dbms_lock to ruldemo; +grant create view to ruldemo; + +connect ruldemo/ruldemo; +set echo on; +set pagesize 150; +column mesg format a78; +column attime format a30; +column rlm$rulecond format a95; +column rlm$ruleid format a5; + +/***************************************************************** + The tests in this file are organized as follows: + I. Application demonstrating the various steps in a Rules + Manager application. + II. Application demonstrating the use of Table aliases and + DML (Insert) Events for rule management. + III. Application demonstrating the use of ADD_EVENT API and + Rule class results view + IV. Application demonstrating the use of collection events +******************************************************************/ +set linesize 110; +--- +--- I. Application demostrating the various steps in a Rules +--- Manager application. +--- +--- The following script uses Law Enforcement application to demonstrate +--- the use of Rules Manager. In this application, rules are defined to +--- raise security alerts, place a person on the watch list, etc based +--- on certain criteria. For this purpose, some real-world events such as +--- Bank Transactions, Transportation and Field Reports are used +--- to describe the criteria. +--- +create table messagequeue (attime timestamp, mesg varchar2(4000)); + +--- +--- 1. Create the basic types that represent the primitive event +--- structures +--- +create or replace type BankTransaction as object + (subjectId NUMBER, --- refer to entity such as personnel + --- could be SSN + tranType VARCHAR2(30), --- DEPOSIT / TRANSFER / WITHDRAW + amount NUMBER, --- + fundFrom VARCHAR2(30)); --- location from which it is transfered +/ + +create or replace type Transportation as object + (subjectId NUMBER, + vesselType VARCHAR2(30), --- TRUCK / CAR / PLANE / TRAIN + locFrom VARCHAR2(30), --- starting location + locTo VARCHAR2(30), --- ending location + startDate DATE, --- start date + endDate DATE); --- end date of +/ + +create or replace type FieldReport as object + (subjectId NUMBER, + rptType VARCHAR2(30), --- Tel call / Meeting / Bg Check + whoWith NUMBER, --- identifier of the person the subject + --- is in touch with + rptOrg VARCHAR2(30), --- Organization reporting it + rptReg VARCHAR2(30), --- Region + rptBody sys.XMLType); --- the actual report +/ + +--- +--- 2. Create a composite event type that consists of these basic types. +--- +create or replace type LawEnforcement as object + (bank BankTransaction, + transport Transportation, + fldrpt FieldReport); +/ + +--- +--- 3. Create a repository for the rules defined on the composite event +--- structure +--- +BEGIN + DBMS_RLMGR.CREATE_RULE_CLASS( + rule_class => 'LawEnforcementRC', + event_struct => 'LawEnforcement', + action_cbk => 'LawEnforcementCBK', + actprf_spec => 'actionType VARCHAR2(40), actionParam VARCHAR2(100)', + rslt_viewnm => 'MatchedCriteria', + rlcls_prop => ''); +END; +/ + +--- The above steps create a relational table, LawEnforcementRC, which acts +--- as the repository for the rules in this application. This table has +--- a set of pre-defined columns to store the Rule identifiers, Rule +--- conditions and the descriptions. In addition to these columns, this +--- rule class table is defined with two columns, actionType and +--- actionParam, as specified through the actpref_spec argument. These +--- columns capture the type of action that should be carried for each +--- rule. +desc LawEnforcementRC; + +--- The above steps also creates the skeleton for an action callback +--- procedure with the specified name. + +select text from user_source where name = 'LAWENFORCEMENTCBK' order by line; + +--- +--- 4. Implement the callback procedure to perform appropriate action +--- for each matching rule, based on the event instances that +--- matched the rule and the action preferences associated with +--- the rule. +--- +CREATE OR REPLACE PROCEDURE LAWENFORCEMENTCBK ( + bank banktransaction, + transport transportation, + fldrpt fieldreport, + rlm$rule LawEnforcementRC%ROWTYPE) IS + mesg VARCHAR2(4000); + msgl VARCHAR2(100); +begin + msgl := 'Rule '||rlm$rule.rlm$ruleid||' matched following primitive events'; + dbms_output.put_line(msgl); + mesg := msgl||chr(10); + if (bank is not null) then + msgl := '->Bank Transaction by subject ('||bank.subjectId||') of type ['||bank.tranType||']'; + dbms_output.put_line(msgl); + mesg := mesg||msgl||chr(10); + end if; + if (transport is not null) then + msgl := + '->Transportation by subject('||transport.subjectId||') use vessel ['||transport.vesselType||']'; + dbms_output.put_line(msgl); + mesg := mesg||msgl||chr(10); + end if; + if (fldrpt is not null) then + msgl := + '->Field report refer to('||fldrpt.subjectId||' and '||fldrpt.whowith||')'; + dbms_output.put_line(msgl); + mesg := mesg||msgl||chr(10); + end if; + + msgl := '=>Recommended Action : Action Type ['||rlm$rule.actionType|| + '] Action Parameter ['||rlm$rule.actionParam||']'; + + dbms_output.put_line(msgl||chr(10)); + mesg := mesg||msgl||chr(10); + insert into messagequeue values (systimestamp, mesg); +end; +/ + +show errors; + +--- +--- 5. The rules defined in the rule class can make use of user-defined +--- functions in the database schema. The following commands create +--- some dummy functions that are later used in the rule conditions. +--- + +-- +-- For the value of the region passed in, query the restricted +-- areas table and return 1 if the current region is a restricted +-- area. +CREATE OR REPLACE FUNCTION IsRestrictedArea(region VARCHAR2) + RETURN NUMBER IS +BEGIN + -- User can expand this function and implement a logic that + -- relies on other relational tables. + RETURN 1; +END; +/ + +-- +-- Check if the subject chosen is on the watch list +-- +CREATE OR REPLACE FUNCTION OnWatchList(subject NUMBER) + RETURN NUMBER IS +BEGIN + -- User can expand this function and implement a logic that + -- relies on other relational tables. + RETURN 1; +END; +/ + +-- +-- Verify if two parties are associates. Return 1 is the two +-- subjects passed in are associates according to the registry. +-- +CREATE OR REPLACE FUNCTION AreAssociates(subjectA NUMBER, + subjectB NUMBER) + RETURN NUMBER IS +BEGIN + -- User can expand this function and implement a logic that + -- relies on other relational tables. + RETURN 1; +END; +/ + +-- Add all three user-defined functions to composite event +-- "LawEnforcement", so that these functions can be used +-- in the corresponding rule conditions. +EXEC DBMS_RLMGR.ADD_FUNCTIONS('LawEnforcement', 'OnWatchList'); +EXEC DBMS_RLMGR.ADD_FUNCTIONS('LawEnforcement', 'IsRestrictedArea'); +EXEC DBMS_RLMGR.ADD_FUNCTIONS('LawEnforcement', 'AreAssociates'); + +--- +--- 6. Define the rules that suggest some actions +--- + +--- Rule : Add a person to the NYPD watch list if he recieves a money +--- transfer for more than 10000 dollars and if he rents a truck, +--- one-way to one of the restricted areas. Note that the join +--- predicate is specified at the rule class elevel. --- +INSERT INTO LawEnforcementRC (rlm$ruleid, actionType, actionParam, rlm$rulecond, + rlm$ruledesc) +VALUES ('1', 'ADD2WATCHLIST','NYPD', + ' + + + tranType = ''TRANSFER'' AND amount > 10000 AND fundFrom != ''usa'' + + + vesselType = ''TRUCK'' AND locFrom != locTo AND IsRestrictedArea(locTo)=1 + + + ', +'Add a person to the NYPD watch list if he recieves a money transfer +for more than 10000 dollars and if he rents a truck one-way to one +of the restricted areas'); + +--- +--- Rule : Add a person to the NYPD watch list if 2 out of the following 3 +--- conditions are met : +--- * The person get a money transfer for over 10000 dollars from outside USA +--- * He rented a truck, one-way, into one of the restricted areas and +--- * He had a phone conversation with a person alreadt on the watch list. +--- +--- The following rule demonstrates the use of ANY where a rule condition is +--- considered true is m out of n events are detected. --- +INSERT INTO LawEnforcementRC (rlm$ruleid, actionType, actionParam, rlm$rulecond, + rlm$ruledesc) +VALUES ('2', 'ADD2WATCHLIST','NYPD', + ' + + + tranType = ''TRANSFER'' AND amount > 10000 AND fundFrom != ''usa'' + + + vesselType = ''TRUCK'' AND locFrom != locTo AND IsRestrictedArea(locTo)=1 + + + rptType = ''TELCALL'' AND OnWatchList(whoWith) = 1 + + + ', +'Add a person to the NYPD watch list if 2 out of the 3 specified +conditions are met'); + +--- +--- Rule : Start a background check on a person if he receives a large +--- sum of money from outside USA, he rents a truck one-way into one of +--- the restricted areas and there is no field report with his background +--- information. +--- +--- The following rule demonstrates the use of negation where a rule condition +--- is considered true if some of the specified events are detected and the +--- other events are not detected --- +INSERT INTO LawEnforcementRC (rlm$ruleid, actionType, actionParam, rlm$rulecond, + rlm$ruledesc) +VALUES ('3','STARTBACKGROUNDCHECK','RENTAL_DESTINATION', + ' + + + tranType = ''TRANSFER'' AND amount > 10000 AND fundFrom != ''USA'' + + + vesselType=''TRUCK'' AND locFrom != locTo AND IsRestrictedArea(locTo)=1 + + + + rptType = ''BG Check'' + + + + ', +'Start a background check on a person if he receives a large +sum of money from outside USA, he rents a truck one-way into +one of restricted areas and there is no field report with his +background information'); + +--- Rule : If a subject received over 10000 dollars from outside US, +--- he rented a truck for one direction into a restricted area and a +--- field report saying that the subject was never arrested before was +--- not submitted within "certain" (0.001 fraction of a day; could be +--- days. But seconds are used to demonstrate the use of deadline) +--- period, add the destination of the truck to high-risk areas --- +--- +--- This rule demonstrates the use of Negation with a deadline. +--- +INSERT INTO LawEnforcementRC (rlm$ruleid, actionType, actionParam, rlm$rulecond, + rlm$ruledesc) +VALUES ('4','ADD2HIGH_RISK_AREA','RENTAL_DESTINATION', + ' + + + tranType = ''TRANSFER'' AND amount > 10000 AND fundFrom != ''usa'' + + + vesselType = ''TRUCK'' AND locFrom != locTo AND IsRestrictedArea(locTo)=1 + + + + rptType = ''BACKGROUNDCHECK'' and + extract(rptBody, ''/history/arrests[@number=0]'') is not null + + + + ', +'If a subject received over 10000 dollars from outside US, +he rented a truck for one direction into a restricted area and a +field report saying that the subject was never arrested before was +not submitted within "certain" period, add the destination of the +truck to high-risk areas'); + +commit; + +--- Browse the rules --- +select rlm$ruleid, rlm$rulecond from LawEnforcementRC order by 1; + +--- +--- 7. Process the rules for the primitive events +--- +set serveroutput on size 10000; + +BEGIN + dbms_rlmgr.process_rules ( + rule_class => 'LawEnforcementRC', + event_inst => + sys.anydata.convertobject( + fieldreport(123302122, 'TELCALL',123302123, 'NSA', 'NE', null))); +END; +/ + +--- The following event partially matches some of the rules defined above --- +BEGIN + dbms_rlmgr.process_rules ( + rule_class => 'LawEnforcementRC', + event_inst => + sys.anydata.convertobject( + banktransaction(123302122, 'TRANSFER', 100000, 'USSR'))); +END; +/ + +--- This event in combination with the other event evaluates some of the +--- rules to true and thus calls the action call-back procedure. +BEGIN + dbms_rlmgr.process_rules ( + rule_class => 'LawEnforcementRC', + event_inst => + sys.anydata.convertobject( + transportation(123302122, 'TRUCK', 'WIS', 'MD', + sysdate, sysdate + 7))); +END; +/ + +select mesg from messagequeue order by attime; + +truncate table messagequeue; + +--- Let us sleep past the deadline for rule 5. The scheduler process picks up +--- this rule and executes its action. The result is a new message in the +--- message queue. +exec dbms_lock.sleep(180); + +--- The action is executed for the rule 5 after the deadline time is elapsed. +select mesg from messagequeue; + +exec dbms_rlmgr.drop_rule_class('LawEnforcementRC'); +exec dbms_rlmgr.drop_event_struct('LawEnforcement'); + +drop type LawEnforcement; + +exec dbms_rlmgr.drop_event_struct('BankTransaction'); +drop type BankTransaction; + +exec dbms_rlmgr.drop_event_struct('Transportation'); +drop type Transportation; + +exec dbms_rlmgr.drop_event_struct('FieldReport'); +drop type fieldreport; + +/*************************************************************************/ +--- +--- II. Application demonstrating the use of Table aliases and +--- DML (Insert) Events for rule management. +--- +--- Order Management application to demonstrate the use of Table +--- Aliases and DMLEVENTS with rules. +-- +column attime format a30; +column mesg format a50; +set echo on; +set pagesize 150; +set linesize 150; + +--- +--- The following script uses Order Management application to demonstrate +--- the use of Rules Manager for the (event) data that is stored in +--- Relational tables. +--- +--- +--- Let us consider 3 relational tables that store the information +--- about the Purchase Orders, Shipping information, and Payment +--- information. +--- +create table PurchaseOrders + (orderId NUMBER, + custId NUMBER, + itemId NUMBER, + itemType VARCHAR2(30), + quantity NUMBER, + shipBy DATE); + +create table ShipmentInfo + (orderId NUMBER, + destState VARCHAR2(2), + address VARCHAR2(50), + shipTime DATE, + shipType VARCHAR2(10)); + +create table PaymentInfo + (orderId NUMBER, + payType VARCHAR2(10), -- Credit Card / Check -- + amountPaid NUMBER, + pymtTime DATE, + billState VARCHAR2(2)); + +--- +--- 1. Create the event structure. +--- The event structures that refer to existing table using +--- table alias constructs cannot be created from object types. +--- Instead, such event structures should be modeled as +--- Expression Filter attribute sets. +--- +begin + DBMS_RLMGR.CREATE_EVENT_STRUCT (event_struct => 'OrderMgmt'); + + DBMS_RLMGR.ADD_ELEMENTARY_ATTRIBUTE( + event_struct => 'OrderMgmt', + attr_name => 'po', + tab_alias => RLM$TABLE_ALIAS('PurchaseOrders')); + + DBMS_RLMGR.ADD_ELEMENTARY_ATTRIBUTE( + event_struct => 'OrderMgmt', + attr_name => 'si', + tab_alias => RLM$TABLE_ALIAS('ShipmentInfo')); + + DBMS_RLMGR.ADD_ELEMENTARY_ATTRIBUTE( + event_struct => 'OrderMgmt', + attr_name => 'py', + tab_alias => RLM$TABLE_ALIAS('PaymentInfo')); +end; +/ + +--- +--- 2. Create the rule class (repository for rules) for the +--- OrderMgmt composite event. Also specify the DMLEVENTS property +--- to process the rules for each Inserted row into the (event) data +--- tabled. +--- +BEGIN + DBMS_RLMGR.CREATE_RULE_CLASS ( + rule_class => 'OrderMgmtRC', + event_struct => 'OrderMgmt', + action_cbk => 'OrderMgmtCBK', + actprf_spec => 'actionType VARCHAR2(40), actionParam VARCHAR2(100)', + rslt_viewnm => 'MatchingOrders', + rlcls_prop => ''); +END; +/ + +desc OrderMgmtCBK; + +--- +--- 3. Implement the action callback procedure to +--- +CREATE OR REPLACE PROCEDURE OrderMgmtCBK ( + po ROWID, -- rowid from the PurchaseOrders table + si ROWID, -- rowid from the ShipmentInfo table + py ROWID, -- rowid from the PaymentInfo table + rlm$rule OrderMgmtRC%ROWTYPE) IS + ordId NUMBER; + msg VARCHAR2(2000); +begin + -- the rowid arguments represent the primitive events that are + -- rows inserted into the corresponding tables. Use the rowids + -- to fetch necessary values. + if (po is not null) then + select orderId into ordId from PurchaseOrders where rowid = po; + elsif (si is not null) then + select orderId into ordId from ShipmentInfo where rowid = si; + elsif (py is not null) then + select orderId into ordId from PaymentInfo where rowid = py; + end if; + + msg := 'Order number: '||ordId||' Matched rule: ' + ||rlm$rule.rlm$ruleid||chr(10)|| + '-> Recommended Action : '||chr(10)|| + ' Action Type ['||rlm$rule.actionType|| + ']'||chr(10)||' Action Parameter ['|| + rlm$rule.actionParam||']'; + + dbms_output.put_line (msg||chr(10)); +end; +/ + +--- +--- 4. Add User-Defined functions that may be useful in rule +--- conditions. +--- +create or replace function getCustType(custId number) + return VARCHAR2 is +begin + -- the actual function implementation can rely on other + -- relational tables to derive the customer type information + return 'GOLD'; +end; +/ + +exec DBMS_RLMGR.ADD_FUNCTIONS('OrderMgmt','getCustType'); + +--- +--- 4. Add some rules +--- +--- Rule : If the order is for more than 100 routers and the +--- payment is received as a check, contact the customer +--- to update on the status of the order. +--- Note that the join predicate across event types is specified +--- at the rule class level +--- +INSERT INTO OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$rulecond) +VALUES (1, 'CALL_CUSTOMER','UPDATE_ORDER_STATUS', + ' + + + itemType = ''ROUTER'' and quantity > 100 + + + payType = ''CHECK'' + + + '); + +--- Rule : If the order is placed by a GOLD customer, +--- and the items are shipped before receiving a payment, +--- adjust the customer's credit. +INSERT INTO OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$rulecond) +VALUES (2, 'UPDATE_CUST_PROFILE', 'DECR_AVAILABLE_CREDIT', + ' + + getCustType(custid) = ''GOLD'' + + + + + + '); + + +--- Rule : If the order is place by a Gold customer and the item +--- item is shipped within 1 day prior to the shipby date, +--- increment the Quality of service statistics. +--- +INSERT INTO OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$rulecond) +VALUES (3, 'UPDATE_STATISTICS', 'INCREMENT QOS', + ' + + getCustType(custid) = ''GOLD'' + + + '); + +commit; + +set serveroutput on; + +insert into PurchaseOrders (orderId, custId, itemId, itemType, + quantity, shipBy) values +(1, 123, 234, 'ROUTER', 120, '01-OCT-2004'); + +insert into ShipmentInfo (orderId, deststate, address, shipTime, + shipType) values +(1, 'CA','1 Main street, San Jose','29-SEP-2004','1 Day Air'); + +insert into PaymentInfo (orderId, paytype, amountpaid, pymttime, + billstate) values +(1, 'CHECK', 100000, '30-SEP-2004', 'CA'); + +commit; + +--- +--- III. Application demonstrating the use of ADD_EVENT API and +--- Rule class results view +--- +--- Now let us consider a similar application without the use of +--- DMLEVENTS. This implies that the user explicitly invokes the +--- rules manager APIs to process the rules for some data stored +--- in relational tables. +--- +--- We can share the same event structure for another rule class. +--- +BEGIN + DBMS_RLMGR.CREATE_RULE_CLASS ( + rule_class => 'OrderMgmtRC2', + event_struct => 'OrderMgmt', + action_cbk => 'OrderMgmtCBK2', + actprf_spec => 'actionType VARCHAR2(40), actionParam VARCHAR2(100)', + rslt_viewnm => 'MatchingOrders2', + rlcls_prop => ''); +END; +/ + +--- Implement the action callback procedure -- +CREATE OR REPLACE PROCEDURE OrderMgmtCBK2 ( + po ROWID, -- rowid from the PurchaseOrders table + si ROWID, -- rowid from the ShipmentInfo table + py ROWID, -- rowid from the PaymentInfo table + rlm$rule OrderMgmtRC2%ROWTYPE) IS + ordId NUMBER; + msg VARCHAR2(2000); +begin + -- the rowid argument represent the primitive events that are + -- rows inseted into the corresponding tables. Use the rowids + -- to fetch necessary values. + if (po is not null) then + select orderId into ordId from PurchaseOrders where rowid = po; + elsif (si is not null) then + select orderId into ordId from ShipmentInfo where rowid = si; + elsif (py is not null) then + select orderId into ordId from PaymentInfo where rowid = py; + end if; + + msg := 'Order number: '||ordId||' Matched rule: ' + ||rlm$rule.rlm$ruleid||chr(10)|| + '-> Recommended Action : '||chr(10)|| + ' Action Type ['||rlm$rule.actionType|| + ']'||chr(10)||' Action Parameter ['|| + rlm$rule.actionParam||']'; + + dbms_output.put_line (msg||chr(10)); +end; +/ + +--- insert the same set of rules into the new rule class. +insert into OrderMgmtRC2 (select * from OrderMgmtRC); + +delete from OrderMgmtRC; + +commit; + +--- Since DML events are not configured for this rule class, +--- the application has to explicitly process rules for the +--- rows in the data table. The rowids of the rows are used +--- as references to the events. + +var datarid varchar2(40); + + +insert into PurchaseOrders (orderId, custId, itemId, itemType, + quantity, shipBy) values +(2, 123, 234, 'ROUTER', 120, '01-OCT-2004') +returning rowid into :datarid; + +BEGIN + dbms_rlmgr.process_rules (rule_class => 'OrderMgmtRC2', + event_type => 'PurchaseOrders', + event_inst => :datarid); +END; +/ + +insert into ShipmentInfo (orderId, deststate, address, shipTime, + shipType) values +(2, 'CA','1 Main street, San Jose','29-SEP-2004','1 Day Air') +returning rowid into :datarid; + +BEGIN + dbms_rlmgr.process_rules (rule_class => 'OrderMgmtRC2', + event_type => 'ShipmentInfo', + event_inst => :datarid); +END; +/ + +insert into PaymentInfo (orderId, paytype, amountpaid, pymttime, + billstate) values +(2, 'CHECK', 100000, '30-SEP-2004', 'CA') +returning rowid into :datarid; + +BEGIN + dbms_rlmgr.process_rules (rule_class => 'OrderMgmtRC2', + event_type => 'PaymentInfo', + event_inst => :datarid); +END; +/ + +-- +-- Now try the session oriented evaluation of rules where the +-- results from matching rules are available in the results view +-- to be queried. +-- +set linesize 80; +desc MatchingOrders2; + +select count(*) from MatchingOrders2; + +insert into PurchaseOrders (orderId, custId, itemId, itemType, + quantity, shipBy) values +(3, 123, 234, 'ROUTER', 120, '01-OCT-2004') +returning rowid into :datarid; + +--- Use ADD_EVENT API in the place of PROCESS_RULES --- +BEGIN + dbms_rlmgr.add_event (rule_class => 'OrderMgmtRC2', + event_type => 'PurchaseOrders', + event_inst => :datarid); +END; +/ + +insert into ShipmentInfo (orderId, deststate, address, shipTime, + shipType) values +(3, 'CA','1 Main street, San Jose','29-SEP-2004','1 Day Air') +returning rowid into :datarid; + +BEGIN + dbms_rlmgr.add_event (rule_class => 'OrderMgmtRC2', + event_type => 'ShipmentInfo', + event_inst => :datarid); +END; +/ + +insert into PaymentInfo (orderId, paytype, amountpaid, pymttime, + billstate) values +(3, 'CHECK', 100000, '30-SEP-2004', 'CA') +returning rowid into :datarid; + +BEGIN + dbms_rlmgr.add_event (rule_class => 'OrderMgmtRC2', + event_type => 'PaymentInfo', + event_inst => :datarid); +END; +/ + +--- Since the event structure is configired with table aliases, +--- the events are represented using the rowids from the +--- corresponding tables. +column rlm$ruleid format a7; +column actiontype format a25; +column actionparam format a25; +select po, si, py, rlm$ruleid, actionType, actionParam from MatchingOrders2 order by 4; + +select + (select orderId from purchaseOrders where rowid = po) as OrderId, + rlm$ruleid, actionType, actionParam from MatchingOrders2 order by 2; + +exec dbms_rlmgr.drop_rule_class('OrderMgmtRC2'); +exec dbms_rlmgr.drop_rule_class('OrderMgmtRC'); +exec dbms_rlmgr.drop_event_struct('OrderMgmt'); + +drop table PurchaseOrders; +drop table ShipmentInfo; +drop table PaymentInfo; +drop table messagequeue; + +-- +--- IV. Use of Collection events in an Order Management Application +-- + +-- +-- 1. Create the object types for the event structure. +-- +create or replace type PurchaseOrder as object + ( orderid number, + customerid number, + itemid number, + itemcount number, + amount number, + exptddate date); +/ + +create or replace type ShipItem as object + ( itemid number, + itemtype varchar2(30), + orderid number, + truckid number); +/ + +create or replace type TruckAtDock as object + ( truckid number, + loadid date, + status varchar2(30), + capacity number); +/ + +create or replace type OrderMgmt as object + ( + porder PurchaseOrder, + sitem ShipItem, + truck TruckAtDock + ); +/ + +-- +-- 2. Create a rule class for the OrderMgmt composite event and enable +-- collection for PurchaseOrder and ShipItem events. +-- +BEGIN + DBMS_RLMGR.CREATE_RULE_CLASS( + rule_class => 'OrderMgmtRC', + event_struct => 'OrderMgmt', + action_cbk => 'OrderMgmtCBK', + actprf_spec => 'actionType VARCHAR2(40), actionParam VARCHAR2(100), + poAggrRet VARCHAR2(20) default null', + rslt_viewnm => 'MatchedScenarios', + rlcls_prop => ' + + + '); +END; +/ + +desc OrderMgmtCBK; + +-- +-- 3. Implement the action callback procedure +-- + +create or replace procedure "ORDERMGMTCBK" ( + PORDER PURCHASEORDER, + PO_EVTID ROWID, + SITEM SHIPITEM, + SI_EVTID ROWID, + TRUCK TRUCKATDOCK, + rlm$rule ORDERMGMTRC%ROWTYPE) is + mesg VARCHAR2(100); + aggrval VARCHAR2(100); +begin + mesg := ' Rule "'||rlm$rule.rlm$ruleid|| + '" matched '|| + case when porder.orderid is not null then 'Purchase Order '||porder.orderid + when porder.customerid is not null then 'Customer '||porder.customerid + when sitem.truckid is not null then '||Truck '||sitem.truckid + end; + + if (porder is not null and rlm$rule.poAggrRet is not null) then + aggrval := dbms_rlmgr.get_aggregate_value ('OrderMgmtRC', po_evtid, + rlm$rule.poAggrRet); + aggrval := ' with '||rlm$rule.poAggrRet||' equal to '||aggrval; + end if; + dbms_output.put_line (mesg||aggrval); +end; +/ + +-- +-- 4. User defined functions for the rules +-- +create or replace function CustomerType (custId int) return VARCHAR2 is +begin + return 'GOLD'; +end; +/ + +exec dbms_rlmgr.add_functions('OrderMgmt','CustomerType'); + +-- +-- 5. Add rules +-- +insert into OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$ruledesc, + rlm$rulecond) values +('High priority Order redirect', 'REDIRECT','HIGH_PRIORITY_QUEUE', + 'Route the order to a high priority queue if it is large order from a Gold Customer', +' + CustomerType(customerid) = ''GOLD'' and amount > 10000 +'); + +insert into OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$ruledesc, + rlm$rulecond) values +('Delayed Order redirect', 'REDIRECT','HIGH_PRIORITY_QUEUE', + 'Route the order to a high priority queue if there is a potential for it to get delayed', +' + + CustomerType(customerid) = ''GOLD'' + + + + +'); + +insert into OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$ruledesc, + rlm$rulecond) values +('Large number of orders promo', 'PROMOTION','ELITE_STATUS', + 'Offer an elite status to a customer if he submited a large number of orders, each with a minimum of 10000 dollars', + ' + + amount > 10000 + +'); + + +insert into OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$ruledesc, + rlm$rulecond) values +('Expanding customer', 'PROMOTION', 'LARGE_ORDER', +'Offer a promotion for ordering in bulk if the average size of the last 10 orders is over 20000 dollars', +' + +'); + +insert into OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$ruledesc, + rlm$rulecond) values +('Promo on Total size of orders in 10 days', 'PROMOTION','ELITE_STATUS', + 'Offer an elite status to a customer if he submited a large number of orders, each with a minimum of 1000 dollars, in a 30 day period', +' + + amount > 1000 + +'); + +insert into OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$ruledesc, + rlm$rulecond) values +('Completed order', 'UPDATE_ORDER_STATUS','COMPLETE', +'Compare the number of items ordered and the items shipped to mark the order complete', +' + + + + itemtype != ''Reusable Container'' + + +'); + +insert into OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$ruledesc, + rlm$rulecond) values +('Ready to ship', 'READY_TO_SHIP', 'LOADED_TRUCK', +'Signal readiness to ship when the truck is at least 90% full', +' + + status = ''Loading'' + + itemtype = ''Reusable Container'' + + +'); + +commit; + +-- +-- 6. Add events +-- +set serveroutput on; +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(100, 300, 51, 8, 11000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(101, 300, 52, 8, 111000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(102, 300, 52, 8, 11000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(103, 300, 54, 8, 111000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(104, 300, 55, 8, 11000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(105, 300, 56, 8, 111000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(106, 300, 56, 8, 11000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(107, 300, 57, 8, 111000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(108, 300, 58, 8, 11000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(109, 300, 59, 8, 111000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(110, 300, 59, 8, 11000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(111, 300, 59, 8, 111000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(112, 300, 59, 8, 11000, '25-OCT-2006'))); + +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(TruckAtDock(900, sysdate, 'Loading', 6))); + +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(shipitem(401, 'Reusable Container', 100, 900))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(shipitem(402, 'Reusable Container', 101, 900))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(shipitem(403, 'Reusable Container', 102, 900))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(shipitem(404, 'Reusable Container', 103, 900))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(shipitem(405, 'Reusable Container', 104, 900))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(shipitem(406, 'Reusable Container', 105, 900))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(shipitem(407, 'Reusable Container', 107, 900))); + +connect / as sysdba; +drop user ruldemo cascade; + +exit; diff --git a/sadv91.sql b/sadv91.sql new file mode 100644 index 0000000..ab02f14 --- /dev/null +++ b/sadv91.sql @@ -0,0 +1,246 @@ +Rem +Rem $Header: sadv91.sql 07-jun-2004.13:50:01 lburgess Exp $ +Rem +Rem sadv91.sql +Rem +Rem Copyright (c) 2000, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem sadv91.sql - Summary Advisor demo for Oracle 9i +Rem +Rem DESCRIPTION +Rem This file demonstrates the use of the Oracle 9i Summary Advisor +Rem API calls +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem lburgess 06/07/04 - add order by clause +Rem btao 03/02/01 - Change Interfaces +Rem btao 10/31/00 - Created +Rem +Rem ==================================================================== +Rem Setup for demos +Rem ==================================================================== +connect system/manager +grant select on mview_recommendations to sh; +grant select on mview_workload to sh; +grant select on mview_filter to sh; +grant alter system to sh; +disconnect + +Rem ******************************************************************** +Rem * Demo 1: Materialized View Recommendation With User Workload * +Rem ******************************************************************** +Rem ==================================================================== +Rem Step 1. Define user workload table and add artificial workload +Rem queries, and gather stats for schema objects +Rem ==================================================================== +connect sh/sh +@sadvuwk.sql +insert into advisor_user_workload values +( + 'select sum(s.quantity_sold) + from sales s, products p + where s.prod_id = p.prod_id and + p.prod_category = ''Boys'' + group by p.prod_category + ', + 'SH', 'app1', 10, NULL, 5, NULL, NULL, NULL, NULL +) +/ +insert into advisor_user_workload values +( + 'select sum(s.amount_sold) + from sales s, products p + where s.prod_id = p.prod_id and + p.prod_category = ''Girls'' + group by p.prod_category + ', + 'SH', 'app1', 10, NULL, 6, NULL, NULL, NULL, NULL +) +/ +insert into advisor_user_workload values +( + 'select sum(quantity_sold) + from sales s, products p + where s.prod_id = p.prod_id and + p.prod_category = ''Men'' + group by p.prod_category + ', + 'SH', 'app1', 11, NULL, 3, NULL, NULL, NULL, NULL +) +/ +insert into advisor_user_workload values +( + 'select sum(quantity_sold) + from sales s, products p + where s.prod_id = p.prod_id and + p.prod_category in (''Women'', ''Men'') + group by p.prod_category + ', + 'SH', 'app1', 1, NULL, 8, NULL, NULL, NULL, NULL +) +/ +execute dbms_stats.gather_schema_stats('SH', 1); + +Rem ==================================================================== +Rem Step 2. Create a new identifier to identify a new collection in the +Rem internal repository and load the user-defined workload into Rem the workload collection +Rem ==================================================================== +variable workload_id number; +execute dbms_olap.create_id(:workload_id); +execute dbms_olap.load_workload_user(:workload_id,- + dbms_olap.workload_new,- + dbms_olap.filter_none, 'SH', 'ADVISOR_USER_WORKLOAD'); +select count(*) from system.mview_workload + where workloadid = :workload_id; + +Rem ==================================================================== +Rem Step 3. Create a new identifier to identify a new filter object. Add +Rem two filter items such that the filter can filter out +Rem workload queries with priority >= 5 and frequency <= 10 +Rem ==================================================================== +variable filter_id number; +execute dbms_olap.create_id(:filter_id); +execute dbms_olap.add_filter_item(:filter_id, 'PRIORITY',- + NULL, 5, NULL, NULL, NULL); +execute dbms_olap.add_filter_item(:filter_id, 'FREQUENCY',- + NULL, NULL, 10, NULL, NULL); +select count(*) from system.mview_filter + where filterid = :filter_id; + +Rem ==================================================================== +Rem Step 4. Recommend materialized views with part of the previous +Rem workload collection that satisfy the filter conditions. +Rem Create a new identifier to identify the recommendation +Rem output. +Rem ==================================================================== +variable run_id number; +execute dbms_olap.create_id(:run_id); +execute dbms_olap.recommend_mview_strategy(:run_id, :workload_id,- + :filter_id, 100000, 100, NULL, NULL); +select count(*) from system.mview_recommendations; + +Rem ==================================================================== +Rem Step 5. Generate HTML reports on the output +Rem Notes: The user must have the priviledge to grant directory +Rem access permission. The commented out example +Rem only applies to UNIX systems. Your specific +Rem operating system may require different path name +Rem specification. +Rem ==================================================================== +Rem execute dbms_java.grant_permission('SH',- +Rem 'java.io.FilePermission', '/tmp', 'read,write'); +Rem +Rem execute dbms_olap.generate_mview_report('/tmp/output1.html',- +Rem :run_id, dbms_olap.rpt_recommendation); + +Rem ==================================================================== +Rem Step 6. Cleanup current output, filter and workload collection +Rem from the internal repository, truncate the user workload +Rem table for new user workloads. +Rem ==================================================================== +execute dbms_olap.purge_results(:run_id); +execute dbms_olap.purge_filter(:filter_id); +execute dbms_olap.purge_workload(:workload_id); +select count(*) from system.mview_workload + where workloadid = :workload_id; +truncate table advisor_user_workload; + +drop table advisor_user_workload; +disconnect + +Rem ******************************************************************** +Rem * Demo 2: Materialized View Recommendation With SQL Cache * +Rem ******************************************************************** +connect sh/sh + +Rem ==================================================================== +Rem Step 1. Clear SQL cache and run some applications or some SQL +Rem queries, so that the Oracle SQL cache is populated with +Rem target queries. +Rem ==================================================================== +alter system flush shared_pool; +select sum(s.quantity_sold) +from sales s, products p +where s.prod_id = p.prod_id + group by p.prod_category + order by p.prod_category; + +select sum(s.amount_sold) +from sales s, products p +where s.prod_id = p.prod_id +group by p.prod_category +order by p.prod_category; + +select t.calendar_month_desc, sum(s.amount_sold) as dollars +from sales s, times t +where s.time_id = t.time_id +group by t.calendar_month_desc +order by t.calendar_month_desc; + +select t.calendar_month_desc, sum(s.amount_sold) as dollars +from sales s, times t +where s.time_id = t.time_id +group by t.calendar_month_desc +order by t.calendar_month_desc; + +Rem ==================================================================== +Rem Step 2. Create a new identifier to identify a new collection in the +Rem internal repository and grab a snapshot of the Oracle SQL +Rem cache into the new collection +Rem ==================================================================== +execute dbms_olap.create_id(:workload_id); +execute dbms_olap.load_workload_cache(:workload_id,- + dbms_olap.workload_new,- + dbms_olap.filter_none, NULL, 1); +select count(*) from system.mview_workload + where workloadid = :workload_id; + +Rem ==================================================================== +Rem Step 3. Recommend materialized views with all of the workload +Rem collection and no filtering +Rem ==================================================================== +execute dbms_olap.create_id(:run_id); +execute dbms_olap.recommend_mview_strategy(:run_id, :workload_id,- + dbms_olap.filter_none, 100000, 100, NULL, NULL); +select count(*) from system.mview_recommendations; + +Rem ==================================================================== +Rem Step 4. Generate HTML reports on the output +Rem ==================================================================== +Rem execute dbms_olap.generate_mview_report('/tmp/output2.html',- +Rem :run_id, dbms_olap.rpt_recommendation); + +Rem ==================================================================== +Rem Step 5. Evaluate materialized views +Rem ==================================================================== +execute dbms_olap.create_id(:run_id); +execute dbms_olap.evaluate_mview_strategy(- + :run_id, :workload_id, dbms_olap.filter_none); + +Rem ==================================================================== +Rem Step 6. Generate HTML reports on the output +Rem ==================================================================== +Rem execute dbms_olap.generate_mview_report('/tmp/output3.html',- +Rem :run_id, dbms_olap.rpt_usage); + +Rem ==================================================================== +Rem Step 7. Cleanup current output, and workload collection +Rem from the internal repository +Rem ==================================================================== +execute dbms_olap.purge_results(:run_id); +execute dbms_olap.purge_workload(:workload_id); +disconnect + +Rem ==================================================================== +Rem Cleanup for demos +Rem ==================================================================== +connect system/manager +revoke select on mview_recommendations from sh; +revoke select on mview_workload from sh; +revoke select on mview_filter from sh; +revoke alter system from sh; +disconnect diff --git a/sadvdemo.sql b/sadvdemo.sql new file mode 100644 index 0000000..5893726 --- /dev/null +++ b/sadvdemo.sql @@ -0,0 +1,301 @@ +rem +rem $Header: sadvdemo.sql 05-sep-00.17:17:16 sramakri Exp $ +rem +rem sadvdemo.sql +rem +rem Copyright (c) 1998, 1999,, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem sadvdemo.sql - Demo package used to pretty-print recommendations +rem of the Summary Advisor. +rem +rem +rem DESCRIPTION +rem The Summary Advisor is a component of the DBMS_OLAP package and +rem contains the RECOMMEND_MV and RECOMMEND_MV_W function which +rem recommend materialized views (summaries). The recommendations are +rem written to a table MVIEW$_RECOMMENDATIONS in the user's schema. +rem The function PRETTYPRINT_RECOMMENDATIONS in this package presents +rem the information from that table in a more readable format. +rem +rem +rem PACKAGE INSTALL NOTES +rem +rem o Install/load this package in the Oracle USER where you wish +rem to run the Summary Advisor +rem +rem +rem USAGE NOTES +rem +rem o Run RECOMMEND_MV or RECOMMEND_MV_W as appropriate to compute the +rem the recommendations +rem +rem o To enable outpiut from the demo package, use the SET SERVEROUTPUT +rem command as follows: +rem +rem SET SERVEROUTPUT ON SIZE 1000000 +rem +rem o Execute procedure DEMO_SUMADV.PRETTYPRINT_RECOMMENDATIONS as: +rem +rem execute DEMO_SUMADV.PRETTYPRINT_RECOMMENDATIONS; +rem +rem +rem MODIFIED (MM/DD/YY) +rem sramakri 09/05/00 - format numbers +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem sramakri 10/15/98 - Summary Advisor pretty-printer script +rem sramakri 10/15/98 - Created +rem + +rem create tables in user schema; if tables already exist +rem these create's will fail; that is okay + +create table mview$_recommendations ( + recommendation_number integer primary key, + recommended_action varchar2(6), + summary_owner varchar(30), + summary_name varchar(30), + group_by_columns varchar2(2000), + where_clause varchar2(2000), + from_clause varchar2(2000), + measures_list varchar2(2000), + storage_in_bytes number, + pct_performance_gain number, + benefit_to_cost_ratio number + ); + +create table mview$_evaluations ( + summary_owner varchar(30), + summary_name varchar(30), + rank integer, + storage_in_bytes number, + frequency number, + cumulative_benefit number, + benefit_to_cost_ratio number + ); + + +CREATE OR REPLACE PACKAGE demo_sumadv IS + + PROCEDURE prettyprint_recommendations; + PROCEDURE prettyprint_evaluations; + +END demo_sumadv; +/ + +CREATE OR REPLACE PACKAGE BODY demo_sumadv AS + + + PROCEDURE printbuff(buff in varchar2) + IS + para demo_sumadv_wrap.paragraph_tabletype; + loc_lines integer; + loc_line_length integer := 76; + j BINARY_INTEGER; + BEGIN + demo_sumadv_wrap.to_paragraph(buff, loc_line_length, para, loc_lines); + dbms_output.put_line(para(1)); + for j in 2 .. loc_lines loop + dbms_output.put_line(' ' || para(j)); + end loop; + END printbuff; + + + PROCEDURE print_new_sum_rec(group_by_columns in varchar2, + measures_list in varchar2, + from_clause in varchar2, where_clause in varchar2) + IS + buff VARCHAR2(5000); + BEGIN + buff := 'SELECT ' || group_by_columns || ', ' || measures_list; + printbuff(buff); + buff := 'FROM ' || from_clause; + printbuff(buff); + if where_clause is not null then + buff := 'WHERE ' || where_clause; + printbuff(buff); + end if; + buff := 'GROUP BY ' || group_by_columns; + printbuff(buff); + END print_new_sum_rec; + + PROCEDURE prettyprint_recommendations + IS + CURSOR c_cur IS + SELECT recommendation_number, recommended_action, + summary_owner, summary_name, group_by_columns, + measures_list, from_clause, where_clause, + storage_in_bytes, pct_performance_gain, benefit_to_cost_ratio + FROM MVIEW$_RECOMMENDATIONS + ORDER BY recommendation_number; + BEGIN + FOR c_rec IN c_cur LOOP + + dbms_output.put_line(' '); + dbms_output.put_line( + 'Recommendation Number = ' || c_rec.recommendation_number); + + IF c_rec.summary_name is null then + dbms_output.put_line('Recommended Action is CREATE new summary:'); + ELSE + dbms_output.put_line('Recommended Action is ' || + c_rec.recommended_action || ' existing summary ' || + c_rec.summary_owner || '.' || c_rec.summary_name); + END IF; + + IF c_rec.summary_name is null then + print_new_sum_rec(c_rec.group_by_columns, c_rec.measures_list, + c_rec.from_clause, c_rec.where_clause); + END IF; + + IF c_rec.storage_in_bytes is null then + dbms_output.put_line('Storage in bytes is null'); + ELSE + dbms_output.put_line( + 'Storage in bytes is ' || to_char(c_rec.storage_in_bytes, '9.99EEEE')); + END IF; + + IF c_rec.pct_performance_gain is null then + dbms_output.put_line('Percent performance gain is null'); + ELSE + dbms_output.put_line( + 'Percent performance gain is ' || + to_char(c_rec.pct_performance_gain, '9.99EEEE')); + END IF; + + IF c_rec.benefit_to_cost_ratio is null then + dbms_output.put_line('Benefit-to-cost ratio is null'); + ELSE + dbms_output.put_line( + 'Benefit-to-cost ratio is ' || + to_char(c_rec.benefit_to_cost_ratio, '9.99EEEE')); + END IF; + + + END LOOP; + END prettyprint_recommendations; + + PROCEDURE prettyprint_evaluations + IS + CURSOR c_cur IS + SELECT summary_owner, summary_name, rank, + storage_in_bytes, frequency, cumulative_benefit, benefit_to_cost_ratio + FROM MVIEW$_EVALUATIONS + ORDER BY rank; + BEGIN + FOR c_rec IN c_cur LOOP + + dbms_output.put_line(' '); + dbms_output.put_line( + 'Rank = ' || c_rec.rank || ' Summmary = ' || + c_rec.summary_owner || '.' || c_rec.summary_name); + + dbms_output.put_line( + 'Frequency is ' || c_rec.frequency); + + dbms_output.put_line('Storage_in_bytes = ' || + to_char(c_rec.storage_in_bytes, '9.99EEEE')); + dbms_output.put_line('Cumulative_benefit = ' || + to_char(c_rec.cumulative_benefit, '9.99EEEE')); + dbms_output.put_line('Benefit-to-cost ratio is ' || + to_char(c_rec.benefit_to_cost_ratio, '9.99EEEE')); + + dbms_output.put_line(' '); + + + END LOOP; + END prettyprint_evaluations; + +END demo_sumadv; + +/ + +CREATE OR REPLACE PACKAGE demo_sumadv_wrap +IS + TYPE paragraph_tabletype IS TABLE OF VARCHAR2 (80) + INDEX BY BINARY_INTEGER; + + PROCEDURE to_paragraph + (text_in IN VARCHAR2, + line_length IN INTEGER, + paragraph_out IN OUT paragraph_tabletype, + num_lines_out IN OUT INTEGER, + word_break_at_input IN VARCHAR2 := ' ', + line_break_at_in IN VARCHAR2 := NULL); +END demo_sumadv_wrap; +/ + +create or replace PACKAGE BODY demo_sumadv_wrap +IS + replace_string VARCHAR2(100) := NULL; + + word_break_at_in constant char := ' '; + + + PROCEDURE set_replace_string IS + BEGIN + replace_string := RPAD ('@', LENGTH (word_break_at_in), '@'); + END; + + PROCEDURE find_last_delim_loc (line_in IN VARCHAR2, loc_out OUT INTEGER) + IS + v_line VARCHAR2(1000) := line_in; + BEGIN + IF word_break_at_in IS NOT NULL THEN + v_line := TRANSLATE (line_in, word_break_at_in, replace_string); + END IF; + loc_out := INSTR (v_line, '@', -1); + END; + + PROCEDURE to_paragraph + (text_in IN VARCHAR2, + line_length IN INTEGER, + paragraph_out IN OUT paragraph_tabletype, + num_lines_out IN OUT INTEGER, + word_break_at_input IN VARCHAR2 := ' ', + line_break_at_in IN VARCHAR2 := NULL) + IS + len_text INTEGER := LENGTH (text_in); + line_start_loc INTEGER := 1; + line_end_loc INTEGER := 1; + last_space_loc INTEGER; + curr_line VARCHAR2(80); + BEGIN + set_replace_string; + + IF len_text IS NULL THEN + num_lines_out := 0; + ELSE + num_lines_out := 1; + LOOP + EXIT WHEN line_end_loc > len_text; + line_end_loc := LEAST (line_end_loc + line_length, len_text + 1); + + /* get the next possible line of text */ + curr_line := SUBSTR (text_in || ' ', + line_start_loc, line_length + 1); + + /* find the last space in this section of the line */ + find_last_delim_loc (curr_line, last_space_loc); + + /* When NO spaces exist, use the full current line*/ + /* otherwise, cut the line at the space. */ + IF last_space_loc > 0 THEN + line_end_loc := line_start_loc + last_space_loc; + END IF; + + /* Add this line to the paragraph */ + paragraph_out (num_lines_out) := + substr (text_in, + line_start_loc, + line_end_loc - line_start_loc); + + num_lines_out := num_lines_out + 1; + line_start_loc := line_end_loc; + END LOOP; + num_lines_out := num_lines_out - 1; + END IF; + END to_paragraph; +END demo_sumadv_wrap; +/ + diff --git a/sadvuwk.sql b/sadvuwk.sql new file mode 100644 index 0000000..fc4bca5 --- /dev/null +++ b/sadvuwk.sql @@ -0,0 +1,49 @@ +Rem +Rem $Header: template.sql 06-feb-96.13:23:14 kosinski Exp $ +Rem +Rem sadvuwk.sql +Rem +Rem Copyright (c) Oracle Corporation 2000. All Rights Reserved. +Rem +Rem NAME +Rem sadvuwk.SQL - Sample script to create a user-workload table +Rem +Rem DESCRIPTION +Rem This is a simple example of creating a user-defined workload table from +Rem which Summary Advisor can extract a workload. +Rem +Rem NOTES +Rem The indexes are optional; however, if you plan on applying workload filters +Rem to the load workload operation, then you should create indexes on the +Rem most significant filter columns fo the user workload. +Rem +Rem The QUERY and OWNER columns are the only required columns for a user-supplied +Rem workload. +Rem +Rem If the QUERY column will contain SQL statements longer than 2000 characters, +Rem then it is acceptable to create the column as a LONG datatype. +Rem +Rem MODIFIED (MM/DD/YY) +Rem gssmith 11/06/00 - Created +Rem + +CREATE TABLE advisor_user_workload + ( + query varchar2(2000), /* full sql text */ + owner varchar(30), /* user submitting the query */ + application varchar(30), /* application name */ + frequency number, /* query frequency */ + lastuse date, /* lastuse date of the query */ + priority number, /* priority of the query */ + responsetime number, /* query response time */ + resultsize number, /* result size in bytes */ + sql_hash number, /* server generated hash */ + sql_addr raw(4) /* lib-cache address */ + ); + +CREATE INDEX adv_uwk_idx_01 + ON advisor_user_workload (application,lastuse); + +CREATE INDEX adv_uwk_idx_02 + ON advisor_user_workload (owner,lastuse); + diff --git a/smdim.sql b/smdim.sql new file mode 100644 index 0000000..d22d21c --- /dev/null +++ b/smdim.sql @@ -0,0 +1,362 @@ +rem +rem $Header: smdim.sql 13-feb-02.14:20:58 twtong Exp $ +rem +rem smdim.sql +rem +rem Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem smdim.sql - describe dimensions +rem +rem DESCRIPTION +rem The procedures here describe dimensions in a user's schema. +rem PRINT_DIM shows information about a specified dimension; +rem PRINT_ALLDIMS shows information about all the dimensions +rem accessible to the user. +rem +rem NOTES +rem These routines are similar to the Server Manager builtin +rem "describe" command which displays information about tables +rem and packages. Hence they should be useful to DBA's using +rem a command-line interface. For developers, these routines are +rem useful because they illustrate techniques to navigate the +rem various catalog views related to dimensions. +rem +rem +rem MODIFIED (MM/DD/YY) +rem twtong 02/13/02 - add attribute_name to print_attributes +rem jraitto 04/14/00 - fix bugs 1268813, 845372 +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem sramakri 10/28/98 - make it JOIN KEY, not "JOINKEY" +rem sramakri 10/28/98 - cleanup +rem sramakri 10/28/98 - PL/SQL procedures to "describe" dimensions +rem sramakri 10/28/98 - Created +rem + +CREATE OR REPLACE PACKAGE demo_dim IS + + PROCEDURE print_dim(in_dim_name varchar2); + PROCEDURE print_alldims; + +END demo_dim; +/ + +CREATE OR REPLACE PACKAGE BODY demo_dim AS + + + PROCEDURE print_attributes(in_owner varchar2, in_dimension_name varchar2) + IS + CURSOR c_cur IS + select attribute_name, level_name, column_name + from all_dim_attributes + where + in_owner = owner and + in_dimension_name = dimension_name + order by level_name, column_name; + + child_table_owner varchar2(32); + child_table_name varchar2(32); + + BEGIN + FOR c_rec IN c_cur LOOP + dbms_output.put(' '); + dbms_output.put('ATTRIBUTE ' || c_rec.attribute_name || + ' LEVEL ' || c_rec.level_name || + ' DETERMINES '); + + select dl.detailobj_owner, dl.detailobj_name + into child_table_owner, child_table_name + from all_dim_levels dl + where in_owner = dl.owner and + in_dimension_name = dl.dimension_name and + c_rec.level_name = dl.level_name; + + dbms_output.put_line(child_table_owner || '.' || child_table_name + || '.' || c_rec.column_name); + END LOOP; + END print_attributes; + + + + + PROCEDURE get_joinkey(in_owner varchar2, in_dimension_name varchar2, + in_hierarchy_name varchar2, in_jkid integer, + jkchildcolms out varchar2, + num_jkchildcolms out integer, parent_level out varchar2) + IS + CURSOR c_cur IS + select key_position, child_join_column, level_name + from all_dim_join_key + where in_jkid = dim_key_id and + in_owner = owner and + in_dimension_name = dimension_name and + in_hierarchy_name = hierarchy_name + order by key_position; + BEGIN + num_jkchildcolms := 0; + FOR c_rec IN c_cur LOOP + + num_jkchildcolms := num_jkchildcolms + 1; + parent_level := c_rec.level_name; + + if num_jkchildcolms > 1 + then + jkchildcolms := jkchildcolms || ', ' || c_rec.child_join_column; + else + jkchildcolms := c_rec.child_join_column; + end if; + + END LOOP; + END get_joinkey; + + + + PROCEDURE print_children(in_owner varchar2, in_dimension_name varchar2, + in_hierarchy_name varchar2, children out varchar2, + num_children out integer) + IS + CURSOR c_cur IS + select dco.position, dco.child_level_name, dco.parent_level_name + from all_dim_child_of dco + where in_owner = dco.owner and + in_dimension_name = dco.dimension_name and + in_hierarchy_name = dco.hierarchy_name + order by dco.position; + BEGIN + num_children := 0; + FOR c_rec IN c_cur LOOP + + num_children := num_children + 1; + + if num_children = 1 + then + dbms_output.put_line(' ' || c_rec.child_level_name); + end if; + + children := 'CHILD OF ' || c_rec.parent_level_name; + + dbms_output.put_line(' ' || children); + + + END LOOP; + END print_children; + + + + + PROCEDURE print_hierarchies(in_owner varchar2, in_dimension_name varchar2) + IS + CURSOR c_cur IS + select hierarchy_name + from all_dim_hierarchies + where + in_owner = owner and + in_dimension_name = dimension_name + order by hierarchy_name; + + num_children integer; + children varchar2(2000); + num_jkcolms integer; + jkcolms varchar2(2000); + in_hierarchy_name varchar2(32); + child_table_owner varchar2(32); + child_table_name varchar2(32); + parent_level varchar2(32); + CURSOR c_jkcur IS + select dco.join_key_id, dco.child_level_name + from all_dim_child_of dco + where in_owner = dco.owner and + in_dimension_name = dco.dimension_name and + in_hierarchy_name = dco.hierarchy_name and + dco.join_key_id is not null + order by dco.position; + BEGIN + FOR c_rec IN c_cur LOOP + + dbms_output.put(' '); + dbms_output.put_line('HIERARCHY ' || c_rec.hierarchy_name || + ' ( '); + print_children(in_owner, in_dimension_name, c_rec.hierarchy_name, + children, num_children); + in_hierarchy_name := c_rec.hierarchy_name; + + for c_jkrec in c_jkcur loop + + select dl.detailobj_owner, dl.detailobj_name + into child_table_owner, child_table_name + from all_dim_levels dl + where in_owner = dl.owner and + in_dimension_name = dl.dimension_name and + c_jkrec.child_level_name = dl.level_name; + + get_joinkey(in_owner, in_dimension_name, in_hierarchy_name, + c_jkrec.join_key_id, + jkcolms, num_jkcolms, parent_level); + + dbms_output.put(' '); + dbms_output.put('JOIN KEY '); + + if num_jkcolms > 1 + then + dbms_output.put('('); + end if; + + dbms_output.put(child_table_owner || '.' || child_table_name + || '.' || jkcolms); + + if num_jkcolms > 1 + then + dbms_output.put(')'); + end if; + + dbms_output.put_line(' REFERENCES ' || parent_level); + + end loop; + + dbms_output.put_line(' )'); + + END LOOP; + END print_hierarchies; + + + + + + PROCEDURE get_segments(in_owner varchar2, in_dimension_name varchar2, + in_level_name varchar2, segments out varchar2, + num_segments out integer) + IS + CURSOR c_cur IS + select dlk.key_position, dlk.column_name + from all_dim_level_key dlk + where in_owner = dlk.owner and + in_dimension_name = dlk.dimension_name and + in_level_name = level_name + order by dlk.key_position; + BEGIN + num_segments := 0; + FOR c_rec IN c_cur LOOP + + num_segments := num_segments + 1; + + if num_segments > 1 + then + segments := segments || ', ' || c_rec.column_name; + else + segments := c_rec.column_name; + end if; + + END LOOP; + END get_segments; + + + + + PROCEDURE print_levels(in_owner varchar2, in_dimension_name varchar2) + IS + CURSOR c_cur IS + select level_name, detailobj_owner, detailobj_name + from all_dim_levels + where + in_owner = owner and + in_dimension_name = dimension_name + order by owner, dimension_name, level_name; + num_segments integer; + segments varchar2(2000); + BEGIN + FOR c_rec IN c_cur LOOP + + dbms_output.put(' '); + dbms_output.put('LEVEL ' || c_rec.level_name || + ' IS '); + + get_segments(in_owner, in_dimension_name, c_rec.level_name, + segments, num_segments); + + if num_segments > 1 + then + dbms_output.put('('); + end if; + + dbms_output.put(c_rec.detailobj_owner || '.' || c_rec.detailobj_name + || '.' || segments); + + if num_segments > 1 + then + dbms_output.put(')'); + end if; + + dbms_output.put_line(' '); + + END LOOP; + END print_levels; + + + + PROCEDURE print_dim(in_dim_name varchar2) + IS + CURSOR c_cur IS + select owner, dimension_name + from all_dimensions + where owner = user + and decode(substr(trim(in_dim_name),1,1),'"', + trim('"' from trim(in_dim_name)), + trim(upper(in_dim_name))) + = dimension_name + order by owner, dimension_name; + counter integer; + BEGIN + counter := 0; + FOR c_rec IN c_cur LOOP + + counter := counter + 1; + dbms_output.put(' '); + dbms_output.put_line('DIMENSION ' || c_rec.owner || '.' + || c_rec.dimension_name ); + + print_levels( c_rec.owner, c_rec.dimension_name ); + dbms_output.put_line(' '); + print_hierarchies( c_rec.owner, c_rec.dimension_name ); + dbms_output.put_line(' '); + print_attributes( c_rec.owner, c_rec.dimension_name ); + dbms_output.put_line(' '); + + END LOOP; + + if counter = 0 + then + dbms_output.put_line('No such dimension present in schema'); + end if; + + END print_dim; + + + PROCEDURE print_alldims + IS + CURSOR c_cur IS + select owner, dimension_name + from all_dimensions + where invalid = 'N' + order by owner, dimension_name; + BEGIN + FOR c_rec IN c_cur LOOP + + dbms_output.put(' '); + dbms_output.put_line('DIMENSION ' || c_rec.owner || '.' + || c_rec.dimension_name ); + + print_levels( c_rec.owner, c_rec.dimension_name ); + dbms_output.put_line(' '); + print_hierarchies( c_rec.owner, c_rec.dimension_name ); + dbms_output.put_line(' '); + print_attributes( c_rec.owner, c_rec.dimension_name ); + dbms_output.put_line(' '); + + END LOOP; + END print_alldims; + + + +END demo_dim; + +/ diff --git a/smxmv1.sql b/smxmv1.sql new file mode 100644 index 0000000..0e356c2 --- /dev/null +++ b/smxmv1.sql @@ -0,0 +1,238 @@ +Rem +Rem $Header: smxmv1.sql 03-aug-2004.12:12:07 mmoy Exp $ +Rem +Rem smxmv1.sql +Rem +Rem Copyright (c) 2001, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem smxmv1.sql +Rem +Rem DESCRIPTION +Rem This is a demo script for explain_mview(). It creates +Rem a materialized view in SALES schema and uses explain_mview() +Rem to describe its capabilities and how to enhance it. +Rem The output of explain_mview() is stored in MV_CAPABILITIES_TABLE +Rem +Rem NOTE +Rem Please run utlxmv.sql in the admin directory to create +Rem MV_CAPABILITIES_TABLE in your schema before running this +Rem demo script +Rem +Rem MODIFIED (MM/DD/YY) +Rem mmoy 08/03/04 - Fix order by. +Rem twtong 04/02/01 - review comment +Rem twtong 03/26/01 - Created +Rem +Rem ================================================================ + +CONNECT sh/sh; +SET ECHO ON; +REM ----------------------------------------------------------- +REM use explain_mview to analyze a potential materialized view +REM ----------------------------------------------------------- + +BEGIN + DBMS_MVIEW.EXPLAIN_MVIEW + ('SELECT t.calendar_month_desc, + SUM(s.amount_sold) AS dollars + FROM sales s, times t + WHERE s.time_id = t.time_id + GROUP BY t.calendar_month_desc','ID1'); +END; +/ + +SELECT SUBSTR(capability_name,1,30) capability_name, + possible, + SUBSTR(related_text,1,15) related_text, + related_num, + msgno, + SUBSTR(msgtxt,1,110) msgtxt +FROM mv_capabilities_table +ORDER BY capability_name, seq; + +TRUNCATE TABLE mv_capabilities_table; + +REM ------------------------------------------------------------------- +REM make corrections and enhancement to increase the capabilities of +REM the potential materialized view according to messages from +REM explain_mview() +REM ------------------------------------------------------------------- + +REM ------------------------------------------------------------------- +REM create materialized view log on sales, times, and products +REM ------------------------------------------------------------------- + +CREATE MATERIALIZED VIEW LOG ON sales WITH ROWID; +CREATE MATERIALIZED VIEW LOG ON times; + +BEGIN + DBMS_MVIEW.EXPLAIN_MVIEW + ('SELECT t.calendar_month_desc, + SUM(s.amount_sold) AS dollars + FROM sales s, times t + WHERE s.time_id = t.time_id + GROUP BY t.calendar_month_desc','ID2'); +END; +/ + +SELECT SUBSTR(capability_name,1,30) capability_name, + possible, + SUBSTR(related_text,1,15) related_text, + related_num, + msgno, + SUBSTR(msgtxt,1,110) msgtxt +FROM mv_capabilities_table +ORDER BY seq; + +TRUNCATE TABLE mv_capabilities_table; + +REM ---------------------------------------------------------------- +REM make more corrections on the materialized view log suggested +REM by explain_mview() +REM ---------------------------------------------------------------- + +DROP MATERIALIZED VIEW LOG ON sales; +DROP MATERIALIZED VIEW LOG ON times; +CREATE MATERIALIZED VIEW LOG ON sales WITH ROWID (time_id, amount_sold) + INCLUDING NEW VALUES; +CREATE MATERIALIZED VIEW LOG ON times WITH ROWID (time_id, calendar_month_desc) + INCLUDING NEW VALUES; + +REM ------------------------------------------------------------------- +REM modify the select statement in the potential materialized view +REM to enhance the capabilities +REM 1) use PMARKER in the select and group by list to enable +REM PCT on sales +REM 2) add COUNT(*) and COUNT(amount) in the select list to +REM enhance fast refresh capabilities +REM ------------------------------------------------------------------- + +BEGIN + DBMS_MVIEW.EXPLAIN_MVIEW + ( 'SELECT DBMS_MVIEW.PMARKER(s.rowid), + t.calendar_month_desc, + COUNT(*) AS cnt_str, + COUNT(s.amount_sold) AS cnt_amt, + SUM(s.amount_sold) AS dollars + FROM sales s, times t + WHERE s.time_id = t.time_id + GROUP BY DBMS_MVIEW.PMARKER(s.rowid), + t.calendar_month_desc','ID3'); +END; +/ + +SELECT SUBSTR(capability_name,1,30) capability_name, + possible, + SUBSTR(related_text,1,15) related_text, + related_num, + msgno, + SUBSTR(msgtxt,1,110) msgtxt +FROM mv_capabilities_table +ORDER BY seq; + +TRUNCATE TABLE mv_capabilities_table; + +REM ------------------------------------------------------------------- +REM re-create the materialized log to include sequence# +REM ------------------------------------------------------------------- + +DROP MATERIALIZED VIEW LOG ON sales; +DROP MATERIALIZED VIEW LOG ON times; +CREATE MATERIALIZED VIEW LOG ON sales WITH ROWID, SEQUENCE (time_id, amount_sold) + INCLUDING NEW VALUES; +CREATE MATERIALIZED VIEW LOG ON times WITH ROWID, SEQUENCE (time_id, calendar_month_desc) + INCLUDING NEW VALUES; + +BEGIN + DBMS_MVIEW.EXPLAIN_MVIEW + ( 'SELECT DBMS_MVIEW.PMARKER(s.rowid), + t.calendar_month_desc, + COUNT(*) AS cnt_str, + COUNT(s.amount_sold) AS cnt_amt, + SUM(s.amount_sold) AS dollars + FROM sales s, times t + WHERE s.time_id = t.time_id + GROUP BY DBMS_MVIEW.PMARKER(s.rowid), + t.calendar_month_desc','ID4'); +END; +/ + +SELECT SUBSTR(capability_name,1,30) capability_name, + possible, + SUBSTR(related_text,1,15) related_text, + related_num, + msgno, + SUBSTR(msgtxt,1,110) msgtxt +FROM mv_capabilities_table +ORDER BY seq; + +TRUNCATE TABLE mv_capabilities_table; + +REM ------------------------------------------------------------------- +REM create the materialized view +REM ------------------------------------------------------------------- + +CREATE MATERIALIZED VIEW month_sales_mv + BUILD IMMEDIATE + REFRESH FORCE + DISABLE QUERY REWRITE + AS + SELECT DBMS_MVIEW.PMARKER(s.rowid), + t.calendar_month_desc, + COUNT(*) AS cnt_str, + COUNT(s.amount_sold) AS cnt_amt, + SUM(s.amount_sold) AS dollars + FROM sales s, times t + WHERE s.time_id = t.time_id + GROUP BY DBMS_MVIEW.PMARKER(s.rowid), + t.calendar_month_DESC; + +REM ---------------------------------------------------------------- +REM use explain_mview() on the materialized view that has just been +REM created to check if it has all the capabilities +REM ----------------------------------------------------------------- + +EXECUTE DBMS_MVIEW.EXPLAIN_MVIEW('month_sales_mv','ID5'); + +SELECT SUBSTR(capability_name,1,30) capability_name, + possible, + SUBSTR(related_text,1,15) related_text, + related_num, + msgno, + SUBSTR(msgtxt,1,110) msgtxt +FROM mv_capabilities_table +ORDER BY seq; + +TRUNCATE TABLE mv_capabilities_table; + +REM ---------------------------------------------------------------- +REM enable query rewrite on the materialized view +REM ----------------------------------------------------------------- + +ALTER materialized VIEW month_sales_mv enable query rewrite; + +EXECUTE DBMS_MVIEW.EXPLAIN_MVIEW('month_sales_mv','ID6'); + +SELECT SUBSTR(capability_name,1,30) capability_name, + possible, + SUBSTR(related_text,1,15) related_text, + related_num, + msgno, + SUBSTR(msgtxt,1,110) msgtxt +FROM mv_capabilities_table +ORDER BY seq; + +TRUNCATE TABLE mv_capabilities_table; + +REM -------------------------------- +REM Clean up +REM -------------------------------- + +DROP MATERIALIZED VIEW month_sales_mv; +DROP MATERIALIZED VIEW LOG ON sales; +DROP MATERIALIZED VIEW LOG ON times; +DISCONNECT + + + diff --git a/smxmv2.sql b/smxmv2.sql new file mode 100644 index 0000000..62de43e --- /dev/null +++ b/smxmv2.sql @@ -0,0 +1,219 @@ +Rem +Rem $Header: smxmv2.sql 02-apr-2001.15:00:24 twtong Exp $ +Rem +Rem smxmv2.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem smxmv2.sql +Rem +Rem DESCRIPTION +Rem This is a demo script for explain_mview(). It uses +Rem explain_mview() on a potential materialized view and +Rem display its capabilities and how to enhance it. The +Rem materialized view is not created by explain_mview(). +Rem Only the select statement for the potential materialized +Rem view is used by explain_mview to analyze its capabilities +Rem The output is stored in a VARRAY +Rem +Rem MODIFIED (MM/DD/YY) +Rem twtong 04/02/01 - review comment +Rem twtong 03/26/01 - Created +Rem +REM ================================================================ + +CONNECT sh/sh; +SET ECHO ON +SET SERVEROUTPUT ON + +DECLARE + XMV_Array SYS.ExplainMVArrayType := SYS.ExplainMVArrayType(); + no_of_msgs NUMBER; + i NUMBER; +BEGIN + DBMS_OUTPUT.enable(32512); + dbms_mview.explain_mview ('SELECT t.week_ending_day, p.prod_subcategory, s.channel_id, + s.promo_id, sum(s.amount_sold) AS dollars + FROM sales s, times t, products p + WHERE s.time_id = t.time_id AND + s.prod_id = p.prod_id + GROUP BY t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id', + XMV_Array); + no_of_msgs := XMV_Array.count; + FOR i IN 1..no_of_msgs + LOOP + DBMS_OUTPUT.PUT_LINE(' CAPABILITY : ' || XMV_Array(i).capability_name); + DBMS_OUTPUT.PUT_LINE(' POSSIBLE : ' || XMV_Array(i).possible); + DBMS_OUTPUT.PUT_LINE(' REL_TEXT : ' || XMV_Array(i).related_text); + DBMS_OUTPUT.PUT_LINE(' REL_NUM : ' || XMV_Array(i).related_num); + DBMS_OUTPUT.PUT_LINE(' MSGNO : ' || XMV_Array(i).msgno); + DBMS_OUTPUT.PUT_LINE(' MSGTXT : ' || XMV_Array(i).msgtxt); + DBMS_OUTPUT.PUT_LINE(' '); + END LOOP; +END; +/ + +REM ------------------------------------------------------------------- +REM make corrections and enhancement to increase the capabilities of +REM the potential materialized view according to messages from +REM explain_mview() +REM ------------------------------------------------------------------- + +REM ------------------------------------------------------------------- +REM create materialized view log on sales, times, and products +REM ------------------------------------------------------------------- + +CREATE MATERIALIZED VIEW LOG ON sales WITH ROWID; +CREATE MATERIALIZED VIEW LOG ON times WITH ROWID; +CREATE MATERIALIZED VIEW LOG ON products WITH ROWID; + +REM ------------------------------------------------------------------- +REM modify the select statement to enhance the capabilities +REM 1) use PMARKER in the select and group by list to enable +REM PCT on sales +REM 2) add COUNT(*) and COUNT(amount) in the select list to +REM enhance fast refresh capabilities +REM ------------------------------------------------------------------- + +DECLARE + XMV_Array SYS.ExplainMVArrayType := SYS.ExplainMVArrayType(); + no_of_msgs NUMBER; + i NUMBER; +BEGIN + DBMS_OUTPUT.enable(32512); + dbms_mview.explain_mview ('SELECT DBMS_MVIEW.PMARKER(s.rowid), t.week_ending_day, + p.prod_subcategory, s.channel_id, s.promo_id, + COUNT(*) AS cnt_str, COUNT(s.amount_sold) AS cnt_amt, + SUM(s.amount_sold) AS dollars + FROM sales s, times t, products p + WHERE s.time_id = t.time_id AND + s.prod_id = p.prod_id + GROUP BY DBMS_MVIEW.PMARKER(s.rowid), + t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id', + XMV_Array); + no_of_msgs := XMV_Array.count; + FOR i IN 1..no_of_msgs + LOOP + DBMS_OUTPUT.PUT_LINE(' CAPABILITY : ' || XMV_Array(i).capability_name); + DBMS_OUTPUT.PUT_LINE(' POSSIBLE : ' || XMV_Array(i).possible); + DBMS_OUTPUT.PUT_LINE(' REL_TEXT : ' || XMV_Array(i).related_text); + DBMS_OUTPUT.PUT_LINE(' REL_NUM : ' || XMV_Array(i).related_num); + DBMS_OUTPUT.PUT_LINE(' MSGNO : ' || XMV_Array(i).msgno); + DBMS_OUTPUT.PUT_LINE(' MSGTXT : ' || XMV_Array(i).msgtxt); + DBMS_OUTPUT.PUT_LINE(' '); + END LOOP; +END; +/ + +REM ---------------------------------------------------------------- +REM make more corrections on the materialized view log suggested +REM by explain_mview() to enable all fast refresh capabilities +REM ---------------------------------------------------------------- + +DROP MATERIALIZED VIEW LOG ON sales; +CREATE MATERIALIZED VIEW LOG ON sales WITH ROWID, SEQUENCE + (time_id, prod_id, channel_id, promo_id, amount_sold) INCLUDING NEW VALUES; + +DROP MATERIALIZED VIEW LOG ON times; +CREATE MATERIALIZED VIEW LOG ON times WITH ROWID, SEQUENCE + (time_id, week_ending_day) INCLUDING NEW VALUES; + +DROP MATERIALIZED VIEW LOG ON products; +CREATE MATERIALIZED VIEW LOG ON products WITH ROWID, SEQUENCE + (prod_id, prod_subcategory) INCLUDING NEW VALUES; + +REM ---------------------------------------------------------------- +REM retry explain_mview() to see if the potential materialized view +REM has all the capabilities +REM ---------------------------------------------------------------- + +DECLARE + XMV_Array SYS.ExplainMVArrayType := SYS.ExplainMVArrayType(); + no_of_msgs NUMBER; + i NUMBER; +BEGIN + DBMS_OUTPUT.enable(32512); + dbms_mview.explain_mview ('SELECT DBMS_MVIEW.PMARKER(s.rowid), t.week_ending_day, + p.prod_subcategory, s.channel_id, s.promo_id, + COUNT(*) AS cnt_str, COUNT(s.amount_sold) AS cnt_amt, + SUM(s.amount_sold) AS dollars + FROM sales s, times t, products p + WHERE s.time_id = t.time_id AND + s.prod_id = p.prod_id + GROUP BY DBMS_MVIEW.PMARKER(s.rowid), + t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id', + XMV_Array); + no_of_msgs := XMV_Array.count; + FOR i IN 1..no_of_msgs + LOOP + DBMS_OUTPUT.PUT_LINE(' CAPABILITY : ' || XMV_Array(i).capability_name); + DBMS_OUTPUT.PUT_LINE(' POSSIBLE : ' || XMV_Array(i).possible); + DBMS_OUTPUT.PUT_LINE(' REL_TEXT : ' || XMV_Array(i).related_text); + DBMS_OUTPUT.PUT_LINE(' REL_NUM : ' || XMV_Array(i).related_num); + DBMS_OUTPUT.PUT_LINE(' MSGNO : ' || XMV_Array(i).msgno); + DBMS_OUTPUT.PUT_LINE(' MSGTXT : ' || XMV_Array(i).msgtxt); + DBMS_OUTPUT.PUT_LINE(' '); + END LOOP; +END; +/ + +REM ---------------------------------------------------------------- +REM create the materialized view +REM ---------------------------------------------------------------- + +CREATE MATERIALIZED VIEW week_sales_mv +BUILD IMMEDIATE +REFRESH FORCE +ENABLE QUERY REWRITE +AS +SELECT DBMS_MVIEW.PMARKER(s.rowid), t.week_ending_day, + p.prod_subcategory, s.channel_id, s.promo_id, + COUNT(*) AS cnt_str, COUNT(s.amount_sold) AS cnt_amt, + SUM(s.amount_sold) AS dollars +FROM sales s, times t, products p +WHERE s.time_id = t.time_id AND + s.prod_id = p.prod_id +GROUP BY DBMS_MVIEW.PMARKER(s.rowid), + t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id; + +REM ---------------------------------------------------------------- +REM use explain_mview() on the materialized view that has just +REM been created +REM ---------------------------------------------------------------- + +DECLARE + XMV_Array SYS.ExplainMVArrayType := SYS.ExplainMVArrayType(); + no_of_msgs NUMBER; + i NUMBER; +BEGIN + DBMS_OUTPUT.enable(32512); + dbms_mview.explain_mview ('week_sales_mv', XMV_Array); + no_of_msgs := XMV_Array.count; + FOR i IN 1..no_of_msgs + LOOP + DBMS_OUTPUT.PUT_LINE(' CAPABILITY : ' || XMV_Array(i).capability_name); + DBMS_OUTPUT.PUT_LINE(' POSSIBLE : ' || XMV_Array(i).possible); + DBMS_OUTPUT.PUT_LINE(' REL_TEXT : ' || XMV_Array(i).related_text); + DBMS_OUTPUT.PUT_LINE(' REL_NUM : ' || XMV_Array(i).related_num); + DBMS_OUTPUT.PUT_LINE(' MSGNO : ' || XMV_Array(i).msgno); + DBMS_OUTPUT.PUT_LINE(' MSGTXT : ' || XMV_Array(i).msgtxt); + DBMS_OUTPUT.PUT_LINE(' '); + END LOOP; +END; +/ + +REM ----------------------------------------------------------- +REM clean up +REM ----------------------------------------------------------- + +DROP MATERIALIZED VIEW LOG ON sales; +DROP MATERIALIZED VIEW LOG ON products; +DROP MATERIALIZED VIEW LOG ON times; +DISCONNECT; + + diff --git a/smxrw.sql b/smxrw.sql new file mode 100644 index 0000000..bb4ff01 --- /dev/null +++ b/smxrw.sql @@ -0,0 +1,1116 @@ +Rem +Rem $Header: smxrw.sql 03-apr-2008.20:53:59 mmoy Exp $ +Rem +Rem smxrw.sql +Rem +Rem Copyright (c) 2001, 2008, Oracle. All rights reserved. +Rem +Rem NAME +Rem smxrw.sql +Rem +Rem DESCRIPTION +Rem This is a demo script for DBMS_MVIEW.EXPLAIN_REWRITE(). +Rem We create a materialized view in SALES schema and +Rem use EXPLAIN_REWRITE() to find out why query rewrite +Rem failed for some queries. The output of EXPLAIN_REWRITE() +Rem can go into a VARRAY or REWRITE_TABLE. +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem mmoy 04/03/08 - Fix sys password. +Rem gvincent 11/02/06 - downcase connects for secure verifiers +Rem mthiyaga 03/28/05 - Add examples using XRW utility +Rem mthiyaga 04/09/01 - Merged mthiyaga_xrw_demo +Rem mthiyaga 04/06/01 - Created +Rem +Rem =============================================================== +Rem + +connect sh/sh; + +SET ECHO ON; + +DROP MATERIALIZED VIEW month_sales_mv; + +CREATE MATERIALIZED VIEW month_sales_mv + ENABLE QUERY REWRITE + AS + SELECT t.calendar_month_number, + SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE s.time_id = t.time_id + GROUP BY t.calendar_month_number; + +REM Create REWRITE_TABLE for the output + +DROP TABLE REWRITE_TABLE; + +REM Create REWRITE_TABLE. Note the script to create the REWRITE_TABLE, utlxrw.sql, can +REM be found in the /rdbms/admin directory. + +@utlxrw.sql; + + +REM Enable query rewrite +ALTER SESSION SET QUERY_REWRITE_ENABLED = TRUE; + +REM Stale tolerated mode +ALTER SESSION SET QUERY_REWRITE_INTEGRITY = STALE_TOLERATED; + +DELETE FROM REWRITE_TABLE; + +REM ----------------------------------------------------------------------------- +REM Example 1: Output goes into REWRITE_TABLE +REM ----------------------------------------------------------------------------- + +SET SERVEROUTPUT ON; +DECLARE + querytxt VARCHAR2(1000) := 'SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE s.time_id = t.time_id AND + t.calendar_month_number = 5 + GROUP BY t.calendar_month_number'; +BEGIN + dbms_mview.Explain_Rewrite(querytxt, 'MONTH_SALES_MV'); +END; +/ + +REM Check the results in REWRITE_TABLE + +SELECT * FROM REWRITE_TABLE; + +REM ----------------------------------------------------------------------------- +REM Example 2: Query doesn't have the join in MONTH_SALES_MV. +REM ----------------------------------------------------------------------------- + + +DELETE FROM REWRITE_TABLE; + +EXECUTE dbms_mview.Explain_Rewrite('SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars FROM sales s, times t GROUP BY t.calendar_month_number', 'MONTH_SALES_MV'); + +SELECT * FROM REWRITE_TABLE; + + +REM ----------------------------------------------------------------------------- +REM Example 3: In this example, we run explain_rewrite on two different queries. +REM Their outputs are distinguished by using two different statement +REM ids (query_1 and query_2). +REM ----------------------------------------------------------------------------- + +DELETE FROM REWRITE_TABLE; + +SET SERVEROUTPUT ON; +DECLARE + querytxt1 VARCHAR2(1000) := 'SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE s.time_id = t.time_id AND + t.calendar_month_number = 5 + GROUP BY t.calendar_month_number'; + querytxt2 VARCHAR2(1000) := 'SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE s.time_id = t.time_id AND + t.calendar_month_number = 10 + GROUP BY t.calendar_month_number'; + +BEGIN + dbms_mview.Explain_Rewrite(querytxt1, 'MONTH_SALES_MV', 'query_1'); + dbms_mview.Explain_Rewrite(querytxt2, 'MONTH_SALES_MV', 'query_2'); +END; +/ + +SELECT statement_id, message FROM REWRITE_TABLE; + + +REM ----------------------------------------------------------------------------- +REM Test 4: Query txt is the only argument passed to EXPLAIN_REWRITE. Output +REM goes to REWRITE_TABLE. Note that since there is no materialized view +REM specified in the argument list, EXPLAIN_REWRITE will output +REM messages related to all the MV's considered by query rewrite. +REM ----------------------------------------------------------------------------- + + +DELETE FROM REWRITE_TABLE; + +SET SERVEROUTPUT ON; +DECLARE + querytxt VARCHAR2(1000) := 'SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE t.calendar_month_number = 5 + GROUP BY t.calendar_month_number'; +BEGIN + dbms_mview.Explain_Rewrite(querytxt); +END; +/ + +-- Check the results in REWRITE_TABLE + +SELECT * FROM REWRITE_TABLE; + + + +REM ----------------------------------------------------------------------------- +REM Test 5: Output goes into a VARRAY. Note that we need to turn on SERVEROUTPUT +REM in order to see the output below. +REM ----------------------------------------------------------------------------- + +SET SERVEROUTPUT ON; +DECLARE + Rewrite_Array SYS.RewriteArrayType := SYS.RewriteArrayType(); + querytxt VARCHAR2(1000) := 'SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE s.time_id = t.time_id AND + t.calendar_month_number = 5 + GROUP BY t.calendar_month_number'; + no_of_msgs NUMBER; + i NUMBER; +BEGIN + dbms_mview.Explain_Rewrite(querytxt, 'MONTH_SALES_MV', Rewrite_Array); + no_of_msgs := rewrite_array.count; + FOR i IN 1..no_of_msgs + LOOP + DBMS_OUTPUT.PUT_LINE('>> MV_NAME : ' || Rewrite_Array(i).mv_name); + DBMS_OUTPUT.PUT_LINE('>> BEFORE VM: ' || Rewrite_Array(i).pass); + DBMS_OUTPUT.PUT_LINE('>> QUERY : ' || Rewrite_Array(i).query_text); + DBMS_OUTPUT.PUT_LINE('>> MESSAGE : ' || Rewrite_Array(i).message); + END LOOP; +END; +/ + + + +REM ----------------------------------------------------------------------------- +REM Test 6: Query rewrite is disabled +REM ----------------------------------------------------------------------------- + +-- Disable query rewrite and try the query +ALTER SESSION SET QUERY_REWRITE_ENABLED = FALSE; + +SET SERVEROUTPUT ON; +DECLARE + Rewrite_Array SYS.RewriteArrayType := SYS.RewriteArrayType(); + querytxt VARCHAR2(1000) := 'SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE s.time_id = t.time_id AND + t.calendar_month_number = 5 + GROUP BY t.calendar_month_number'; + no_of_msgs NUMBER; + i NUMBER; +BEGIN + dbms_mview.Explain_Rewrite(querytxt, 'MONTH_SALES_MV', Rewrite_Array); + no_of_msgs := rewrite_array.count; + FOR i IN 1..no_of_msgs + LOOP + DBMS_OUTPUT.PUT_LINE('>> MV_NAME : ' || Rewrite_Array(i).mv_name); + DBMS_OUTPUT.PUT_LINE('>> BEFORE VM: ' || Rewrite_Array(i).pass); + DBMS_OUTPUT.PUT_LINE('>> QUERY : ' || Rewrite_Array(i).query_text); + DBMS_OUTPUT.PUT_LINE('>> MESSAGE : ' || Rewrite_Array(i).message); + END LOOP; +END; +/ + +REM ----------------------------------------------------------------------------- +REM Test 7: Query rewrite is enabled +REM ----------------------------------------------------------------------------- + +REM Enable query rewrite and try the query again +ALTER SESSION SET QUERY_REWRITE_ENABLED = TRUE; + +SET SERVEROUTPUT ON; +DECLARE + Rewrite_Array SYS.RewriteArrayType := SYS.RewriteArrayType(); + querytxt VARCHAR2(1000) := 'SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE s.time_id = t.time_id AND + t.calendar_month_number = 5 + GROUP BY t.calendar_month_number'; + no_of_msgs NUMBER; + i NUMBER; +BEGIN + dbms_mview.Explain_Rewrite(querytxt, 'MONTH_SALES_MV', Rewrite_Array); + no_of_msgs := rewrite_array.count; + FOR i IN 1..no_of_msgs + LOOP + DBMS_OUTPUT.PUT_LINE('>> MV_NAME : ' || Rewrite_Array(i).mv_name); + DBMS_OUTPUT.PUT_LINE('>> BEFORE VM: ' || Rewrite_Array(i).pass); + DBMS_OUTPUT.PUT_LINE('>> QUERY : ' || Rewrite_Array(i).query_text); + DBMS_OUTPUT.PUT_LINE('>> MESSAGE : ' || Rewrite_Array(i).message); + END LOOP; +END; +/ + +REM ----------------------------------------------------------------------------- +REM Clean up +REM ----------------------------------------------------------------------------- + +DROP MATERIALIZED VIEW MONTH_SALES_MV; + +--------------------------------------------------------------------------------- +--- Following EXPLAIN_REWRITE() examples use a utility called SYS.XRW. This +--- utility helps the user to easily select the desired output fields from +--- EXPLAIN_REWRITE(). Since the output of EXPLAIN_REWRITE() consists of +--- many fields, this utility can be very helpful to the user. +--------------------------------------------------------------------------------- + +CONNECT sys/knl_test7 as sysdba; + +SET ECHO OFF; +--- Load the XRW utility +--- +@xrwutl; + +DROP user xrwdemo cascade; +CREATE user xrwdemo identified by xrwdemo; +GRANT connect, resource, dba to xrwdemo; +GRANT CREATE MATERIALIZED VIEW TO xrwdemo; +GRANT global query rewrite TO xrwdemo; + +CONNECT xrwdemo/xrwdemo; + +DROP TABLE FT; +CREATE TABLE FT (a1 INT, b1 INT, sales INT); + +DROP MATERIALIZED VIEW MV1; + +CREATE MATERIALIZED VIEW MV1 +ENABLE QUERY REWRITE AS +SELECT a1, b1, sum(sales) sum_sales +FROM FT +GROUP BY a1, b1; + + +-- Following query rewrites. Note the rewritten query text and query block number +-- +set serveroutput on size 999999 +DECLARE + querytxt VARCHAR2(1500) := 'SELECT a1, b1, SUM(sales) FROM FT GROUP BY a1, b1'; +BEGIN + SYS.XRW('', 'COSTS, QUERY_TXT, PASS, REWRITTEN_TXT, QUERY_BLOCK_NO', querytxt); +END; +/ + +DROP MATERIALIZED VIEW MV1; + +DROP TABLE FT; +CREATE TABLE FT (a1 INT, b1 INT, sales INT); + + +CREATE MATERIALIZED VIEW MV1 AS +SELECT a1, b1, sum(sales) sum_sales +FROM FT +GROUP BY a1, b1; + + +--- Rewrite is disabled for MV1. This query doesn't rewrite +set serveroutput on size 999999 +DECLARE + querytxt VARCHAR2(1500) := 'SELECT a1, b1, SUM(sales) FROM FT GROUP BY a1, b1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT', querytxt); +END; +/ + +--- Enable rewrite for MV1. It should rewrite now. + +DROP MATERIALIZED VIEW MV1; + +CREATE MATERIALIZED VIEW MV1 +ENABLE QUERY REWRITE AS +SELECT a1, b1, sum(sales) sum_sales +FROM FT +GROUP BY a1, b1; + +DECLARE + querytxt VARCHAR2(1500) := 'SELECT a1, b1, SUM(sales) FROM FT GROUP BY a1, b1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT', querytxt); +END; +/ + + +DROP TABLE FT; +CREATE TABLE FT (a1 INT, b1 INT, sales INT); + +DROP MATERIALIZED VIEW MV1; + +CREATE MATERIALIZED VIEW MV1 +ENABLE QUERY REWRITE AS +SELECT a1, b1, sum(sales) sum_sales +FROM FT +GROUP BY a1, b1; + +INSERT INTO FT VALUES (5, 5, 500); + + +-- Following query doesn't rewrite in ENFORCED mode +-- +set serveroutput on size 999999 +DECLARE + querytxt VARCHAR2(1500) := 'SELECT a1, b1, SUM(sales) FROM FT GROUP BY a1, b1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT', querytxt); +END; +/ + +drop table a; +drop table b; +drop table c; +drop table d; + +create table A(a1 int, a2 int, a3 int); +create table B(b1 int, b2 int, b3 int); +create table C(c1 int, c2 int, c3 int); +create table D(d1 int, d2 int, d3 int); + +ALTER TABLE b ADD CONSTRAINT pk_b PRIMARY KEY (b1); +ALTER TABLE C ADD CONSTRAINT PK_C PRIMARY KEY (c1); + +-- Make join between A and B lossless +ALTER TABLE A ADD CONSTRAINT fk_a FOREIGN KEY(a1) REFERENCES b(b1); +ALTER TABLE A MODIFY a1 NOT NULL; + +-- Make join between B and C lossless +ALTER TABLE B ADD CONSTRAINT fk_b FOREIGN KEY(b2) REFERENCES c(c1); +ALTER TABLE B MODIFY b2 NOT NULL; + +drop materialized view mv1; + +-- MV1: A--->B--->C +-- | +-- D + +create materialized view mv1 +enable query rewrite as +select a.a1, b.b1, sum(a.a3) as sum_a +from a, b, c, d +where a.a1 = b.b1 + and a.a2 = d.d2 + and b.b2 = c.c1 +group by a.a1, b.b1; + + +-- Query doesn't rewrite due to anchor table in the MV +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(1500) := 'select a.a1, b.b1, sum(a.a3) +from a, b, c +where a.a1 = b.b1 + and b.b2 = c.c1 +group by a.a1, b.b1'; +BEGIN + SYS.XRW('', '', querytxt); +END; +/ + +drop table a; +drop table b; +drop table c; + +create table A(a1 int, a2 int, a3 int); +create table B(b1 int, b2 int, b3 int); +create table C(c1 int, c2 int, c3 int); + +ALTER TABLE b ADD CONSTRAINT pk_b PRIMARY KEY (b1); + +-- Make join between A and B lossless +ALTER TABLE A ADD CONSTRAINT fk_a FOREIGN KEY(a1) REFERENCES b(b1); +ALTER TABLE A MODIFY a1 NOT NULL; + +drop materialized view mv1; + +-- MV1: A--->B +-- | +-- C + +create materialized view mv1 +enable query rewrite as +select a.a1, b.b1, c.c1, sum(a.a3) as sum_a +from a, b, c +where a.a1 = c.c1 and a.a1 = b.b1 +group by a1, b1, c1; + +-- should NOT rewrite as the MV delta has a lossy join + +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a.a1, b.b1, sum(a.a3) +from a, b +where a.a1 = b.b1 +group by a.a1, b.b1'; +BEGIN + SYS.XRW('', '', querytxt); +END; +/ + +drop table a; +drop table b; +drop table c; +drop table d; + +create table A(a1 int, a2 int, a3 int); +create table B(b1 int, b2 int, b3 int); +create table C(c1 int, c2 int, c3 int); +create table D(d1 int, d2 int, d3 int); + +ALTER TABLE b ADD CONSTRAINT pk_b PRIMARY KEY (b1); +ALTER TABLE C ADD CONSTRAINT PK_C PRIMARY KEY (c1); + +-- Make join between A and B lossless +ALTER TABLE A ADD CONSTRAINT fk_a FOREIGN KEY(a1) REFERENCES b(b1); +ALTER TABLE A MODIFY a1 NOT NULL; + +-- Make join between B and C lossless +ALTER TABLE B ADD CONSTRAINT fk_b FOREIGN KEY(b2) REFERENCES c(c1); +ALTER TABLE B MODIFY b2 NOT NULL; + +drop materialized view mv1; + +-- MV1: A--->B--->C +-- | +-- D + +drop materialized view mv1; + +create materialized view mv1 +enable query rewrite as +select a.a1, b.b1, sum(a.a3) as sum_a +from a, b, c, d +where a.a1 = b.b1 + and a.a2 = d.d2 + and b.b2 = c.c1 +group by a.a1, b.b1; + + +-- Doesn't rewrite due to join back failures +-- +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a.a1, b.b1, sum(a.a3) +from a, b, c, d +where a.a1 = b.b1 + and a.a2 = d.d2 + and b.b2 = c.c1 + and b.b3 = c.c2 +group by a.a1, b.b1'; +BEGIN + SYS.XRW('', '', querytxt); +END; +/ + +drop table a; +drop table b; +drop table c; +drop table d; + +create table A(a1 int, a2 int, a3 int); +create table B(b1 int, b2 int, b3 int); +create table C(c1 int, c2 int, c3 int); +create table D(d1 int, d2 int, d3 int); + +ALTER TABLE b ADD CONSTRAINT pk_b PRIMARY KEY (b1); +ALTER TABLE C ADD CONSTRAINT PK_C PRIMARY KEY (c1); + +-- Make join between A and B lossless +ALTER TABLE A ADD CONSTRAINT fk_a FOREIGN KEY(a1) REFERENCES b(b1); +ALTER TABLE A MODIFY a1 NOT NULL; + +-- Make join between B and C lossless +ALTER TABLE B ADD CONSTRAINT fk_b FOREIGN KEY(b2) REFERENCES c(c1); +ALTER TABLE B MODIFY b2 NOT NULL; + +drop materialized view mv1; + +-- MV1: A--->B--->C +-- | +-- D + +drop materialized view mv1; + +create materialized view mv1 +enable query rewrite as +select a.a1, b.b1, sum(a.a3) as sum_a +from a, b, c, d +where a.a1 = b.b1 + and a.a2 = d.d2 + and b.b2 = c.c1 + and b.b2 = c.c2 +group by a.a1, b.b1; + + +-- Does not rewrite due to a lossy join in the MV +-- +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a.a1, b.b1, sum(a.a3) +from a, b, c, d +where a.a1 = b.b1 + and a.a2 = d.d2 + and b.b2 = c.c1 + and b.b3 = c.c2 +group by a.a1, b.b1'; +BEGIN + SYS.XRW('', '', querytxt); +END; +/ + + + + +DROP TABLE FT1; +DROP MATERIALIZED VIEW NESTED_MV1; +DROP MATERIALIZED VIEW NESTED_MV2; +DROP MATERIALIZED VIEW NESTED_MV3; +DROP MATERIALIZED VIEW NESTED_MV4; +DROP MATERIALIZED VIEW NESTED_MV5; + +REM create a fact table, FT1, for nested MAV tests + +CREATE TABLE FT1 (akey INT, bkey INT, ckey INT, dkey INT, ekey INT, sales INT); + +REM CREATE NESTED_MV1 on fact + +CREATE MATERIALIZED VIEW NESTED_MV1 +ENABLE QUERY REWRITE +AS + SELECT akey, bkey, ckey, dkey, ekey, sum(sales) sum_sales + FROM FT1 + GROUP BY akey, bkey, ckey, dkey, ekey; + +REM create NESTED_MV2 on NESTED_MV1 + +CREATE MATERIALIZED VIEW NESTED_MV2 +AS + SELECT akey, bkey, ckey, dkey, sum(sum_sales) sum_sales2 + FROM NESTED_MV1 + GROUP BY akey, bkey, ckey, dkey; + +REM create NESTED_MV3 on NESTED_MV2 + +CREATE MATERIALIZED VIEW NESTED_MV3 +ENABLE QUERY REWRITE +AS + SELECT akey, bkey, ckey, sum(sum_sales2) sum_sales3 + FROM NESTED_MV2 + GROUP BY akey, bkey, ckey; + +REM create NESTED_MV4 on NESTED_MV3 + +CREATE MATERIALIZED VIEW NESTED_MV4 +ENABLE QUERY REWRITE +AS + SELECT akey, bkey, sum(sum_sales3) sum_sales4 + FROM NESTED_MV3 + GROUP BY akey, bkey; + +REM create NESTED_MV5 on NESTED_MV4 + +CREATE MATERIALIZED VIEW NESTED_MV5 +ENABLE QUERY REWRITE +AS + SELECT akey, sum(sum_sales4) sum_sales5 + FROM NESTED_MV4 + GROUP BY akey; + + +-- Doesn't Rewrite with NESTED_MV5 as NESTED_MV2 is not enabled yet + +set serveroutput on; + +DECLARE + querytxt VARCHAR2(100) := 'SELECT akey, sum(sales) FROM FT1 GROUP BY akey'; +BEGIN + SYS.XRW('', 'REWRITTEN_TXT', querytxt); +END; +/ + +alter materialized view nested_mv2 enable query rewrite; + + +--Rewrites with NESTED_MV5 now + +set serveroutput on; + +DECLARE + querytxt VARCHAR2(100) := 'SELECT akey, sum(sales) FROM FT1 GROUP BY akey'; +BEGIN + SYS.XRW('', 'REWRITTEN_TXT', querytxt); +END; +/ + + +DROP TABLE FT; +CREATE TABLE FT (f1 INT, f2 INT, s INT); + +DROP TABLE A; +CREATE TABLE A(a1 int, a2 int); + +DROP TABLE B; +CREATE TABLE B(b1 int); + +ALTER TABLE A ADD CONSTRAINT pk_a PRIMARY KEY (a1); +ALTER TABLE B ADD CONSTRAINT pk_b PRIMARY KEY (b1); + +ALTER TABLE FT ADD CONSTRAINT fk_ft_a FOREIGN KEY (f1) REFERENCES A(a1); +ALTER TABLE FT MODIFY (f1 NOT NULL) ; +ALTER TABLE FT ADD CONSTRAINT fk_ft_b FOREIGN KEY (f2) REFERENCES B(b1); +ALTER TABLE FT MODIFY (f2 NOT NULL); + +DROP MATERIALIZED VIEW MV1; + +CREATE MATERIALIZED VIEW MV1 +ENABLE QUERY REWRITE AS +SELECT f1, a1, sum(s) sum_s +FROM FT, A +WHERE FT.f1 = A.a1 +GROUP BY f1, a1; + +DROP MATERIALIZED VIEW MV2; + +CREATE MATERIALIZED VIEW MV2 +ENABLE QUERY REWRITE AS +SELECT f1, a1, b1, sum(s) sum_s +FROM FT, A, B +WHERE FT.f1 = A.a1 AND FT.f2 = B.b1 +GROUP BY f1, a1, b1; + +set serveroutput on; +DECLARE + querytxt VARCHAR2(100) := 'SELECT a1, SUM(s) +FROM FT, A +WHERE FT.f1 = A.a1 +GROUP BY a1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, COSTS', querytxt); +END; +/ + + +drop table a; +create table a(a1 int, s int); + +drop materialized view mv1; +create materialized view mv1 +enable query rewrite as +select a1, sum(s) sum_s +from a +WHERE a1 < 50 +group by a1; + +drop materialized view mv2; +create materialized view mv2 +enable query rewrite as +select a1, sum(s) sum_s +from a +WHERE a1 >= 50 +group by a1; + + +-- query doesn't rewrite as cost is more expensive than the +-- unrewritten query. +-- +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a1, sum(s) sum_s from a group by a1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, COSTS, QUERY_BLOCK_NO', querytxt); +END; +/ + + +--- Create MV3 such that it doesn't have SUM(s) in it. +-- +drop materialized view mv3; +create materialized view mv3 +enable query rewrite as +select a1, count(s) count_s +from a +WHERE a1 >= 50 +group by a1; + +-- rewrites with mv1 and mv2. +-- +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a1, sum(s) sum_s from a group by a1'; +BEGIN + SYS.XRW('MV3', 'QUERY_TXT, REWRITTEN_TXT, COSTS, QUERY_BLOCK_NO', querytxt); +END; +/ + + + +DROP TABLE A cascade constraints; +create table a(a1 int, a2 int, a3 int, s int); + +drop materialized view mv1; +create materialized view mv1 +enable query rewrite as +select a1, sum(s) +from a +group by a1; + + +-- query has an inline view which can be rewritten with MV1. Outer query +-- cannot be rewritten. Note the rewritten query and the query block numbers +-- + +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a_1, sum_s from (select a1 a_1, sum(s) sum_s from a group by a1) iv1'; +BEGIN + SYS.XRW('', 'COSTS, QUERY_TXT, PASS, REWRITTEN_TXT, QUERY_BLOCK_NO', + querytxt); +END; +/ + + + +DROP TABLE A cascade constraints; +create table a(a1 int, a2 int, a3 int, s int); + +DROP TABLE B cascade constraints; +create table b(b1 int, b2 int, b3 int, t int); + +drop materialized view mv1; +create materialized view mv1 +enable query rewrite as +select a1, b1, sum(s) +from a, b +group by a1, b1; + + +-- Note the query block numbers for the rewritten inline views. Inline view +-- IV1 gets rewritten using exact text match +-- + +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a_1, x_1, sum_s from (select a1 a_1, b1 b_1, sum(s) sum_s from a, b group by a1, b1) iv1, (select sum(s) sum_ss, a1 x_1 from a group by a1) iv2'; +BEGIN + SYS.XRW('', 'REWRITTEN_TXT, QUERY_BLOCK_NO', + querytxt); +END; +/ + + +-- Note the query block numbers for the rewritten inline views. Inline view +-- IV1 gets rewritten using exact text match and inline view IV3 gets +-- rewritten using general rewrite +-- + +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a_1, x_1, sum_s from (select a1 a_1, b1 b_1, sum(s) sum_s from a, b group by a1, b1) iv1, (select sum(s) sum_ss, a1 x_1 from a group by a1) iv2, (select a1 a_11, b1 b_11, sum(s) sum_sss from b, a group by b1, a1) iv3'; +BEGIN + SYS.XRW('', 'REWRITTEN_TXT, QUERY_BLOCK_NO', + querytxt); +END; +/ + + +DROP TABLE A CASCADE CONSTRAINTS; +DROP TABLE "A_small" CASCADE CONSTRAINTS; +DROP TABLE "A_SMALL" CASCADE CONSTRAINTS; +DROP TABLE B CASCADE CONSTRAINTS; +DROP TABLE C CASCADE CONSTRAINTS; +DROP TABLE D CASCADE CONSTRAINTS; + +CREATE TABLE A (a1 INTEGER, a2 INTEGER constraint nn_a2 not null, + a3 INTEGER, a4 INTEGER, a5 INTEGER); +CREATE TABLE "A_small" (a1 INTEGER, a2 INTEGER constraint small1_a2 not null, + a3 INTEGER, a4 INTEGER, a5 INTEGER, a6 varchar(30)); +CREATE TABLE "A_SMALL" (a1 INTEGER, a2 INTEGER constraint small2_a2 not null, + a3 INTEGER, a4 INTEGER, a5 INTEGER, a6 varchar(30)); +CREATE TABLE B (b1 INTEGER, b2 INTEGER, y INTEGER constraint nn_y not null, + g INTEGER, + h INTEGER); +CREATE TABLE C (c1 INTEGER, c2 INTEGER, c3 INTEGER, + c4 INTEGER); +CREATE TABLE D (d1 INTEGER, d2 INTEGER, d3 INTEGER, + d4 INTEGER); + +DROP MATERIALIZED VIEW inline_mv1; + +CREATE MATERIALIZED VIEW inline_mv1 +ENABLE QUERY REWRITE AS +SELECT A.a1, A.a2, SUM(V1.a3) as sum_s +FROM A, (SELECT * FROM A) V1 +WHERE A.a1 = V1.a1 +GROUP BY A.a1, A.a2; + + +DROP MATERIALIZED VIEW inline_mv3; + +CREATE MATERIALIZED VIEW inline_mv3 +ENABLE QUERY REWRITE AS +SELECT A.a1, A.a2, B.b1, SUM(V1.a3) as sum_s1, SUM(V2.b2) as sum_s2 +FROM A, B, (SELECT * FROM A) V1, (SELECT * FROM B) V2 +WHERE A.a1 = V1.a1 AND + A.a2 = B.b2 +GROUP BY A.a1, A.a2, B.b1; + + +DROP MATERIALIZED VIEW inline_mv4; + +--- MV has multiple inline views +CREATE MATERIALIZED VIEW inline_mv4 +ENABLE QUERY REWRITE AS +SELECT A.a1, A.a2, B.b1, SUM(V1.a3) as sum_s1, SUM(V2.b2) as sum_s2 +FROM A, B, (SELECT * FROM A) V1, (SELECT * FROM B) V2 +GROUP BY A.a1, A.a2, B.b1; + + +DROP MATERIALIZED VIEW inline_mv5; + +--- MV has multiple inline views +CREATE MATERIALIZED VIEW inline_mv5 +ENABLE QUERY REWRITE AS +SELECT A.a1, A.a2, B.b1, SUM(V1.a3) as sum_s1, SUM(V2.b2) as sum_s2 +FROM A, B, (SELECT * FROM A) V1, (SELECT * FROM B) V2 +WHERE (A.a1 = V1.a1) AND (B.b1 = V2.b2) +GROUP BY A.a1, A.a2, B.b1; + + +DROP MATERIALIZED VIEW INLINE_MV6; + +--- MV has multiple inline views, with joins +CREATE MATERIALIZED VIEW inline_mv6 +ENABLE QUERY REWRITE AS +SELECT A.a1, sum(V2.sum_v1) sum_v2 FROM +A, (SELECT A.a1, A.a2, SUM(V1.a3) as sum_v1 + FROM A, (SELECT * FROM A) V1 + GROUP BY A.a1, A.a2) V2 +WHERE (A.a2 = V2.a2) +GROUP BY A.a1; + + +DROP MATERIALIZED VIEW INLINE_MV7; + +--- MV has multiple inline views, with joins between views +CREATE MATERIALIZED VIEW inline_mv7 +ENABLE QUERY REWRITE AS +SELECT A.a1, sum(V2.sum_v1) sum_v2 FROM +A, (SELECT A.a1, A.a2, SUM(V1.a3) as sum_v1 + FROM A, (SELECT * FROM A) V1 + GROUP BY A.a1, A.a2) V2, + (SELECT B.b1, B.b2 FROM B) V3 +WHERE (V2.a1 = V3.b1) +GROUP BY A.a1; + + +DROP MATERIALIZED VIEW INLINE_MV8; + +--- MV has multiple inline views, with joins between views +CREATE MATERIALIZED VIEW inline_mv8 +ENABLE QUERY REWRITE AS +SELECT A.a1, sum(V2.sum_v1) sum_v2 FROM +A, (SELECT A.a1, A.a2, SUM(V1.a3) as sum_v1 + FROM A, (SELECT * FROM A) V1 + GROUP BY A.a1, A.a2) V2, + (SELECT B.b1, B.b2 FROM B) V3 +WHERE (V2.a1 = V3.b1) +GROUP BY A.a1; + + +DROP MATERIALIZED VIEW INLINE_MV9; + +--- MV has multiple inline views, but no joins +CREATE MATERIALIZED VIEW inline_mv9 +ENABLE QUERY REWRITE AS +SELECT A.a1, B.b1, v1.a2, SUM(V1.a3) as sum_s1 +FROM A, B, (SELECT * FROM A) V1, (SELECT * FROM B) V2 +WHERE A.a1 = V1.a1 AND + A.a2 = B.b2 +GROUP BY A.a1, B.b1, V1.a2; + + +DROP MATERIALIZED VIEW INLINE_MV10; + +CREATE MATERIALIZED VIEW inline_mv10 +ENABLE QUERY REWRITE AS +SELECT A.a1, B.b1, v3.a2, SUM(V3.a3) as sum_s1 +FROM A, B, (SELECT * FROM (SELECT * FROM A) V1) V3, (SELECT * FROM B) V2 +WHERE A.a1 = V3.a1 AND + A.a2 = B.b2 +GROUP BY A.a1, B.b1, V3.a2; + + +DROP MATERIALIZED VIEW INLINE_MV11; + +CREATE MATERIALIZED VIEW inline_mv11 +ENABLE QUERY REWRITE +AS +SELECT A.a1, B.b1, SUM(A.a1) as sum_a1, COUNT(A.a1) as cnt_a1 +FROM A, B, (SELECT a1, a2, SUM(a1) FROM A GROUP BY a1, a2) V1 +WHERE A.a1 = V1.a1 +GROUP BY A.a1, B.b1; + +DROP MATERIALIZED VIEW INLINE_MV_CASE1; +CREATE MATERIALIZED VIEW inline_mv_case1 +ENABLE QUERY REWRITE +AS +SELECT A.a1, A.a2, SUM(V1.a3) as sum_s +FROM A, (SeLeCT /*doen't matter ''""' comments */ + * FroM "A_small") V1 +WHERE A.a1 = V1.a1 +GROUP BY A.a1, A.a2; + +DROP MATERIALIZED VIEW INLINE_MV_CASE2; +CREATE MATERIALIZED VIEW inline_mv_case2 +ENABLE QUERY REWRITE +AS +SELECT A.a1, A.a2, SUM(V1.a3) as sum_s +FROM A, (SeLeCT * fROm "A_SMALL") V1 +WHERE A.a1 = V1.a1 +GROUP BY A.a1, A.a2; + +DROP MATERIALIZED VIEW INLINE_MV_CASE3; +CREATE MATERIALIZED VIEW inline_mv_case3 +ENABLE QUERY REWRITE +AS +SELECT A.a1, A.a2, SUM(V1.a3) as sum_s +FROM A, (SeLeCT * FroM "A_small" + where a6='small') V1 +WHERE A.a1 = V1.a1 +GROUP BY A.a1, A.a2; + + +-- +-- Rewrites with inline_mv_case2 +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a2, A.a1, SUM(V1.a3) FROM A, (SELECT * FROM A_small) V1 +WHERE V1.a1 = A.a1 +GROUP BY A.a2, A.a1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + + +-- +-- Rewrites with inline_mv_case3 +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a2, A.a1, SUM(V1.a3) as sum_s +FROM A, (SeLeCT * FroM "A_small" + where a6=''small'') V1 +WHERE A.a1 = V1.a1 +GROUP BY A.a1, A.a2'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + + +-- +-- Rewrites using exact text match +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a1, A.a2, SUM(V1.a3) FROM A, (SELECT * FROM A) V1 +WHERE A.a1 = V1.a1 +GROUP BY A.a1, A.a2'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + +-- +-- No full or partial text match possible. Rewrites with general rewrite +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a1, B.b1, SUM(V1.a3) as sum_s1, SUM(V2.b2) as sum_s2 +FROM A, B, (SELECT * FROM A) V1, (SELECT * FROM B) V2 +WHERE V1.a1 = A.a1 AND + B.b2 = A.a2 +GROUP BY A.a1, B.b1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + + +-- Query has multiple inline views. +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a1, A.a2, B.b1, SUM(V1.a3) as sum_s1, SUM(V2.b2) as sum_s2 +FROM A, B, (SELECT * FROM A) V1, (SELECT * FROM B) V2 +WHERE (A.a1 = V1.a1) AND (B.b1 = V2.b2) +GROUP BY A.a1, A.a2, B.b1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a1, B.b1, A.a2, SUM(V1.a3) as sum_s1, SUM(V2.b2) as sum_s2 +FROM A, B, (SELECT * FROM A) V1, (SELECT * FROM B) V2 +group BY A.a1, B.b1, A.a2'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + +-- +-- rewrites with multiple nested inline views +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a1, sum(V2.sum_v1) sum_v2 FROM +A, (SELECT A.a1, A.a2, SUM(V1.a3) as sum_v1 + FROM A, (SELECT * FROM A) V1 + GROUP BY A.a1, A.a2) V2 +WHERE (V2.a2 = A.a2) +GROUP BY A.a1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + + +-- +--- Different aliases used in query for inline views. Should rewrite with +--- inline_mv10 +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a1, VX.a2, SUM(VX.a3) as sum_s1 +FROM A, B, (SELECT * FROM (SELECT * FROM A) V1) VX, (SELECT * FROM B) VY +WHERE A.a1 = VX.a1 AND + B.b2 = A.a2 +GROUP BY A.a1, VX.a2'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + + +--- rewrites with inline_mv11 +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a1, AVG(A.a1) as avg_a1 +FROM A, B, (SELECT a1, a2, SUM(a1) FROM A GROUP BY a1, a2) V1 +WHERE V1.a1 = A.a1 +GROUP BY A.a1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + +connect sys/knl_test7 as sysdba; + +drop public synonym XRW; + +drop user xrwdemo cascade; + + +DISCONNECT; + + diff --git a/strmatREADME.txt b/strmatREADME.txt new file mode 100644 index 0000000..5904c07 --- /dev/null +++ b/strmatREADME.txt @@ -0,0 +1,79 @@ + +asynchronous trigger is composed of two parts. + +* strmats.sql sets up dictionary tables, types, and a package to implement + asynchronous trigger using streams. + +* strmatu.sql is an example that creates two row triggers and a table + trigger on table u1.accounts, recording any changes to user Alice's + balance. + +* archiving must be enabled in the database. + + Unlike traditional triggers, asynchronous triggers are created and dropped + by a PL/SQL API. The when clause and trigger body syntax are mostly the same, + with following exceptions: + + * value of the changed row will be referenced as old, new instead of + :old, :new. + + * attribute function inserting, updating, deleting will NOT work in + asynchronous triggers. Instead one should use + + bitand(dml_events, async_trig_pkg.on_insert) = async_trig_pkg.on_insert + bitand(dml_events, async_trig_pkg.on_update) = async_trig_pkg.on_update + bitand(dml_events, async_trig_pkg.on_delete) = async_trig_pkg.on_delete + + to identify inserting, updating, deleting events respectively. + + Package async_trig_pkg contains the following procedures: + + * set_up_streams() which sets up capture and apply for asynchronous triggers + * clean_up_streams() which cleans up streams capture apply, queue, etc. + * create_trigger() which creates an asynchronous trigger + * drop_trigger() which drops an asynchronous trigger + + LIMITATIONS: + + This package is just a prototype and has the following limitations. + + * Name canonicalization. It is assumed that all names passed to + async_trig_pkg APIs are ALREADY canonicalized. + + * Datatype support. The column type of the table on which asynchoronous + triggers are defined are limited to the following data types: + + NUMBER, FLOAT, VARCHAR2, RAW, DATE, TIMESTAMP. + + * ALTERATION. To alter a trigger one needs to drop and recreate it. + Same is the streams set up. + + * ERROR HANDLING. Because we are not inside the kernel, DDL operations + (set_up_streams, create_trigger etc.) are not strictly atomic. If an + operation raised an error for some reason, the asynchronous trigger + dictionary data might be left in an inconsistent state. In this case, + ORA-20001 (streams already exists) or ORA-20009 (trigger already + exists) will be raised when you retry the operation. + + drop_trigger operation can clean up the state of a failed create_trigger. + clean_up_streams can clean up the state of a failed set_up_streams. + + * SUPPLIMENTAL LOGGING. To be able to see unchanged column values in + an update asynchronous trigger, supplemental logging needed to be + turned on for that table. The asynchronous trigger script will not + turn on supplemental logging by default, because it can affect the + performance of the user DML txn. + + Most of the limitations could be amended given some more time. If any + of the above is not acceptable, please let me know. + + INSTRUCTIONS: + + -- create streams by calling set_up_streams() + -- create trigger on table of interest using create_trigger() + -- check that trigger is fired on DMLs of the table + -- drop unwanted triggers by drop_trigger() + -- clean_up_streams() will drop all asynchronous triggers, drop capture, + apply, queue, etc. + -- check async_trigger_usecase.sql for an example + -- report bugs and problems to wei.wang@oracle.com diff --git a/strmatp.sql b/strmatp.sql new file mode 100644 index 0000000..acfb993 --- /dev/null +++ b/strmatp.sql @@ -0,0 +1,753 @@ +create or replace package async_trig_pkg AUTHID CURRENT_USER AS + + on_insert constant binary_integer := 1; + on_update constant binary_integer := 2; + on_delete constant binary_integer := 4; + + /* set up catpure and apply parameters */ + procedure set_up_streams(capture_name IN varchar2, + apply_name IN varchar2); + + /* clean up capture and apply */ + procedure clean_up_streams; + + /* + * After trigger creation, the following procedure will be created for + * row triggers: + * procedure (lcr IN lcr$_row_record, + * dml_events IN binary_integer) IS + * old %rowtype; + * new %rowtype; + * BEGIN + * ... -- populate old and new values using lcr + * IF () THEN + * + * END IF; + * END; + * + * The IF ... THEN caluse will be omitted if when_clause is NULL. + * for table triggers, the following procedure will be created: + * + * procedure (dml_events IN binary_integer) IS + * BEGIN + * + * END; + * + * Table triggers will be called once per txn. + */ + + procedure create_trigger(trigger_owner IN varchar2, + trigger_name IN varchar2, + table_owner IN varchar2, + table_name IN varchar2, + dml_events IN binary_integer, + for_each_row IN boolean DEFAULT TRUE, + when_clause IN varchar2 DEFAULT NULL, + action IN varchar2); + + /* drop the asynchronous trigger */ + procedure drop_trigger(owner IN varchar2, + trigger_name IN varchar2); +end; +/ +show errors +/ +grant execute on async_trig_pkg to public +/ +create or replace public synonym async_trig_pkg for trgadm.async_trig_pkg +/ + +create or replace package async_trig_internal AS + + tabdml table_dml_list := table_dml_list(); + + procedure set_up_streams(capture_name IN varchar2, + apply_name IN varchar2); + + procedure clean_up_streams; + + + procedure create_trigger(trig_owner IN varchar2, + trig_name IN varchar2, + tab_owner IN varchar2, + tab_name IN varchar2, + dml_events IN binary_integer, + for_each_row IN boolean DEFAULT TRUE, + when_clause IN varchar2 DEFAULT NULL, + action IN varchar2); + + + procedure drop_trigger(trig_owner IN varchar2, + trig_name IN varchar2); + + procedure dml_handler(in_any IN ANYDATA); + + procedure commit_handler(scn IN number); + +end; +/ +show errors +/ + +create or replace package body async_trig_pkg as + procedure set_up_streams(capture_name IN varchar2, + apply_name IN varchar2) IS + cnt binary_integer; + BEGIN + select count(role) into cnt from session_roles where role = 'DBA'; + IF cnt > 0 THEN + async_trig_internal.set_up_streams(capture_name, apply_name); + + dbms_rule_adm.create_rule_set( + rule_set_name => 'TRGADM.ASYNC_TRIG_ARS', + evaluation_context => 'sys.streams$_evaluation_context'); + + dbms_capture_adm.create_capture(queue_name => 'TRGADM.ASYNC_TRIG_Q', + capture_name => capture_name); + + dbms_apply_adm.create_apply(queue_name => 'TRGADM.ASYNC_TRIG_Q', + apply_name => apply_name, + rule_set_name => 'TRGADM.ASYNC_TRIG_ARS', + apply_captured => TRUE); + dbms_apply_adm.set_parameter(apply_name, 'COMMIT_SERIALIZATION', 'FULL'); + ELSE + raise_application_error(-20002, + 'DBA role is required to set up asynchronous trigger streams'); + END IF; + END; + + procedure clean_up_streams IS + cnt binary_integer; + BEGIN + select count(role) into cnt from session_roles where role = 'DBA'; + IF cnt > 0 THEN + async_trig_internal.clean_up_streams; + ELSE + raise_application_error(-20003, + 'DBA role is required to clean up asynchronous trigger streams'); + END IF; + END; + + procedure create_trigger(trigger_owner IN varchar2, + trigger_name IN varchar2, + table_owner IN varchar2, + table_name IN varchar2, + dml_events IN binary_integer, + for_each_row IN boolean DEFAULT TRUE, + when_clause IN varchar2 DEFAULT NULL, + action IN varchar2) IS + cnt binary_integer; + trig_owner VARCHAR2(30); + tab_owner VARCHAR2(30); + tab_name VARCHAR2(30); + cur_user VARCHAR2(30); + BEGIN + + trig_owner := NVL(trigger_owner, USERENV('SCHEMAID')); + tab_owner := NVL(table_owner, USERENV('SCHEMAID')); + tab_name := table_name; + + -- check the existence of the underlying table + select count(1) into cnt from all_tables + where owner = tab_owner and table_name = tab_name; + + IF cnt = 0 THEN + raise_application_error(-20007, + 'Table "' || tab_owner || '"."' || tab_name || + ' does not exist'); + END IF; + + select username into cur_user from user_users; + + -- check current user's privilege to create the trigger + IF trig_owner = cur_user THEN + select count(privilege) into cnt from session_privs + where privilege = 'CREATE TRIGGER'; + ELSE + select count(privilege) into cnt from session_privs + where privilege = 'CREATE ANY TRIGGER'; + END IF; + + IF cnt > 0 THEN + async_trig_internal.create_trigger(trig_owner, trigger_name, + tab_owner, tab_name, + dml_events, for_each_row, when_clause, action); + ELSE + raise_application_error(-20004, + 'Insufficient privilege to create trigger "' || trigger_owner || + '"."' || trigger_name || '"'); + END IF; + END; + + + procedure drop_trigger(owner IN varchar2, + trigger_name IN varchar2) IS + cnt binary_integer; + cur_user VARCHAR2(30); + BEGIN + select username into cur_user from user_users; + + IF owner = cur_user THEN + cnt := 1; + ELSE + select count(privilege) into cnt from session_privs + where privilege = 'DROP ANY TRIGGER'; + END IF; + + IF cnt > 0 THEN + async_trig_internal.drop_trigger(owner, trigger_name); + ELSE + raise_application_error(-20005, + 'Insufficient privilege to drop trigger "' || owner || '"."' || + trigger_name); + END IF; + END; +end async_trig_pkg; +/ + +show errors +/ + +create or replace package body async_trig_internal as + + CRLF CONSTANT VARCHAR2(4) := ' +'; + on_insert constant binary_integer := async_trig_pkg.on_insert; + on_update constant binary_integer := async_trig_pkg.on_update; + on_delete constant binary_integer := async_trig_pkg.on_delete; + + procedure set_up_streams(capture_name IN varchar2, + apply_name IN varchar2) IS + cnt NUMBER; + BEGIN + select count(1) into cnt FROM props$; + IF cnt > 0 THEN + raise_application_error(-20001, + 'asynchronous trigger streams already exists.'); + END IF; + insert into props$ values (capture_name, apply_name, 'NOT STARTED'); + commit; + + dbms_streams_adm.set_up_queue( + queue_table => 'TRGADM.ASYNC_TRIG_QT', + queue_name => 'TRGADM.ASYNC_TRIG_Q'); + + END set_up_streams; + + PROCEDURE clean_up_streams IS + db varchar2(128); + capture_name VARCHAR2(30); + apply_name VARCHAR2(30); + apply_status VARCHAR2(30); + cursor tab_c is select unique table_owner, table_name + from async_trigger$; + cursor trig_c is select trigger_owner, trigger_name from async_trigger$; + owner_name VARCHAR2(65); + proc_does_not_exist EXCEPTION; + PRAGMA EXCEPTION_INIT(proc_does_not_exist, -26701); + + BEGIN + select global_name into db from global_name; + select trigger_capture, trigger_apply, trigger_apply_status into + capture_name, apply_name, apply_status from props$; + + IF apply_status = 'STARTED' THEN + -- stop capture and apply + dbms_capture_adm.stop_capture(capture_name); + dbms_apply_adm.stop_apply(apply_name); + + for t_rec in tab_c loop + owner_name := '"' || t_rec.table_owner || '"."' || t_rec.table_name || + '"'; + + -- remove dml handlers + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'INSERT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'UPDATE', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DELETE', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => db, + instantiation_scn => null); + end loop; + + -- remove capture and apply + BEGIN + dbms_apply_adm.drop_apply(apply_name, true); + dbms_capture_adm.drop_capture(capture_name, true); + EXCEPTION + WHEN proc_does_not_exist THEN + NULL; + WHEN others THEN + RAISE; + END; + + END IF; + + FOR g_rec in trig_c LOOP + execute immediate 'drop procedure "' || g_rec.trigger_owner || '"."' || + g_rec.trigger_name || '"'; + END LOOP; + + DELETE FROM async_trigger$; + DELETE FROM async_trigger_rule$; + DELETE FROM props$; + commit; + -- remove the queue ASYNC_TRIG_Q + dbms_streams_adm.remove_queue('ASYNC_TRIG_Q'); + + END clean_up_streams; + + -- for simplicity, all the necessary error condition checks and security + -- checks are omitted. + + PROCEDURE create_trigger(trig_owner IN varchar2, + trig_name IN varchar2, + tab_owner IN varchar2, + tab_name IN varchar2, + dml_events IN binary_integer, + for_each_row IN boolean DEFAULT TRUE, + when_clause IN varchar2 DEFAULT NULL, + action IN varchar2) IS + capture_name VARCHAR2(30); + apply_name VARCHAR2(30); + apply_status VARCHAR2(30); + stmt_buf VARCHAR2(20000); + flags NUMBER; + inst_scn number; + db varchar2(128); + cnt binary_integer; + full_name VARCHAR2(65); + dml_rule_c VARCHAR2(65); + ddl_rule_c VARCHAR2(65); + dml_rule_a VARCHAR2(65); + ddl_rule_a VARCHAR2(65); + + cursor col_c(tab_owner varchar2, tab_name varchar2) + IS select column_name, data_type from dba_tab_columns + where owner = tab_owner and table_name = tab_name; + BEGIN + + -- check whether trigger already exists + SELECT count(1) INTO cnt FROM async_trigger$ + WHERE trigger_owner = trig_owner and trigger_name = trig_name; + + IF cnt > 0 THEN + raise_application_error(-20009, + 'trigger ' || trig_owner || '.' || trig_name || 'already exists'); + END IF; + + full_name := '"' || tab_owner || '"."' || tab_name || '"'; + stmt_buf := 'CREATE PROCEDURE "' || trig_owner || '"."' || + trig_name; + + IF (not for_each_row) and when_clause IS NOT NULL THEN + raise_application_error(-20006, + 'table triggers cannot specify WHEN clause'); + END IF; + + IF for_each_row THEN + + stmt_buf := stmt_buf || + '" (lcr IN sys.lcr$_row_record, dml_events IN binary_integer) ' + || 'IS' || CRLF || ' old ' || full_name || '%rowtype; ' + || CRLF || ' new ' || full_name || '%rowtype; ' || CRLF || + ' rc NUMBER; ' || CRLF || + ' col_val SYS.ANYDATA; ' || CRLF || 'BEGIN' || CRLF ; + + -- now computes the old and new values for row triggers + stmt_buf := stmt_buf || + ' IF lcr.get_command_type() = ''INSERT'' THEN' || CRLF || + ' old := NULL; ' || CRLF || ' ELSE' || CRLF; + + FOR c_rec IN col_c(tab_owner, tab_name) LOOP + stmt_buf := stmt_buf || + ' col_val := lcr.get_value(''OLD'', ''' || + c_rec.column_name || ''');' || CRLF || + ' IF col_val IS NULL THEN ' || CRLF || + ' old.' || c_rec.column_name || ':= NULL; ' || CRLF || + ' ELSE ' || CRLF; + + IF c_rec.data_type = 'NUMBER' or c_rec.data_type = 'FLOAT' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETNUMBER(old.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'VARCHAR2' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETVARCHAR2(old.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'RAW' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETRAW(old.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'DATE' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETDATE(old.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'TIMESTAMP' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETTIMESTAMP(old.' || + c_rec.column_name ||'); ' || CRLF; + ELSE + raise_application_error(-20008, 'UNKNOWN data type'); + END IF; + + stmt_buf := stmt_buf || ' END IF; ' || CRLF; + END LOOP; + + stmt_buf := stmt_buf || ' END IF; ' || CRLF || + ' IF lcr.get_command_type() = ''DELETE'' THEN ' || CRLF || + ' new := NULL; ' || CRLF || ' ELSE' || CRLF; + + FOR c_rec IN col_c(tab_owner, tab_name) LOOP + stmt_buf := stmt_buf || + ' col_val := lcr.get_value(''NEW'', ''' || + c_rec.column_name || ''');' || CRLF || + ' IF col_val IS NULL THEN ' || CRLF || + ' new.' || c_rec.column_name || ':= NULL; ' || CRLF || + ' ELSE ' || CRLF; + + IF c_rec.data_type = 'NUMBER' or c_rec.data_type = 'FLOAT' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETNUMBER(new.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'VARCHAR2' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETVARCHAR2(new.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'RAW' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETRAW(new.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'DATE' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETDATE(new.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'TIMESTAMP' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETTIMESTAMP(new.' || + c_rec.column_name ||'); ' || CRLF; + ELSE + raise_application_error(-20008, 'UNKNOWN data type'); + END IF; + + stmt_buf := stmt_buf || ' END IF; ' || CRLF; + END LOOP; + + stmt_buf := stmt_buf || ' END IF; ' || CRLF; + + ELSE + stmt_buf := stmt_buf || + '" (dml_events IN binary_integer) IS' || CRLF || 'BEGIN' || + CRLF ; + END IF; + + IF (when_clause IS NOT NULL) THEN + stmt_buf := stmt_buf || ' IF ' || when_clause || ' THEN' || CRLF || + action || CRLF || ' END IF; ' || CRLF || 'END; '; + ELSE + stmt_buf := stmt_buf || action || CRLF || 'END; '; + END IF; + + -- create the trigger + execute immediate stmt_buf; + + -- insert into trigger table + IF for_each_row THEN + flags := 1; + ELSE + flags := 0; + END IF; + + insert into async_trigger$ values (tab_owner, tab_name, trig_owner, + trig_name, dml_events, flags); + commit; + + select trigger_capture, trigger_apply, trigger_apply_status into + capture_name, apply_name, apply_status from props$; + select global_name into db from global_name; + select count(*) into cnt from dba_apply_instantiated_objects + where source_object_owner = tab_owner and source_object_name = tab_name and + source_object_type = 'TABLE' and source_database = db; + + -- if table already has an instantiation scn registered, don't call + -- dbms_apply_adm.set_table_instantiation_scn() + + IF (cnt = 0) THEN + inst_scn := dbms_flashback.get_system_change_number(); + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => full_name, + source_database_name => db, + instantiation_scn => inst_scn); + END IF; + + -- as a simplification, add one rule per-table for all triggers + -- on the table + select count(1) into cnt from async_trigger_rule$ + where owner = tab_owner and table_name = tab_name; + + IF cnt = 0 THEN + dbms_streams_adm.add_table_rules( + table_name => full_name, + streams_type => 'apply', + streams_name => apply_name, + queue_name => 'TRGADM.ASYNC_TRIG_Q', + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + source_database => db, + dml_rule_name => dml_rule_a, + ddl_rule_name => ddl_rule_a); + + dbms_apply_adm.set_dml_handler( + object_name => full_name, + object_type => 'TABLE', + operation_name => 'INSERT', + error_handler => false, + user_procedure => 'trgadm.async_trig_internal.dml_handler', + apply_database_link => NULL, + apply_name => apply_name); + + dbms_apply_adm.set_dml_handler( + object_name => full_name, + object_type => 'TABLE', + operation_name => 'UPDATE', + error_handler => false, + user_procedure => 'trgadm.async_trig_internal.dml_handler', + apply_database_link => NULL, + apply_name => apply_name); + + dbms_apply_adm.set_dml_handler( + object_name => full_name, + object_type => 'TABLE', + operation_name => 'DELETE', + error_handler => false, + user_procedure => 'trgadm.async_trig_internal.dml_handler', + apply_database_link => NULL, + apply_name => apply_name); + + dbms_streams_adm.add_table_rules( + table_name => full_name, + streams_type => 'capture', + streams_name => capture_name, + queue_name => 'TRGADM.ASYNC_TRIG_Q', + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + dml_rule_name => dml_rule_c, + ddl_rule_name => ddl_rule_c, + inclusion_rule => true); + + insert into async_trigger_rule$ values (tab_owner, tab_name, dml_rule_c, + dml_rule_a); + commit; + END IF; + + IF (apply_status = 'NOT STARTED') THEN + -- start capture and apply + dbms_apply_adm.set_parameter(apply_name => apply_name, + parameter => 'disable_on_error', + value => 'n'); + dbms_apply_adm.alter_apply( + apply_name => apply_name, + precommit_handler => 'trgadm.async_trig_internal.commit_handler'); + + dbms_apply_adm.start_apply(apply_name => apply_name); + dbms_capture_adm.start_capture(capture_name => capture_name); + + UPDATE props$ set trigger_apply_status = 'STARTED' + where trigger_capture = capture_name; + COMMIT; + END IF; + + END; + + procedure drop_trigger(trig_owner IN varchar2, + trig_name IN varchar2) IS + d_table VARCHAR2(30); + dml_evts binary_integer; + cnt NUMBER; + capture_name VARCHAR2(30); + apply_name VARCHAR2(30); + dml_rule_c VARCHAR2(65); + dml_rule_a VARCHAR2(65); + full_name VARCHAR2(65); + tab_owner VARCHAR2(30); + ob_does_not_exist EXCEPTION; + PRAGMA EXCEPTION_INIT(ob_does_not_exist, -4043); + BEGIN + + select table_owner, table_name, dml_events + into tab_owner, d_table, dml_evts + from async_trigger$ + where trigger_owner = trig_owner and trigger_name = trig_name; + + delete from async_trigger$ + where trigger_owner = trig_owner and trigger_name = trig_name; + + select count(1) into cnt from async_trigger$ + where table_owner = tab_owner and table_name = d_table; + commit; + + BEGIN + execute immediate 'drop procedure "' || + trig_owner || '"."' ||trig_name|| '"'; + EXCEPTION + WHEN ob_does_not_exist THEN + NULL; + WHEN others THEN + RAISE; + END; + + -- cleanup DML handler when necessary + select trigger_capture, trigger_apply into capture_name, apply_name + from props$; + + IF cnt = 0 THEN + BEGIN + select capture_rule, apply_rule into dml_rule_c, dml_rule_a + from async_trigger_rule$ + where owner = tab_owner and table_name = d_table; + + dbms_streams_adm.remove_rule(rule_name => dml_rule_c, + streams_type => 'CAPTURE', + streams_name => capture_name); + + dbms_streams_adm.remove_rule(rule_name => dml_rule_a, + streams_type => 'APPLY', + streams_name => apply_name); + full_name := '"' || tab_owner || '"."' || d_table || '"'; + dbms_apply_adm.set_dml_handler( + object_name => full_name, + object_type => 'TABLE', + operation_name => 'INSERT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + + dbms_apply_adm.set_dml_handler( + object_name => full_name, + object_type => 'TABLE', + operation_name => 'UPDATE', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + + dbms_apply_adm.set_dml_handler( + object_name => full_name, + object_type => 'TABLE', + operation_name => 'DELETE', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + EXCEPTION + WHEN no_data_found THEN + NULL; + WHEN OTHERS THEN + RAISE; + END; + END IF; + END; + + PROCEDURE add_table_dml(tab_owner IN varchar2, + tab_name IN varchar2, + dml_evts IN binary_integer) IS + tab_found boolean; + BEGIN + tab_found := FALSE; + FOR i IN 1 .. tabdml.count LOOP + IF tabdml(i).owner = tab_owner and tabdml(i).table_name = tab_name and + tabdml(i).dml = dml_evts THEN + tab_found := TRUE; + EXIT; + END IF; + END LOOP; + + IF NOT tab_found THEN + tabdml.extend(1); + tabdml(tabdml.count) := table_dml(tab_owner, tab_name, dml_evts); + END IF; + END; + + PROCEDURE dml_handler(in_any IN ANYDATA) IS + lcr SYS.LCR$_ROW_RECORD; + rc PLS_INTEGER; + commnd varchar2(30); + dml_evts binary_integer; + flags binary_integer; + cursor trg_c(tab_owner varchar2, tab_name varchar2, evts number) + IS select trigger_owner, trigger_name + from trgadm.async_trigger$ + where table_owner = tab_owner and table_name = tab_name and + bitand(dml_events, evts) > 0 and flags = 1; + tab_owner VARCHAR2(30); + tab_name VARCHAR2(30); + BEGIN + -- get LCR info + rc := in_any.getobject(lcr); + + -- Fire row triggers + commnd := lcr.get_command_type(); + IF commnd = 'INSERT' THEN + dml_evts := on_insert; + ELSIF commnd = 'UPDATE' THEN + dml_evts := on_update; + ELSIF commnd = 'DELETE' THEN + dml_evts := on_delete; + ELSE + dml_evts := 0; + END IF; + + IF dml_evts > 0 THEN + tab_owner := lcr.get_object_owner(); + tab_name := lcr.get_object_name(); + + -- remember to fire table triggers in the commit handler + add_table_dml(tab_owner, tab_name, dml_evts); + + FOR t_rec IN trg_c(tab_owner, tab_name, dml_evts) LOOP + execute immediate 'begin "' || t_rec.trigger_owner || '"."' || + t_rec.trigger_name || '"(:1, :2); end;' using + lcr, dml_evts; + END LOOP; + END IF; + END; + + PROCEDURE commit_handler(scn IN number) IS + cursor trg_c(tab_owner varchar2, tab_name varchar2, evts number) + IS select trigger_owner, trigger_name + from trgadm.async_trigger$ + where table_owner = tab_owner and table_name = tab_name and + bitand(dml_events, evts) > 0 and flags = 0; + BEGIN + + -- fire table triggers here + FOR i in 1 .. tabdml.count LOOP + FOR t_rec IN trg_c(tabdml(i).owner, tabdml(i).table_name, + tabdml(i).dml) LOOP + execute immediate 'begin "' || t_rec.trigger_owner || '"."' || + t_rec.trigger_name || '"(:1); end;' using tabdml(i).dml; + END LOOP; + END LOOP; + + tabdml.delete; + END; + +end; +/ diff --git a/strmats.sql b/strmats.sql new file mode 100644 index 0000000..869b377 --- /dev/null +++ b/strmats.sql @@ -0,0 +1,60 @@ +connect sys/knl_test7 as sysdba +drop user trgadm cascade +/ +grant dba to trgadm identified by trgadm +/ +begin + dbms_streams_auth.grant_admin_privilege( + grantee => 'trgadm', + grant_privileges => true); +end; +/ +grant create any procedure to trgadm +/ +grant drop any procedure to trgadm +/ +grant execute any procedure to trgadm +/ +grant select on dba_tab_columns to trgadm +/ + +connect trgadm/trgadm + +create table async_trigger$ ( + table_owner VARCHAR2(30), + table_name VARCHAR2(30), + trigger_owner VARCHAR2(30), + trigger_name VARCHAR2(30), + dml_events NUMBER, + flags NUMBER) +/ + +create table async_trigger_rule$( + owner VARCHAR2(30), + table_name VARCHAR2(30), + capture_rule VARCHAR2(65), + apply_rule VARCHAR2(65)) + / + +create table props$ ( + trigger_capture VARCHAR2(30), + trigger_apply VARCHAR2(30), + trigger_apply_status VARCHAR2(30)) +/ + +create index async_trigger_i1 on async_trigger$(table_owner, table_name) +/ +create unique index async_trigger_i2 on async_trigger$(trigger_owner, +trigger_name) +/ + +create type table_dml IS object ( + owner varchar2(30), + table_name varchar2(30), + dml number) +/ + +create type table_dml_list is varray(1024) of table_dml +/ + +@@strmatp.sql diff --git a/strmatu.sql b/strmatu.sql new file mode 100644 index 0000000..b5d343f --- /dev/null +++ b/strmatu.sql @@ -0,0 +1,125 @@ +/* + ************* asynchronous commit-time trigger using Streams ************* + + This script creates two row triggers and a table trigger on + table u1.accounts, recording any changes to user Alice's balance. + +*/ + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +SET ECHO ON +connect sys/knl_test7 as sysdba; +grant connect, resource to u1 identified by u1; + +connect trgadm/trgadm +exec async_trig_pkg.set_up_streams('ACCOUNT_CAPTURE', 'ACCOUNT_APPLY'); + +connect u1/u1 +create table accounts(name varchar2(30), balance number); +create table account_history (event_name varchar2(30), + event_time timestamp, + name varchar2(30), + old_balance number, + new_balance number); + +DECLARE + trigger_action VARCHAR2(1000); +BEGIN + + -- first, create an insert trigger, for each row + trigger_action := 'INSERT INTO u1.account_history values (''INSERT'', ' || + 'SYSTIMESTAMP, new.name, NULL, new.balance); '; + async_trig_pkg.create_trigger(trigger_owner => 'U1', + trigger_name => 'ACCOUNT_TRIG1', + table_owner => 'U1', + table_name => 'ACCOUNTS', + dml_events => async_trig_pkg.on_insert, + for_each_row => TRUE, + when_clause => 'new.name = ''ALICE''', + action => trigger_action); + + -- then, create an update/delete trigger, for each row + trigger_action := 'IF bitand(dml_events, async_trig_pkg.on_update) = ' || + 'async_trig_pkg.on_update THEN ' || + 'INSERT INTO u1.account_history values (''UPDATE'', ' || + 'SYSTIMESTAMP, old.name, old.balance, new.balance); ' || + ' ELSE ' || + 'INSERT INTO u1.account_history values (''DELETE'', ' || + 'SYSTIMESTAMP, old.name, old.balance, NULL); ' || + ' END IF; '; + async_trig_pkg.create_trigger(trigger_owner => 'U1', + trigger_name => 'ACCOUNT_TRIG2', + table_owner => 'U1', + table_name => 'ACCOUNTS', + dml_events => async_trig_pkg.on_update + + async_trig_pkg.on_delete, + for_each_row => TRUE, + when_clause => 'old.name = ''ALICE''', + action => trigger_action); + + -- last, create an insert/update/delete table trigger + trigger_action := 'INSERT INTO u1.account_history values (''DML'', ' || + 'SYSTIMESTAMP, NULL, NULL, NULL); '; + async_trig_pkg.create_trigger(trigger_owner => 'U1', + trigger_name => 'ACCOUNT_TRIG3', + table_owner => 'U1', + table_name => 'ACCOUNTS', + dml_events => async_trig_pkg.on_update + + async_trig_pkg.on_insert + + async_trig_pkg.on_delete, + for_each_row => FALSE, + action => trigger_action); + +END; +/ + +insert into accounts values ('ALICE', 1000); +commit; + +update accounts set balance = 2000 where name = 'ALICE'; +commit; + +delete from accounts where name= 'ALICE'; +commit; + +insert into accounts values ('BOB', 500); +commit; + +connect system/manager +declare +scn number; +cscn number; +slept number := 0; +begin + + -- Get current scn + scn := dbms_flashback.get_system_change_number; + while (slept < 1200) loop + dbms_lock.sleep(15); + slept := slept + 15; + begin + select lwm_message_number into cscn from gv$streams_apply_coordinator + where apply_name = 'ACCOUNT_APPLY'; + exception + when no_data_found + then cscn := 0; + when others then raise; + end; + if cscn >= scn then + exit; + end if; + end loop; +end; +/ + +connect u1/u1 +select * from account_history order by event_name, event_time; + +connect trgadm/trgadm +exec async_trig_pkg.clean_up_streams; diff --git a/strmmon.c b/strmmon.c new file mode 100644 index 0000000..a884011 --- /dev/null +++ b/strmmon.c @@ -0,0 +1,3845 @@ +/* Copyright (c) 2004, 2008, Oracle. All rights reserved. */ + +/* + + NAME + strmmon.c - STReams MONitor : used for Streams diagnostics + + DESCRIPTION + used for Streams diagnostics + + NOTES + Serves as an example for simple queries to monitor Streams performance. + + MODIFIED (MM/DD/YY) + snalla 06/06/08 - turn off domain controller authentication + rmao 09/26/07 - bug 6367892, add event message of knlslmw + snalla 09/07/07 - lrglrf1 3095832 do not include unistd.h on win32 + platform - adding changes reverted from bpwang_lrg-1938240 + tianli 02/27/07 - lrg 2858006: variable "status" fix + yizhang 08/16/06 - Fix bug 5382689 + yizhang 04/07/06 - Fix bug 5118340. + yizhang 09/29/05 - Collect the time used in wait events for all stream + related processes. + narora 09/13/05 - code hygiene + narora 08/12/05 - add propagation bandwidth + narora 04/27/05 - bug 4334913: fix LOG stats + narora 03/31/05 - print memsize with M acronym + narora 03/18/05 - print streams pool size repeatedly + narora 03/14/05 - bug 4204079: add destination to check for old prop + narora 02/04/05 - bug 4164092: -sysdba option shouldn't coredump + sbalaram 10/06/04 - indicate backlogs, flow control + sbalaram 08/17/04 - sbalaram_streams_diagnostics + sbalaram 07/26/04 - enhancements + narora 11/18/03 - fix flushing to file + narora 09/12/03 - handle errors if the anydata queue doesn't have + any buffered enqueues + narora 09/12/03 - + +*/ + +/***************************************************************************** + + STRMMON - Streams Monitoring Program + ------------------------------------ + +Overview: +-------- +STRMMON is a monitoring tool focused on Oracle Streams. Using this +tool, database administrators get a quick overview of the Streams +activity occurring within a database. In a single line display, strmmon +reports information. The reporting interval and number of iterations to +display are configurable. + +Usage: +----- +There are 7 command line input parameters for STRMMON: interval, count, +user, passw, dbname, sysdba, long. The first 2 parameters (interval and count) +control the sampling rate and the amount of output. The next 4 +parameters specify the connect information to the particular Streams +database. Specifying the last parameter displays cumulative information +rather than rate information, which is printed by default. + +When the command "strmmon" is issued without any parameters, a usage +message is displayed: + +% strmmon + +Usage: strmmon -interval -count [-user ] + [-passw ] [-dbname ] [-sysdba] + [-long] + +Parameters: +---------- +-interval The interval in seconds at which STRMMON will monitor the + database. To specify that the sampling rate to be every 3 + seconds: + -interval 3 + This is a required parameter for strmmon. + +-count The number of iterations to monitor the Streams environment. + To specify 5 iterations, use the following: + -count 5 + This is a required parameter for strmmon. + +-user The schema name for logging into the database. Any schema name + can be specified. If the SYS schema is specified, additional + information is displayed. To specify the SYSTEM schema, use + -user SYSTEM + This parameter should not be specified if logging in as + "/ as sysdba" is desired. + -user is an optional parameter for strmmon. + +-passw The login password for the schema identified with the -user + clause. To specify the password for the SYSTEM schema, use + -passw oracle + This parameter should not be specified if logging in as + "/ as sysdba" is desired. + -passw is an optional parameter for strmmon. + +-dbname The connection information or service name from tnsnames.ora + for the specific database to be monitored. To specify the connect + information for the monitored database, use + -dbname ORCL.WORLD + This is an optional parameter for strmmon. + +-sysdba This flag indicates that the login role is SYSDBA. This optional + parameter is typically used with the SYS schema. To specify the + login role SYSDBA, use + -sysdba + When logging in as "/ as sysdba", the -user and -passw + parameters are not required. + +-long Indication to print a detailed report for capture, apply + and propagation. + -long is an optional parameter. + By default, only the capture, apply and propagation rates are + displayed. + + +Output: +------ +The strmmon output begins with a banner line identifying the program parameters +and database. This information is followed with a brief description of the +major components of the output display. An example of this identifying output +is shown below: + +% strmmon -interval 5 -count 5 -sysdba + +STREAMS Monitor, v 2.5 Copyright Oracle Corp. 2002, 2005. +Interval = 5, Count=5 + +Logon= @ ORACLE 11.1.0.2.0 + +Streams Pool Size = 152M + +LOG : +NET: +Cxxx: +MEM : % +PRxx: +Qx : +PSxx: +Axxx: +: flow control in effect +: potential bottleneck +AR: apply reader +AS(n): n number of apply server +: +xx->: database instance name + +The following example shows the identifying output for "-long" option. + +% strmmon -long -interval 5 -count 5 -sysdba + +STREAMS Monitor, v 2.5 Copyright Oracle Corp. 2002, 2005. +Interval = 5, Count=5 + +Logon= @ ORACLE 11.1.0.2.0 + +Streams Pool Size = 152M + +LOG : +NET: +Cxxx: +MEM : % +PRxx: / +Qx : / +PSxx: / +Axxx: +: flow control in effect +: potential bottleneck +AR: apply reader +AS(n): n number of apply servers +: +xx->: database instance name + + +Note: The information about the Streams Pool Size is displayed only for +database versions greater than or equal to 10gR1. The wait event percentages +for propagation receiver are displayed only for database version greater than +or equal to 10gR2. The wait event percentages for the rest components are +displayed only for database version greater than or equal to 10gR1. + + +After this initial information about the program, Strmmon produces a single +line of output representing the current status of Oracle Streams after the +requested interval for each iteration . For example, if strmmon is invoked with +"-interval 5 -count 5", a line of output will be displayed every 5 seconds. +After 5 lines have been displayed (25 seconds), the monitoring will end. + +Each line is composed of multiple blocks of information dependent on the +Streams processes configured within the database. These blocks are displayed +by a keyword to identify the component followed by the statistics for that +particular component. The separator between the components is the "|" symbol. + +There are 6 components for Streams: LOG, Cxxx, Qx, PSxx, PRxx, Axxx. +Except for the LOG component, multiple occurrences of each component are +possible dependent on the streams processes configured at database. + + +LOG + +Information about the redo log activity is written in this block. The statistic +following the LOG: keyword gives the redo generated per second. If the "-long" +option is specified, then the first statistic following the LOG: keyword is the +current SCN that has been written to the redo log. This number represents the +current activity within the database. If this number does not increase, no +activity is occurring on the database. The second statistic is the last block +number written in the redo log. Redo blocks are always 512 bytes, so this +statistic can be used to calculate the amount of redo generated between +intervals. The output for the LOG component is always the first entry after the +timestamp on the display and appears as follows: + +2006-10-27 11:48:55 | LOG 440569 325388 +2006-10-27 11:49:00 | LOG 440609 325389 +2006-10-27 11:49:05 | LOG 440650 325391 +2006-10-27 11:49:10 | LOG 440691 325393 +2006-10-27 11:49:15 | LOG 440732 325395 + +In the above example, the current scn written to the redo log is 440569 and +the last block number is 325388. Since the strmmon command was issued with +-interval 5 -count 5, 5 lines of output are displayed with a 5 second interval +between them. + + +Cxxx + +For each capture process configured in the database, a separate block will be +displayed. Each block displays the number of lcrs captured per sec, number of +lcrs enqueued per sec and the capture latency. If "-long" option is specified, +then in each block, the Logminer read scn, the total number of messages +captured from the redo log and the most recent scn captured from the redo log +are shown. In addition, the number of messages that match the rules specified +for the capture process including the most recent message scn enqueued are +shown along with the capture latency. + +One can also use the difference between successive capture "messages captured" +statistics to determine the rate at which capture is mining the redo log. The +enqueue scn of capture is an indicator of where the capture process will +restart, if capture is stopped and restarted while the database is running. +This statistic can also be used for comparison with the appropriate database +Apply process high-water mark scn. If these statistics match, the capture and +apply are caught up and the data is synchronized. + +It lists the percentage of idle events, flow control events, and one of the +most significant wait event for the capture process if the database version +is 10gR1 or higher. + +MEM + +If strmmon is run from the SYS schema connected as SYSDBA, and the +database version is 10gR1 or higher, then this displays the percentage +of Streams Pool memory currently in use and the total size of the +streams pool. + + +Qx + +For each streams queue in the database, a seperate block displays the +queue identifier, the cummulative message rate and the spill rate. If +"-long" option is specified, then for each streams queue in the +database, a separate block will display the queue identifier as well +as the number of outstanding messages in the buffered queue, the +cumulative number of messages that have been in the queue and the +number of messages spilled from memory to disk. In version 9iR2, the +number of messages currently spilled is displayed. In 10gR1, the +cumulative number of messages spilled is displayed. For 9iR2, the +default and the "-long" option display the same data. + +The queue identifier (QID) can be used to identify the name of the +queue. Use the QID in queries against the DBA_QUEUES view to identify +the particular queue in the database. In 9i, the number of outstanding +messages in the buffered queue is only displayed if strmmon is run +from the SYS schema as SYSDBA. In 9iR2, if the number of spilled +messages becomes non-zero, consider stopping capture temporarily to +slow down the flow of data. + +PSxx + +For each propagation sender, the number of lcrs propagated per sec is +displayed. If "-long" option is specified, then for each propagation, +the total number of messages and the total number of bytes propagated to +the destination site and the total time needed to propagate those messages +is displayed. + +It lists the percentage of idle events, flow control events, and one of the +most significant wait event for the propagation sender process if the +database version is 10gR2 or higher. + +PRxx + +For each propagation receiver, the number of messages received per sec is +displayed. If "-long" option is specified, then for each propagation, +the total number of messages received and the total time needed to receive +those messages is displayed. + +It lists the percentage of idle events, flow control events, and one of the +most significant wait event for the propagation receiver process if the +database version is 10gR1 or higher. + +Axxx + +For each apply process, the number of lcrs dequeued per sec and the dequeue +latency are displayed. If the "-long" option is specified, then for each +apply process in the database, in addition to the total messages dequeued +and the most recent scn dequeued by the apply reader, the dequeue latency, the +total number of transactions received, assigned and applied by the coordinator +are displayed. The apply high water mark scn along with the apply high water +mark latency is also shown. This statistic records the most recent scn from +the source site that has been applied at the destination site. + +It lists the percentage of idle events, flow control events, and one of the +most significant wait event for the apply reader process and the apply server +processes if the database version is 10gR1 or higher. + + + +This indicates that the capture process is blocked due to flow control. + + + +This indicates that the capture or apply process is currently a bottleneck. + +xx-> + +This indicates the name of the database instance for which the data follows. + + +Installation: +------------ +Before compiling and linking the strmmon program, make sure that the +ORACLE_HOME and LD_LIBRARY_PATH environmental variables are set up +appropriately. First delete any old executable, and then compile and link: + + rm -f strmmon strmmon.o; make -f demo_rdbms.mk strmmon + +After the program has been compiled and linked, strmmon can be used for +monitoring a Streams environment. + +******************************************************************************/ + +/* for WINDOWS compatibility of 'sleep' call */ +#if defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32) +#include +#define sleep(x) Sleep(1000*(x)) +#endif + +/* for WINDOWS compatibility of 'strncasecmp' call */ +#if defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32) +#define strncasecmp strnicmp +#endif + +#ifndef ORATYPES +#include +#endif + +#ifndef _STDIO_H +#include +#endif + +#ifndef _STDLIB_H +#include +#endif + +#ifndef _STRING_H +#include +#endif + +#ifndef _SYS_TYPES_H +#include +#endif + +#ifndef _TIME_H +#include +#endif + +#if !(defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32)) +#ifndef _UNISTD_H +#include +#endif +#endif + +#ifndef _SIGNAL_H +#include +#endif + +#ifndef OCI_ORACLE +#include +#endif + +#define VERSION_9iR2 92020 +#define VERSION_10g 101010 +#define VERSION_10gR2 102000 + +typedef enum process_type + {CAPTURE_PROCESS=1, PR_SENDER_PROCESS=2, + PR_RECEIVER_PROCESS=3, APPLY_READER=4, APPLY_SERVER=5} + process_type_t; + +/*STREAMS capture process waiting for archive log + *and wait for transaction are the idle events for 10.1 version + */ +static const char* capture_idle_events = + {"|LogMiner: client waiting for transaction||events in waitclass Other||Streams capture: waiting for archive log||wait for transaction||STREAMS capture process waiting for archive log|"}; + /*"LogMiner: wakeup event for builder", + "LogMiner: wakeup event for preparer" */ + +/* waiting for subscribers to catch up is the flowcontrol event for 10.1 + * version. Rest events are for 10.2 and above. */ +static const char* capture_flowcontrol_events = + {"|Streams capture: waiting for subscribers to catch up||Streams capture: resolve low memory condition||Streams: resolve low memory condition||waiting for subscribers to catch up|"}; + +static const char* propagation_sender_idle_events = + {"|wait for unread message on broadcast channel||jobq slave wait|"}; + +static const char* propagation_sender_flowcontrol_events = + {"|SQL*Net more data to dblink||SQL*Net message from dblink|"}; + +static const char* propagation_receiver_idle_events = + {"|SQL*Net more data from client||SQL*Net message from client||Streams AQ: qmn slave idle wait|"}; + +static const char* propagation_receiver_flowcontrol_events = + { "|Streams AQ: enqueue blocked on low memory||Streams AQ: enqueue blocked due to flow control|"}; + +/*queue messages & knlqdeq is the idle wait events for 10.1 version*/ +static const char* apply_reader_idle_events = + {"|Streams AQ: waiting for messages in the queue||queue messages||knlqdeq|"}; + +static const char* apply_reader_flowcontrol_events = + {"|rdbms ipc message|"}; + +static const char* apply_server_idle_events = + {"|rdbms ipc message|"}; + +static const char* apply_server_flowcontrol_events = + {"||"}; + +typedef struct options +{ + ub4 interval; + ub4 elapstim; /* The elape time in one-hundredth of second */ + ub4 count; + ub4 iters; + ub1 short_opt; +} options_t; + +typedef struct oci +{ + OCIEnv * envp; + OCIError * errp; + OCIServer * srvp; + OCISvcCtx * svcp; + OCISession * authp; + OCIStmt * stmtp; + OCIStmt * stmt2p; + OCIStmt * stmt3p; + struct oci *nxt_oci; +} oci_t; + +typedef struct sid_pval +{ + ub4 sid; + void * pval; + process_type_t type; + struct sid_pval *next; +} sid_pval_t; + +typedef struct event_pval +{ + /* For apply server, it contains the number of apply server process. + For other process, it is the sid of that process. */ + ub4 sidnum; + oratext event_name[128]; + ub2 event_namelen; + ub4 iters; + ub8 time_in_micro_second; + ub8 time_in_micro_second_old; + struct event_pval *next_event; +} event_pval_t; + +typedef struct cap_pval +{ + ub4 capturenum; + oratext capturename[128]; + ub2 capturenamelen; + OCINumber read_scn; + ub4 total_captured; + ub4 total_enqueued; + ub4 elapsed_pause_time; + boolean flow_ctrl; + struct event_pval *pevent; + struct cap_pval *next_cap; +} cap_pval_t; + +typedef struct app_pval +{ + ub4 applynum; + oratext applyname[128]; + ub2 applynamelen; + ub4 total_applied; + ub4 txns_applied; + struct event_pval *pevent_reader; + struct event_pval *pevent_server; + struct app_pval *next_app; + ub4 server_num; +} app_pval_t; + +typedef struct prop_pval +{ + ub4 src_queueid; + ub4 dst_queueid; + oratext src_queuename[30]; + ub2 src_queuenamelen; + oratext src_schemaname[30]; + ub2 src_schemanamelen; + oratext src_dbname[128]; + ub2 src_dbnamelen; + oratext dst_queuename[30]; + ub2 dst_queuenamelen; + oratext dst_schemaname[30]; + ub2 dst_schemanamelen; + oratext dst_dbname[128]; + ub2 dst_dbnamelen; + char *destination[128]; + ub2 destination_len; + ub4 total_number; + ub8 total_bytes; + struct event_pval *pevent_sender; + struct event_pval *pevent_receiver; + struct prop_pval *next_prop; +} prop_pval_t; + +typedef struct que_pval +{ + ub4 queueid; + ub4 cnummsgs; + ub4 cspillmsgs; + struct que_pval *next_que; +} que_pval_t; + +typedef struct connection +{ + oratext * user; + ub4 userlen; + oratext * passw; + ub4 passwlen; + oratext * dbname; + ub4 dbnamelen; + oratext instname[128]; + ub2 instnamelen; + oratext versionstr[20]; + ub2 versionstrlen; + ub4 version; + ub1 sysdba; + ub1 sysuser; + + struct connection * next_connection; + + oci_t *ocip; + cap_pval_t *cap_pval; + app_pval_t *app_pval; + que_pval_t *que_pval; + prop_pval_t *prop_pval; + sid_pval_t *sid_pval; + ub4 num_sid; + ub4 org_sid; + ub4 lgwr_pval; + ub8 client_bytes; + ub8 dblink_bytes; + char sidstr[2048]; +} connection_t; + +typedef struct queue +{ + ub4 queueid; + oratext queuename[128]; + ub2 queuenamelen; + oratext schemaname[128]; + ub2 schemanamelen; + ub4 cnummsgs; + ub4 cspillmsgs; + ub4 nummsgs; +} queue_t; + +#define OCICALL(ocip, function) do {\ +sword status=function;\ +if (OCI_SUCCESS==status) break;\ +else if (OCI_SUCCESS_WITH_INFO==status) \ +{puts((char *)"Error: OCI_SUCCESS_WITH_INFO");\ +exit(1);}\ +else if (OCI_NEED_DATA==status) \ +{puts((char *)"Error: OCI_NEED_DATA");\ +exit(1);}\ +else if (OCI_NO_DATA==status) \ +{puts((char *)"Error: OCI_NO_DATA");\ +exit(1);}\ +else if (OCI_ERROR==status) \ +{ocierror(ocip, (char *)"OCI_ERROR", TRUE);\ +exit(1);}\ +else if (OCI_INVALID_HANDLE==status) \ +{puts((char *)"Error: OCI_INVALID_HANDLE");\ +exit(1);}\ +else if (OCI_STILL_EXECUTING==status) \ +{puts((char *)"Error: OCI_STILL_EXECUTING");\ +exit(1);}\ +else if (OCI_CONTINUE==status) \ +{puts((char *)"Error: OCI_CONTINUE");\ +exit(1);}\ +else {printf("Error: unknown status %d\n", status);\ +exit(1);}\ +} while(0) + + +static void get_options(options_t * opts, connection_t ** first_conn, int argc, + char ** argv); +static void print_usage(int exitcode); +static void oraconnect(options_t * opts, connection_t * connp); +static void oradisconnect(oci_t * ocip); +static void ocierror(oci_t * ocip, char * msg, boolean stop_on_error); +static void print_header(options_t * opts, connection_t * connp); +static void print_stats(options_t * opts, connection_t * connp); +static void print_capture_stats(options_t * opts, connection_t * connp, + oci_t * ocip, cap_pval_t ** cap_pval); +static void print_short_capture_stats(options_t * opts, + connection_t * connp, oci_t * ocip, cap_pval_t ** cap_pval); +static void print_queue9i_stats(options_t * opts, connection_t * connp, + oci_t * ocip, prop_pval_t ** prop_pval); +static void print_queue_stats(options_t * opts, connection_t * connp, + oci_t * ocip, que_pval_t ** que_pval, prop_pval_t ** prop_pval); +static void print_prop_receiver_stats(options_t * opts, connection_t * connp, + oci_t * ocip, queue_t* que, + prop_pval_t ** prop_pval, + unsigned *pnum_ptr); +static void print_prop_sender_stats(options_t * opts, connection_t * connp, + oci_t * ocip, ub4 queueid, + prop_pval_t ** prop_pval, + unsigned *pnum_ptr); +static void print_apply_stats(options_t * opts, connection_t * connp, + oci_t * ocip, app_pval_t ** app_pval); +static void print_short_apply_stats(options_t * opts, connection_t * connp, + oci_t * ocip, app_pval_t ** app_pval); +static void get_version(connection_t * connp); +static void print_log_stats(options_t * opts, oci_t * ocip, ub4 *lgwr_pval); +static void print_net_stats(options_t * opts, connection_t * connp); +static void print_pool_size(oci_t * ocip); +static void print_mem_stats(options_t * opts, oci_t * ocip); +static void print_latency(sb4 latency); +static void print_bytes(ub8 bytes); +static void collect_event_data (options_t * opts, connection_t * connp); +static void print_event_stats(options_t * opts, void* pval, process_type_t type); + +int main(int argc, char ** argv) +{ + options_t opts; + connection_t *first_conn = (connection_t *)NULL; + connection_t *cur_conn; + time_t ptim = 0; + time_t tim; + struct tm * ltime; + + /* store the command line arguments */ + get_options(&opts, &first_conn, argc, argv); + + /* initialize each connection */ + for (cur_conn = first_conn; + cur_conn != (connection_t *)NULL; + cur_conn = cur_conn->next_connection) + { + /* connect to the database */ + oraconnect(&opts, cur_conn); + + /* get the version of ORACLE for current database */ + get_version(cur_conn); + + /* print header for current database */ + print_header(&opts, cur_conn); + + /* Set the number of sids to 0 */ + cur_conn->num_sid = 0; + cur_conn->org_sid = 0; + } + + opts.elapstim = opts.interval * 100; + + for (opts.iters = 0; opts.iters < opts.count; opts.iters++) + { + if (opts.iters) { + sleep(opts.interval); + } + + tim = time(NULL); + ltime = localtime(&tim); + + /* first print the current time */ + printf("%d-%02d-%d %02d:%02d:%02d", + (ltime->tm_year)+1900, (ltime->tm_mon)+1, ltime->tm_mday, + ltime->tm_hour, ltime->tm_min, ltime->tm_sec); + + /* don't sleep in the first iteration */ + if (opts.iters) { + opts.elapstim = (ub4)(difftime(tim, ptim) * 100); + } + + ptim = tim; + + for (cur_conn = first_conn; + cur_conn != (connection_t *)NULL; + cur_conn = cur_conn->next_connection) + { + /* print stats for current database */ + printf(" || %.*s->", cur_conn->instnamelen, cur_conn->instname); + print_stats(&opts, cur_conn); + } + + /* flush the current line of output */ + fprintf(stdout, "\n"); + fflush(stdout); + } + + for (cur_conn = first_conn; + cur_conn != (connection_t *)NULL; + cur_conn = cur_conn->next_connection) + { + oradisconnect(cur_conn->ocip); + } + + return 0; +} + +static void ocierror(oci_t * ocip, char * msg, boolean stop_on_error) +{ + sb4 errcode=0; + text bufp[4096]; + + if (ocip->errp) + { + OCIErrorGet((void *) ocip->errp, (ub4) 1, (text *) NULL, &errcode, + bufp, (ub4) 4096, (ub4) OCI_HTYPE_ERROR); + printf("%s: %s", msg, bufp); + } + else + puts(msg); + + if (stop_on_error) + exit(1); +} + +static void get_options(options_t * opts, connection_t ** first_conn, int argc, + char ** argv) +{ + char * option; + char * value; + connection_t *cur_connection = NULL; + connection_t *new_connection = NULL; + connection_t *prev_connection = NULL; + + /* clear the options */ + memset(opts, 0, sizeof(*opts)); + + /* The default option is the short option */ + opts->short_opt = 1; + + if (argc == 1) + { + print_usage(0); + } + + while(--argc) + { + /* get the option name */ + argv++; + option = *argv; + + /* check that the option begins with a "-" */ + if (!strncmp(option, (char *)"-", 1)) + { + option ++; + } + else + { + printf("Error: bad argument %s\n", option); + exit(1); + } + + /* check if its a boolean option */ + if (!strncmp(option, (char *)"sysdba", 6)) + { + if (!cur_connection) + { + /* allocate and clear a new connection options parameter */ + cur_connection = (connection_t *)malloc(sizeof(connection_t)); + memset(cur_connection, 0, sizeof(connection_t)); + /* for a blank username password a single byte user password still + * needs to be given */ + cur_connection->user = (oratext *)" "; + cur_connection->userlen = 1; + cur_connection->passw = (oratext *)" "; + cur_connection->passwlen = 1; + + if (*first_conn == (connection_t *) NULL) + { + *first_conn = cur_connection; + } + else + { + prev_connection->next_connection = cur_connection; + } + } + cur_connection->sysdba = 1; + /* sysdba is the last option for a connection */ + prev_connection = cur_connection; + cur_connection = (connection_t *)0; + + continue; + } + + if (!strncmp(option, (char *)"long", 4)) + { + opts->short_opt = 0; + continue; + } + + /* get the value of the option */ + --argc; + argv++; + if (!argc) + { + printf("Error: option '%s' needs a value\n", option); + exit(1); + } + value = *argv; + + if (!strncmp(option, (char *)"int", 3)) + { + opts->interval = (ub4) atol(value); + if (!opts->interval) + { + printf("Error: interval must be +ve\n"); + } + } + else if (!strncmp(option, (char *)"count", 5)) + { + opts->count = (ub4) atol(value); + if (!opts->count) + { + printf("Error: count must be +ve\n"); + } + } + else if (!strncmp(option, (char *)"user", 4)) + { + for (cur_connection = *first_conn; + cur_connection != (connection_t *)NULL; + cur_connection = cur_connection->next_connection) + prev_connection = cur_connection; + ; + new_connection = (connection_t *)malloc(sizeof(connection_t)); + memset(new_connection, 0, sizeof(connection_t)); + new_connection->user = (oratext *)value; + new_connection->userlen = strlen(value); + new_connection->next_connection = (connection_t *)NULL; + cur_connection = new_connection; + + if (*first_conn == (connection_t *) NULL) + { + *first_conn = new_connection; + } + else + { + prev_connection->next_connection = new_connection; + } + } + else if (!strncmp(option, (char *)"passw", 5)) + { + if (!cur_connection) + { + print_usage(1); + } + else + { + cur_connection->passw = (oratext *)value; + cur_connection->passwlen = strlen(value); + } + } + else if (!strncmp(option, (char *)"dbname", 6)) + { + if (!cur_connection) + { + print_usage(1); + } + else + { + cur_connection->dbname = (oratext *)value; + cur_connection->dbnamelen = strlen(value); + } + } + else + { + printf("Error: unknown option %s\n", option); + exit(1); + } + } + + if (!opts->interval || !opts->count) + { + print_usage(1); + } + + /* for each connection set the "sysuser" flag if either + * the username is SYS + * or + * the connection is made AS SYSDBA + */ + for (cur_connection = *first_conn; + cur_connection != (connection_t *)NULL; + cur_connection = cur_connection->next_connection) + { + if (cur_connection->sysdba || + (!strncasecmp((char *)cur_connection->user,(char *)"SYS",3) && + (cur_connection->userlen==3))) + { + cur_connection->sysuser = 1; + } + } + + /* + if (!opts->userlen) + { + opts->userlen = 1; + opts->user=(oratext *)" "; + } + if (!opts->passwlen) + { + opts->passwlen = 1; + opts->passw= (oratext *)" "; + } + */ +} + +static void print_usage(int exitcode) +{ + puts((char *)"Usage: strmmon -interval -count " + " [-user ]" + "\n" + " [-passw ] [-dbname ] [-sysdba]" + "\n" + " [-long]" + "\n"); + + exit(exitcode); +} + +static void oraconnect(options_t * opts, connection_t * connp) +{ + oci_t * ocip = connp->ocip = (oci_t *)malloc(sizeof(oci_t)); + + if (OCIEnvCreate(&ocip->envp, OCI_OBJECT, (void *)0, + (void * (*)(void *, size_t)) 0, + (void * (*)(void *, void *, size_t))0, + (void (*)(void *, void *)) 0, + (size_t) 0, (void **) 0 )) + { + ocierror(ocip, (char *)"OCIEnvCreate() failed", TRUE); + } + + if (OCIHandleAlloc((void *) ocip->envp, (void **) &ocip->errp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (void **) 0)) + { + ocierror(ocip, (char *)"OCIHandleAlloc(OCI_HTYPE_ERROR) failed", TRUE); + } + + /* allocate the server handle */ + OCICALL(ocip, + OCIHandleAlloc((void *) ocip->envp, (void **) &ocip->srvp, + OCI_HTYPE_SERVER, (size_t) 0, (void **) 0)); + + /* create a server context */ + OCICALL(ocip, + OCIServerAttach (ocip->srvp, ocip->errp, connp->dbname, + (sb4)connp->dbnamelen, OCI_DEFAULT)); + + /* allocate the service handle */ + OCICALL(ocip, + OCIHandleAlloc((void *) ocip->envp, (void **) &ocip->svcp, + OCI_HTYPE_SVCCTX, (size_t) 0, (void **) 0)); + + /* set attribute server context in the service context */ + OCICALL(ocip, + OCIAttrSet((void *) ocip->svcp, OCI_HTYPE_SVCCTX, + (void *) ocip->srvp, (ub4) 0, OCI_ATTR_SERVER, + (OCIError *) ocip->errp)); + + /* allocate a session handle */ + OCICALL(ocip, + OCIHandleAlloc((void *) ocip->envp, (void **)&ocip->authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (void **) 0)); + + /* set the username in the session */ + OCICALL(ocip, + OCIAttrSet((void *) ocip->authp, (ub4) OCI_HTYPE_SESSION, + (void *) connp->user, + (ub4) connp->userlen, + (ub4) OCI_ATTR_USERNAME, ocip->errp)); + + /* set the password in the session */ + OCICALL(ocip, + OCIAttrSet((void *) ocip->authp, (ub4) OCI_HTYPE_SESSION, + (void *) connp->passw, + (ub4) connp->passwlen, + (ub4) OCI_ATTR_PASSWORD, ocip->errp)); + + OCICALL(ocip, + OCISessionBegin(ocip->svcp, ocip->errp, ocip->authp, + OCI_CRED_RDBMS, + (ub4) connp->sysdba ? + OCI_SYSDBA : OCI_DEFAULT)); + + OCICALL(ocip, + OCIAttrSet((void *) ocip->svcp, (ub4) OCI_HTYPE_SVCCTX, + (void *) ocip->authp, (ub4) 0, + (ub4) OCI_ATTR_SESSION, ocip->errp)); + + if (OCIHandleAlloc((void *) ocip->envp, (void **) &ocip->stmtp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (void **) 0)) + { + ocierror(ocip, (char *)"OCIHandleAlloc(OCI_HTYPE_STMT) failed", TRUE); + } + + if (OCIHandleAlloc((void *) ocip->envp, (void **) &ocip->stmt2p, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (void **) 0)) + { + ocierror(ocip, (char *)"OCIHandleAlloc(OCI_HTYPE_STMT-2) failed", TRUE); + } + + if (OCIHandleAlloc((void *) ocip->envp, (void **) &ocip->stmt3p, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (void **) 0)) + { + ocierror(ocip, (char *)"OCIHandleAlloc(OCI_HTYPE_STMT-3) failed", TRUE); + } + + /* restore the interrupt signal handler */ + signal(SIGINT, SIG_DFL); +} + +static void oradisconnect(oci_t * ocip) +{ + if (OCILogoff(ocip->svcp, ocip->errp)) + { + ocierror(ocip, (char *)"OCILogoff() failed", TRUE); + } + + if (ocip->stmtp) + OCIHandleFree((void *) ocip->stmtp, (ub4) OCI_HTYPE_STMT); + + if (ocip->stmt2p) + OCIHandleFree((void *) ocip->stmt2p, (ub4) OCI_HTYPE_STMT); + + if (ocip->stmt2p) + OCIHandleFree((void *) ocip->stmt3p, (ub4) OCI_HTYPE_STMT); + + if (ocip->errp) + OCIHandleFree((void *) ocip->errp, (ub4) OCI_HTYPE_ERROR); + + if (ocip->envp) + OCIHandleFree((void *) ocip->envp, (ub4) OCI_HTYPE_ENV); +} + +static void print_header(options_t * opts, connection_t * connp) +{ + oci_t * ocip = connp->ocip; + + puts((char *)"\nSTREAMS Monitor, v 2.5 Copyright Oracle Corp. 2002, 2005."); + printf("Interval = %u, Count=%u \n\n", + opts->interval, opts->count); + + printf("Logon=%.*s@%.*s ORACLE %.*s\n\n", + connp->userlen, + connp->userlen ? (char *)connp->user : "", + connp->dbnamelen, + connp->dbnamelen ? (char *)connp->dbname : "", + connp->versionstrlen, connp->versionstr); + + if (connp->version >= VERSION_10g) + { + printf("Streams Pool Size = "); + print_pool_size(ocip); + printf("\n\n"); + } + + if (connp->sysuser) + { + if (opts->short_opt) + { + printf("LOG : \n"); + } + else + { + printf("LOG : \n"); + } + } + + printf("NET: "); + if (opts->short_opt) + { + printf(" \n"); + } + else + { + printf(" \n"); + } + + printf("Cxxx: "); + if(opts->short_opt) + { + printf(" " + "\n"); + } + else + { + if (connp->version >= VERSION_10g) + { + printf(" "); + } + printf(" " + "\n"); + } + + if ((connp->sysuser) && (connp->version >= VERSION_10g)) + { + printf("MEM : %% \n"); + } + + if (opts->short_opt) + { + puts((char *)"PRxx: "); + } + else { + puts((char *)"PRxx: /"); + } + + if (!opts->short_opt) + { + printf("Qx : "); + if (connp->version >= VERSION_10g) + { + printf("/ "); + } + else if (connp->sysuser) + { + /* in 9i only SYS can query the outstanding messages */ + printf(" "); + } + if (connp->version >= VERSION_10g) + { + printf("\n"); + } + else + { + printf("\n"); + } + } + else + { + if (connp->version >= VERSION_10g) + { + printf("Qx : \n"); + } + /* for 9i short queue stats are not printed */ + } + + if (opts->short_opt) + { + puts((char *)"PSxx: "); + } + else + { + puts((char *)"PSxx: /"); + } + + if (opts->short_opt) + { + puts((char *)"Axxx: " + ""); + } + else + { + puts((char *)"Axxx: " + " " + " "); + } + + puts((char *)": flow control in effect"); + puts((char *)": potential bottleneck"); + + puts((char *)"AR: apply reader"); + puts((char *)"AS(n): n number of apply server"); + + if (connp->version >= VERSION_10g) + puts((char *)": "); + + puts((char *)"xx->: database instance name"); + + printf("\n"); +} + +static void print_stats(options_t * opts, connection_t * connp) +{ + if (opts->iters > 0) + { + collect_event_data(opts, connp); + } + + if (connp->sysuser) + { + print_log_stats(opts, connp->ocip, &connp->lgwr_pval); + } + + /* print the network usage stats */ + print_net_stats(opts, connp); + + /* now print the capture statistics */ + if (opts->short_opt) + { + print_short_capture_stats(opts, connp, connp->ocip, &connp->cap_pval); + } + else + { + print_capture_stats(opts, connp, connp->ocip, &connp->cap_pval); + } + + if (connp->version >= VERSION_10g) + { + print_queue_stats(opts, connp, connp->ocip, &connp->que_pval, + &connp->prop_pval); + } + else + { + /* in 9iR2, we only get the current spilled messages. + * Also, there is no way to get the cummulative messages. + * So, we cannot compute the rates in 9iR2. + */ + print_queue9i_stats(opts, connp, connp->ocip, &connp->prop_pval); + } + + if (opts->short_opt) + { + print_short_apply_stats(opts, connp, connp->ocip, &connp->app_pval); + } + else + { + print_apply_stats(opts, connp, connp->ocip, &connp->app_pval); + } + + if ((connp->sysuser) && (connp->version >= VERSION_10g)) + { + print_mem_stats(opts, connp->ocip); + } + + if (opts->iters == 0) + { + collect_event_data(opts, connp); + } + +} + +#define POOL_SIZE_10g "select current_size from v$sga_dynamic_components \ +where component='streams pool'" + +static void print_pool_size(oci_t * ocip) +{ + OCIDefine *defnp; + OCINumber pool_size; + OCINumber megabyte; + OCINumber pool_mb; + sword temp; + uword tempsize; + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) POOL_SIZE_10g, + sizeof(POOL_SIZE_10g), OCI_NTV_SYNTAX, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, + (void *)&pool_size, + sizeof(pool_size), SQLT_VNU, NULL, + NULL, NULL, OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 1, 0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_EXACT_FETCH)); + + /* create an OCI number with 1M in it */ + temp = (sword) 1 << 20; + tempsize = sizeof(temp); + OCICALL(ocip, OCINumberFromInt(ocip->errp, &temp, tempsize, + OCI_NUMBER_SIGNED, &megabyte)); + + /* divide the pool size by 1M */ + OCICALL(ocip, OCINumberDiv(ocip->errp, &pool_size, &megabyte, &pool_mb)); + + /* covert the pool size to an integer and print it */ + OCICALL(ocip, OCINumberToInt(ocip->errp, &pool_mb, tempsize, + OCI_NUMBER_SIGNED, &temp)); + + printf("%dM", temp); +} + + +#define CAPTURE_SHORT_STATS_9iR2 "select c.sid, c.CAPTURE# CAPTURENUM, \ +c.CAPTURE_NAME, nvl(c.TOTAL_MESSAGES_CAPTURED,0) TOTAL_MESSAGES_CAPTURED, \ +nvl(c.TOTAL_MESSAGES_ENQUEUED,0) TOTAL_MESSAGES_ENQUEUED, \ +nvl((c.CAPTURE_TIME - c.CAPTURE_MESSAGE_CREATE_TIME)*86400, -1) \ +CAPTURE_LATENCY from v$streams_capture c order by 1" + +#define CAPTURE_SHORT_STATS "select c.sid, c.CAPTURE# CAPTURENUM, \ +c.CAPTURE_NAME, nvl(c.TOTAL_MESSAGES_CAPTURED,0) TOTAL_MESSAGES_CAPTURED, \ +nvl(c.TOTAL_MESSAGES_ENQUEUED,0) TOTAL_MESSAGES_ENQUEUED, \ +nvl((c.CAPTURE_TIME - \ + c.CAPTURE_MESSAGE_CREATE_TIME)*86400, -1) CAPTURE_LATENCY, \ +nvl(c.CAPTURE_MESSAGE_NUMBER,0) CAPTURE_MESSAGE_NUMBER, \ +l.read_scn, c.ELAPSED_PAUSE_TIME \ +from v$streams_capture c, v$logmnr_session l where \ +c.capture_name=l.session_name order by 1" + +#define CAPTURE_STATS_9iR2 "select c.sid, c.CAPTURE# CAPTURENUM, \ +c.CAPTURE_NAME, nvl(c.TOTAL_MESSAGES_CAPTURED,0) TOTAL_MESSAGES_CAPTURED, \ +nvl(c.CAPTURE_MESSAGE_NUMBER,0) CAPTURE_MESSAGE_NUMBER, \ +nvl(c.TOTAL_MESSAGES_ENQUEUED,0) TOTAL_MESSAGES_ENQUEUED, \ +nvl(c.ENQUEUE_MESSAGE_NUMBER,0) ENQUEUE_MESSAGE_NUMBER, \ +nvl((c.CAPTURE_TIME - \ + c.CAPTURE_MESSAGE_CREATE_TIME)*86400, -1) CAPTURE_LATENCY \ +from v$streams_capture c order by 1" + +#define CAPTURE_STATS "select c.sid, c.CAPTURE# CAPTURENUM, c.CAPTURE_NAME, \ +nvl(c.TOTAL_MESSAGES_CAPTURED,0) TOTAL_MESSAGES_CAPTURED, \ +nvl(c.CAPTURE_MESSAGE_NUMBER,0) CAPTURE_MESSAGE_NUMBER, \ +nvl(c.TOTAL_MESSAGES_ENQUEUED,0) TOTAL_MESSAGES_ENQUEUED, \ +nvl(c.ENQUEUE_MESSAGE_NUMBER,0) ENQUEUE_MESSAGE_NUMBER, \ +nvl((c.CAPTURE_TIME - \ + c.CAPTURE_MESSAGE_CREATE_TIME)*86400, -1) CAPTURE_LATENCY, \ +l.read_scn, c.ELAPSED_PAUSE_TIME \ +from v$streams_capture c, v$logmnr_session l where \ +c.capture_name=l.session_name order by 1" + +typedef struct capture +{ + ub4 capturenum; + oratext capturename[128]; + ub2 capturenamelen; + ub4 total_captured; + OCINumber captured_scn; + oratext captured_scn_str[128]; + ub4 captured_scn_strlen; + ub4 total_enqueued; + OCINumber enqueued_scn; + oratext enqueued_scn_str[128]; + ub4 enqueued_scn_strlen; + OCINumber read_scn; + oratext read_scn_str[128]; + ub4 read_scn_strlen; + sb4 capture_latency; + ub4 elapsed_pause_time; + ub4 sid; +} capture_t; + + +static cap_pval_t* print_capture_rates(oci_t * ocip, options_t * opts, + connection_t * connp, + cap_pval_t **cap_pval, + capture_t cap, + boolean short_opt, boolean *flow_ctrl, + boolean *bottleneck) +{ + boolean cur_cap_exists = FALSE; + cap_pval_t *cap_elem; + cap_pval_t *new_elem; + sword result = 0; + cap_pval_t *cur_cap = 0; + sid_pval_t sidval; + sid_pval_t *new_sid = 0; + + for (cap_elem = *cap_pval; + cap_elem != (cap_pval_t *)NULL; + cap_elem = cap_elem->next_cap) + { + cur_cap = cap_elem; + + if ((cap_elem->capturenamelen == cap.capturenamelen) && + !memcmp((void *)cap_elem->capturename, (void *)cap.capturename, + (size_t)cap_elem->capturenamelen)) + { + cur_cap_exists = TRUE; + + if (connp->version >= VERSION_10g) + { + if ((*flow_ctrl) = (cap.elapsed_pause_time > + cap_elem->elapsed_pause_time)) + { + printf(" "); + } + else + { + OCICALL(ocip, OCINumberCmp(ocip->errp, &(cap.captured_scn), + &(cap_elem->read_scn), &result)); + + if (result < 0) + { + /* We do not want to report that capture is a bottleneck in the + * current interval if it was under flow control in the previous + * interval, and if the interval is less than 60 seconds. + */ + if ((!cap_elem->flow_ctrl) || + ((cap_elem->flow_ctrl) && (opts->interval > 60))) + { + *bottleneck = TRUE; + printf(" "); /* indicate capture as potential bottleneck */ + } + else + { + printf(" - "); /* for alignment */ + } + } + else + { + printf(" - "); /* for alignment */ + } + } + } + + if (short_opt) + { + /* In case the capture had been brought down and then restarted */ + if (cap.total_captured >= cap_elem->total_captured) + { + printf("C%03u %u %u", cap.capturenum, + (cap.total_captured-cap_elem->total_captured)*100/(opts->elapstim), + (cap.total_enqueued-cap_elem->total_enqueued)*100/(opts->elapstim)); + print_latency(cap.capture_latency); + } + else + { + printf(" "); /* for alignment */ + } + } + + /* update the data for the current capture in the linked list */ + memcpy((void *)cap_elem->capturename, (void *)cap.capturename, + (size_t)cap.capturenamelen); + cap_elem->capturenamelen = cap.capturenamelen; + cap_elem->capturenum = cap.capturenum; + cap_elem->total_captured = cap.total_captured; + cap_elem->total_enqueued = cap.total_enqueued; + + if (*flow_ctrl) + { + cap_elem->flow_ctrl = TRUE; + } + else + { + cap_elem->flow_ctrl = FALSE; + } + + if (connp->version >= VERSION_10g) + { + cap_elem->read_scn = cap.read_scn; + cap_elem->elapsed_pause_time = cap.elapsed_pause_time; + } + + break; + } + } + + /* add the data for this new capture process into the linked list */ + if (!cur_cap_exists) + { + printf(" "); /* for alignment */ + /* add the new capture stats to the linked list */ + new_elem = (cap_pval_t *)malloc (sizeof(cap_pval_t)); + memset(new_elem, 0, sizeof(cap_pval_t)); + if (connp->version >= VERSION_10g) + { + new_elem->read_scn = cap.read_scn; + new_elem->elapsed_pause_time = cap.elapsed_pause_time; + } + memcpy((void *)new_elem->capturename, (void *)cap.capturename, + (size_t)cap.capturenamelen); + new_elem->capturenamelen = cap.capturenamelen; + new_elem->capturenum = cap.capturenum; + new_elem->total_captured = cap.total_captured; + new_elem->total_enqueued = cap.total_enqueued; + new_elem->flow_ctrl = FALSE; + if (*cap_pval == (cap_pval_t *)NULL) + { + *cap_pval = new_elem; + } + else + { + cur_cap->next_cap = new_elem; + } + cur_cap = new_elem; + + /* add the new sid info to sid_pval list */ + new_sid = (sid_pval_t *)malloc(sizeof(sid_pval_t)); + new_sid->sid = cap.sid; + new_sid->pval = new_elem; + new_sid->type = CAPTURE_PROCESS; + new_sid->next = connp->sid_pval; + + connp->sid_pval = new_sid; + connp->num_sid ++; + } + return cur_cap; + +} + +static void print_short_capture_stats(options_t * opts, connection_t * connp, + oci_t * ocip, cap_pval_t ** cap_pval) +{ + capture_t cap; + OCIDefine *defnp; + sword result = 0; + boolean flow_ctrl = FALSE; + boolean bottleneck = FALSE; + sword status = OCI_SUCCESS; + boolean cur_cap_exists = FALSE; + cap_pval_t *cur_cap; + + if (connp->version >= VERSION_10g) + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, + (oratext *) CAPTURE_SHORT_STATS, + sizeof(CAPTURE_SHORT_STATS), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + } + else + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, + (oratext *) CAPTURE_SHORT_STATS_9iR2, + sizeof(CAPTURE_SHORT_STATS_9iR2), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + } + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &cap.sid, + sizeof(cap.sid), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 2, &cap.capturenum, + sizeof(cap.capturenum), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 3, &cap.capturename, + sizeof(cap.capturename), SQLT_CHR, NULL, + &cap.capturenamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 4, + &cap.total_captured, sizeof(cap.total_captured), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 5, + &cap.total_enqueued, sizeof(cap.total_enqueued), + SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 6, + &cap.capture_latency, sizeof(cap.capture_latency), + SQLT_INT, NULL, NULL, NULL, OCI_DEFAULT)); + + if (connp->version >= VERSION_10g) + { + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp,7,&cap.captured_scn, + sizeof(cap.captured_scn), SQLT_VNU, NULL, NULL, + NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 8, &cap.read_scn, + sizeof(cap.read_scn), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 9, + &cap.elapsed_pause_time, + sizeof(cap.elapsed_pause_time), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + } + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmtp, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + flow_ctrl = FALSE; + bottleneck = FALSE; + result = 0; + + printf(" | "); + + cur_cap = print_capture_rates(ocip, opts, connp, cap_pval, cap, TRUE, + &flow_ctrl, &bottleneck); + + if (connp->version >= VERSION_10g) + { + print_event_stats(opts, (void *)cur_cap, CAPTURE_PROCESS); + } + } + + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | C ", FALSE); + } + + /* finish the cursor */ + OCICALL(ocip, + OCIStmtFetch2(ocip->stmtp, ocip->errp, 0, OCI_DEFAULT, 0, OCI_DEFAULT)); +} + +static void print_capture_stats(options_t * opts, connection_t * connp, + oci_t * ocip, cap_pval_t ** cap_pval) +{ + capture_t cap; + OCIDefine *defnp; + sword result = 0; + boolean flow_ctrl = FALSE; + boolean bottleneck = FALSE; + sword status = OCI_ERROR; + boolean cur_cap_exists = FALSE; + cap_pval_t *cur_cap; + + if (connp->version >= VERSION_10g) + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) CAPTURE_STATS, + sizeof(CAPTURE_STATS), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + } + else + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, + (oratext *) CAPTURE_STATS_9iR2, + sizeof(CAPTURE_STATS_9iR2), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + } + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &cap.sid, + sizeof(cap.sid), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 2, &cap.capturenum, + sizeof(cap.capturenum), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 3, &cap.capturename, + sizeof(cap.capturename), SQLT_CHR, NULL, + &cap.capturenamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 4, + &cap.total_captured, sizeof(cap.total_captured), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 5, &cap.captured_scn, + sizeof(cap.captured_scn), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 6, + &cap.total_enqueued, sizeof(cap.total_enqueued), + SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 7, &cap.enqueued_scn, + sizeof(cap.enqueued_scn), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 8, + &cap.capture_latency, sizeof(cap.capture_latency), + SQLT_INT, NULL, NULL, NULL, OCI_DEFAULT)); + + if (connp->version >= VERSION_10g) + { + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 9, &cap.read_scn, + sizeof(cap.read_scn), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 10, + &cap.elapsed_pause_time, + sizeof(cap.elapsed_pause_time), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + } + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmtp, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + flow_ctrl = FALSE; + bottleneck = FALSE; + result = 0; + cur_cap_exists = FALSE; + + + if (connp->version >= VERSION_10g) + { + printf(" | "); + cur_cap = print_capture_rates(ocip, opts, connp, cap_pval, cap, FALSE, + &flow_ctrl, &bottleneck); + + cap.read_scn_strlen = 128; + OCICALL(ocip, + OCINumberToText(ocip->errp, &cap.read_scn, + (const oratext *)"TM9", 3, (oratext *)0, 0, + &cap.read_scn_strlen, cap.read_scn_str)); + printf(" C%03u %.*s ", cap.capturenum, cap.read_scn_strlen, + cap.read_scn_str); + } + else + { + printf(" | C%03u ", cap.capturenum); + } + + cap.captured_scn_strlen = 128; + OCICALL(ocip, + OCINumberToText(ocip->errp, &cap.captured_scn, + (const oratext *)"TM9", 3, (oratext *)0, 0, + &cap.captured_scn_strlen, cap.captured_scn_str)); + + cap.enqueued_scn_strlen = 128; + OCICALL(ocip, + OCINumberToText(ocip->errp, &cap.enqueued_scn, + (const oratext *)"TM9", 3, (oratext *)0, 0, + &cap.enqueued_scn_strlen, cap.enqueued_scn_str)); + + printf("%u %.*s %u %.*s", + cap.total_captured, cap.captured_scn_strlen, cap.captured_scn_str, + cap.total_enqueued, cap.enqueued_scn_strlen, cap.enqueued_scn_str + ); + + print_latency(cap.capture_latency); + + if (connp->version >= VERSION_10g) + { + print_event_stats(opts, (void *)cur_cap, CAPTURE_PROCESS); + } + } + + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | C ", FALSE); + } + + /* finish the cursor */ + OCICALL(ocip, + OCIStmtFetch2(ocip->stmtp, ocip->errp, 0, OCI_DEFAULT, 0, OCI_DEFAULT)); +} + + +#define QUEUE9i_STATS "select dq.qid, dq.owner, dq.queue_table from dba_queues\ + dq, dba_queue_tables dqt where dq.owner not in ('SYS','SYSTEM') and \ +dq.QUEUE_TYPE='NORMAL_QUEUE' and dq.owner=dqt.owner and \ +dq.queue_table=dqt.queue_table and dqt.object_type='SYS.ANYDATA'" + +#define QUEUE9i_OUTMESG_STATS "select bufqm_nmsg from x$bufqm where \ +bufqm_qid=:1" + +#define QUEUE9i_SPILL_STATS "select count(*) from %.*s.AQ$_%.*s_P" + +typedef struct queue9i +{ + ub4 queueid; + oratext owner[128]; + ub2 ownerlen; + oratext qtable[128]; + ub2 qtablelen; + ub4 spilled; + ub4 outstanding; +} queue9i_t; + +static void print_queue9i_stats(options_t * opts, connection_t * connp, + oci_t * ocip, prop_pval_t ** prop_pval) +{ + queue9i_t que9i; + OCIDefine *defnp; + OCIBind *bndp; + unsigned pnum = 0; + char spillquery[1024]; + ub4 spillquerylen; + sword status; + sword status2 = OCI_SUCCESS; + + que_pval_t *que_elem; + que_pval_t *new_elem; + que_pval_t *cur_que; + boolean cur_que_exists = FALSE; + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) QUEUE9i_STATS, + sizeof(QUEUE9i_STATS), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &que9i.queueid, + sizeof(que9i.queueid), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 2, &que9i.owner, + sizeof(que9i.owner), SQLT_CHR, NULL, + &que9i.ownerlen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 3, &que9i.qtable, + sizeof(que9i.qtable), SQLT_CHR, NULL, + &que9i.qtablelen, NULL, + OCI_DEFAULT)); + + while(OCI_SUCCESS == + (status2 = OCIStmtFetch2(ocip->stmtp, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + if (!opts->short_opt) + { + printf(" | Q%u", que9i.queueid); + + if (connp->sysuser) + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, + (oratext *)QUEUE9i_OUTMESG_STATS, + sizeof(QUEUE9i_OUTMESG_STATS), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + bndp = (OCIBind *)0; + OCICALL(ocip, + OCIBindByPos(ocip->stmt2p, &bndp, ocip->errp, 1, + (void *) &que9i.queueid, sizeof(que9i.queueid), + SQLT_UIN, (void *) 0, (ub2 *) 0, (ub2 *) 0, + (ub4) 0, (ub4 *) 0, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 1, + &que9i.outstanding, sizeof(que9i.outstanding), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + + status = OCIStmtExecute(ocip->svcp, ocip->stmt2p, ocip->errp, 1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_EXACT_FETCH); + + if (OCI_NO_DATA == status) + { + /* if there has been no buffered enqueues then x$bufqm will not show + * a row for this table */ + printf(" -"); + } + else if (OCI_SUCCESS == status) + { + printf(" %u", que9i.outstanding); + } + else + { + /* lrg 2858006: compiler issue, temporary fix to initialize status */ + sword status_tmp = status; + OCICALL(ocip, status_tmp); + } + } + + /* contruct the query for the spilled messages */ + spillquerylen = + (ub4)sprintf(spillquery, QUEUE9i_SPILL_STATS, que9i.ownerlen, + que9i.owner, que9i.qtablelen, que9i.qtable); + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, (oratext *) spillquery, + spillquerylen, OCI_NTV_SYNTAX, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 1, + &que9i.spilled, + sizeof(que9i.spilled), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + status = OCIStmtExecute(ocip->svcp, ocip->stmt2p, ocip->errp, 1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_EXACT_FETCH); + + if (OCI_SUCCESS == status) + { + printf(" %u", que9i.spilled); + } + else + { + printf(" -"); + } + } + print_prop_sender_stats(opts, connp, ocip, que9i.queueid, prop_pval, &pnum); + } + + if (OCI_ERROR == status2) + { + ocierror(ocip, (char *)" | Q ", FALSE); + } +} + +#define QUEUE_STATS "select queue_id, QUEUE_NAME, QUEUE_SCHEMA, nvl(cnum_msgs,0) CNUM_MSGS, \ +nvl(cspill_msgs,0) CSPILL_MSGS, nvl(num_msgs,0) num_msgs from \ +v$buffered_queues" + + +static void print_queue_stats(options_t * opts, connection_t * connp, + oci_t * ocip, que_pval_t ** que_pval, + prop_pval_t ** prop_pval) +{ + queue_t que; + OCIDefine *defnp; + sword status = OCI_SUCCESS; + que_pval_t *que_elem; + que_pval_t *new_elem; + que_pval_t *cur_que; + unsigned pnum = 0; + boolean cur_que_exists = FALSE; + + /* now print the queue statistics and the propagation stats for each + * buffered queue */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) QUEUE_STATS, + sizeof(QUEUE_STATS), OCI_NTV_SYNTAX, OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &que.queueid, + sizeof(que.queueid), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 2, &que.queuename, + sizeof(que.queuename), SQLT_CHR, NULL, + &que.queuenamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 3, &que.schemaname, + sizeof(que.schemaname), SQLT_CHR, NULL, + &que.schemanamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 4, &que.cnummsgs, + sizeof(que.cnummsgs), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 5, &que.cspillmsgs, + sizeof(que.cspillmsgs), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 6, &que.nummsgs, + sizeof(que.nummsgs), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmtp, ocip->errp, 1, OCI_DEFAULT, 0, + OCI_DEFAULT))) + { + print_prop_receiver_stats(opts, connp, ocip, &que, prop_pval, &pnum); + + if (!opts->short_opt) + { + printf(" | Q%u %5u/%u %5u", que.queueid, que.nummsgs, que.cnummsgs, + que.cspillmsgs); + } + else + { + for (que_elem = *que_pval; + que_elem != (que_pval_t *)NULL; + que_elem = que_elem->next_que) + { + cur_que = que_elem; + if (que_elem->queueid == que.queueid) + { + cur_que_exists = TRUE; + printf (" | Q%u %u %u", que.queueid, + (que.cnummsgs-que_elem->cnummsgs)*100/(opts->elapstim), + (que.cspillmsgs-que_elem->cspillmsgs)*100/(opts->elapstim)); + + /* update the values for the queue in the list */ + que_elem->cnummsgs = que.cnummsgs; + que_elem->cspillmsgs = que.cspillmsgs; + break; + } + } + if (!cur_que_exists) + { + /* add the values for the new queue to the linked list */ + new_elem = (que_pval_t *)malloc(sizeof(que_pval_t)); + new_elem->queueid = que.queueid; + new_elem->cnummsgs = que.cnummsgs; + new_elem->cspillmsgs = que.cspillmsgs; + new_elem->next_que = (que_pval_t *)NULL; + if (*que_pval == (que_pval_t *)NULL) + { + *que_pval = new_elem; + } + else + { + cur_que->next_que = new_elem; + } + } + } + print_prop_sender_stats(opts, connp, ocip, que.queueid, prop_pval, &pnum); + + } + + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | Q ", FALSE); + } + + /* finish fetching from the buffered queue cursor */ + OCICALL(ocip, + OCIStmtFetch2(ocip->stmtp, ocip->errp, 0, OCI_DEFAULT, 0, + OCI_DEFAULT)); +} + +typedef struct prop +{ + ub4 total_number; + ub4 total_time; + ub8 total_bytes; + oratext src_queuename[30]; + ub2 src_queuenamelen; + oratext src_schemaname[30]; + ub2 src_schemanamelen; + oratext src_dbname[128]; + ub2 src_dbnamelen; + oratext dst_queuename[30]; + ub2 dst_queuenamelen; + oratext dst_schemaname[30]; + ub2 dst_schemanamelen; + oratext dst_dbname[128]; + ub2 dst_dbnamelen; + oratext destination[128]; + ub2 destination_len; +} prop_t; + +#define PROP_RECEIVER_STATS_10gR2_FIRST \ +"select NVL(SRC_QUEUE_NAME, '\0'), \ +NVL(SRC_QUEUE_SCHEMA, '\0'), TOTAL_MSGS, ELAPSED_ENQUEUE_TIME, \ +NVL(SRC_DBNAME, '\0') \ +from v$propagation_receiver \ +where (DST_QUEUE_NAME=:1 or DST_QUEUE_NAME is NULL) and \ +(DST_QUEUE_SCHEMA=:2 or DST_QUEUE_SCHEMA is NULL)" + +#define PROP_RECEIVER_STATS_10gR2 "select NVL(SRC_QUEUE_NAME, '\0'), \ +NVL(SRC_QUEUE_SCHEMA, '\0'), TOTAL_MSGS, ELAPSED_ENQUEUE_TIME, \ +NVL(SRC_DBNAME, '\0') \ +from v$propagation_receiver \ +where DST_QUEUE_NAME=:1 and DST_QUEUE_SCHEMA=:2" + +#define PROPAGATION_RECEIVER_SIDS_10gR2 \ +"select k.KWQPDSID from x$kwqpd k where k.KWQPDDQN=:1 and k.KWQPDDQS=:2 \ +and (KWQPDSQN IS NULL or KWQPDSQN=:3) \ +and (KWQPDSQS IS NULL or KWQPDSQS=:4) \ +and (KWQPDDBN IS NULL or KWQPDDBN=:5)" + +static void print_prop_receiver_stats(options_t * opts, connection_t * connp, + oci_t * ocip, queue_t *que, + prop_pval_t ** prop_pval, + unsigned * pnum_ptr) +{ + prop_t prp; + OCIBind *bndp; + OCIDefine *defnp; + sword status = OCI_SUCCESS; + prop_pval_t *prop_elem; + prop_pval_t *new_elem; + prop_pval_t *cur_prop; + boolean cur_prop_exists = FALSE; + sid_pval_t sidval; + sid_pval_t *new_sid = 0; + + if (connp->version >= VERSION_10gR2) + { + if (*pnum_ptr == 0) + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, + (oratext *) PROP_RECEIVER_STATS_10gR2_FIRST, + sizeof(PROP_RECEIVER_STATS_10gR2_FIRST), + OCI_NTV_SYNTAX, + OCI_DEFAULT)); + else + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, + (oratext *) PROP_RECEIVER_STATS_10gR2, + sizeof(PROP_RECEIVER_STATS_10gR2), + OCI_NTV_SYNTAX, + OCI_DEFAULT)); + } + else + { + return; + } + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt2p, &bndp, ocip->errp, 1, + (void *) &(que->queuename), + (sword) sizeof(que->queuename), + SQLT_CHR, (void *) 0, + (ub2 *)&(que->queuenamelen), (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt2p, &bndp, ocip->errp, 2, + (void *) &(que->schemaname), + (sword) sizeof(que->schemaname), + SQLT_CHR, + (void *) 0, (ub2 *)&(que->schemanamelen), (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmt2p, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 1, + (void *)&prp.src_queuename, + sizeof(prp.src_queuename), + SQLT_CHR, NULL, &prp.src_queuenamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 2, + (void *)&prp.src_schemaname, + sizeof(prp.src_schemaname), + SQLT_CHR, NULL, &prp.src_schemanamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 3, + &prp.total_number, sizeof(prp.total_number), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 4, + &prp.total_time, sizeof(prp.total_time), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 5, + (void *)&prp.src_dbname, sizeof(prp.src_dbname), + SQLT_CHR, NULL, &prp.src_dbnamelen, NULL, + OCI_DEFAULT)); + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmt2p, ocip->errp, 1, OCI_DEFAULT, 0, + OCI_DEFAULT))) + { + (*pnum_ptr)++; + cur_prop_exists = FALSE; + + for (prop_elem = *prop_pval; + prop_elem != (prop_pval_t *)NULL; + prop_elem = prop_elem->next_prop) + { + cur_prop = prop_elem; + if ((prop_elem->src_dbnamelen == prp.src_dbnamelen) + && (prop_elem->src_queuenamelen == prp.src_queuenamelen) + && !memcmp((void *)prop_elem->src_dbname, (void *)prp.src_dbname, + prp.src_dbnamelen) + && !memcmp((void *)prop_elem->src_queuename, + (void *)prp.src_queuename, + prp.src_queuenamelen)) + { + cur_prop_exists = TRUE; + + if (opts->short_opt) + { + /* In case the propagation process was brought down and restarted */ + if (prp.total_number >= prop_elem->total_number) + { + printf(" | PR%02u ", *pnum_ptr); + printf("%u", (prp.total_number - prop_elem->total_number)*100 + /opts->elapstim); + } + else if (prp.total_time > 0) + { + printf(" | PR%02u ", *pnum_ptr); + printf("%u", prp.total_number/prp.total_time); + } + } + + /* update the data for the current propagation process */ + prop_elem->total_number = prp.total_number; + + break; + } + } + if (!cur_prop_exists) + { + /* add the data for the new propagation process into the linked list*/ + new_elem = (prop_pval_t *)malloc (sizeof(prop_pval_t)); + new_elem->dst_queueid = que->queueid; + memcpy((void *)new_elem->src_queuename, (void *)(prp.src_queuename), + (prp.src_queuenamelen)); + new_elem->src_queuenamelen = prp.src_queuenamelen; + memcpy((void *)new_elem->src_schemaname, (void *)(prp.src_schemaname), + (prp.src_schemanamelen)); + new_elem->src_schemanamelen = prp.src_schemanamelen; + new_elem->src_dbnamelen = prp.src_dbnamelen; + memcpy((void *)new_elem->src_dbname, (void *)prp.src_dbname, + prp.src_dbnamelen); + + new_elem->total_number = prp.total_number; + new_elem->total_bytes = prp.total_bytes; + new_elem->pevent_sender = NULL; + new_elem->pevent_receiver = NULL; + new_elem->next_prop = (prop_pval_t *)NULL; + + + if (*prop_pval == (prop_pval_t *)NULL) + { + *prop_pval = new_elem; + } + else + { + cur_prop->next_prop = new_elem; + } + cur_prop = new_elem; + + if ((connp->version >= VERSION_10gR2) && connp->sysdba) + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt3p, ocip->errp, + (oratext *) PROPAGATION_RECEIVER_SIDS_10gR2, + sizeof(PROPAGATION_RECEIVER_SIDS_10gR2), + OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 1, + (void *) &(que->queuename), + (sword) sizeof(que->queuename), + SQLT_CHR, + (void *) 0, (ub2 *)&(que->queuenamelen), + (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 2, + (void *) &(que->schemaname), + (sword) sizeof(que->schemaname), + SQLT_CHR, + (void *) 0, (ub2 *)&(que->schemanamelen), + (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 3, + (void *) &(cur_prop->src_queuename), + (sword) sizeof(cur_prop->src_queuename), + SQLT_CHR, + (void *) 0, (ub2 *)&(cur_prop->src_queuenamelen), + (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 4, + (void *) &(cur_prop->src_schemaname), + (sword) sizeof(cur_prop->src_schemaname), + SQLT_CHR, + (void *) 0, (ub2 *)&(cur_prop->src_schemanamelen), + (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 5, + (void *) &(cur_prop->src_dbname), + (sword) sizeof(cur_prop->src_dbname), + SQLT_CHR, + (void *) 0, (ub2 *)&(cur_prop->src_dbnamelen), + (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmt3p, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt3p, &defnp, ocip->errp, 1, + &sidval.sid, + sizeof(sidval.sid), SQLT_UIN, NULL, + NULL, NULL, + OCI_DEFAULT)); + + while (OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmt3p, ocip->errp, 1, + OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + new_sid = (sid_pval_t *)malloc(sizeof(sid_pval_t)); + new_sid->sid = sidval.sid; + new_sid->pval = new_elem; + new_sid->type = PR_RECEIVER_PROCESS; + new_sid->next = connp->sid_pval; + + connp->sid_pval = new_sid; + connp->num_sid ++; + } + } + } + + if (!opts->short_opt) + { + printf(" | PR%02u %u/%u", *pnum_ptr, prp.total_number, + prp.total_time); + } + + if (cur_prop != NULL && (connp->version >= VERSION_10gR2) && connp->sysdba) + { + print_event_stats(opts, (void *)cur_prop, PR_RECEIVER_PROCESS); + } + } + + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | PR ", FALSE); + } + + /* finish fetching from the propagation cursor */ + OCICALL(ocip, + OCIStmtFetch2(ocip->stmt2p, ocip->errp, 0, OCI_DEFAULT, 0, + OCI_DEFAULT)); +} + + +#define PROP_SENDER_STATS "select dq.name, dq.owner, dqs.TOTAL_NUMBER, dqs.TOTAL_TIME, \ +dqs.TOTAL_BYTES, dqs.destination \ +from dba_queue_schedules dqs, dba_queues dq where dqs.schema=dq.owner and \ +dqs.qname=dq.name and dq.qid=:1 order by dqs.destination" + +#define PROP_SENDER_STATS_10gR2 "select dq.name, dq.owner, dqs.TOTAL_NUMBER, dqs.TOTAL_TIME, \ +dqs.TOTAL_BYTES, dqs.destination \ +from dba_queue_schedules dqs, dba_queues dq where dqs.schema=dq.owner and \ +dqs.qname=dq.name and dq.qid=:1 and dqs.message_delivery_mode = 'BUFFERED' \ +order by dqs.destination" + +#define PROPAGATION_SENDER_SIDS \ +"select KWQPSSID from x$kwqps where KWQPSQID=:1 and (KWQPSDBN=:2 or KWQPSDQN=:3)" + +static void print_prop_sender_stats(options_t * opts, connection_t * connp, + oci_t * ocip, ub4 queueid, + prop_pval_t ** prop_pval, + unsigned *pnum_ptr) +{ + prop_t prp; + OCIBind *bndp; + OCIDefine *defnp; + OCINumber total_bytes_num; + sword status = OCI_SUCCESS; + prop_pval_t *prop_elem; + prop_pval_t *new_elem; + prop_pval_t *cur_prop; + boolean cur_prop_exists = FALSE; + sid_pval_t sidval; + sid_pval_t *new_sid = 0; + + if (connp->version >= VERSION_10gR2) + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, + (oratext *) PROP_SENDER_STATS_10gR2, + sizeof(PROP_SENDER_STATS_10gR2), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + } + else + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, + (oratext *) PROP_SENDER_STATS, + sizeof(PROP_SENDER_STATS), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + } + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt2p, &bndp, ocip->errp, 1, + (void *) &queueid, + (sword) sizeof(queueid), + SQLT_UIN, + (void *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 1, + (void *)&prp.src_queuename, + sizeof(prp.src_queuename), + SQLT_CHR, NULL, &prp.src_queuenamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 2, + (void *)&prp.src_schemaname, + sizeof(prp.src_schemaname), + SQLT_CHR, NULL, &prp.src_schemanamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 3, + &prp.total_number, sizeof(prp.total_number), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 4, + &prp.total_time, sizeof(prp.total_time), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 5, + &total_bytes_num, sizeof(total_bytes_num), + SQLT_VNU, NULL, NULL, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 6, + (void *)&prp.destination, sizeof(prp.destination), + SQLT_CHR, NULL, &prp.destination_len, NULL, + OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmt2p, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmt2p, ocip->errp, 1, OCI_DEFAULT, 0, + OCI_DEFAULT))) + { + (*pnum_ptr)++; + cur_prop_exists = FALSE; + + /* convert total bytes to ub8 */ + OCICALL(ocip, + OCINumberToInt(ocip->errp, &total_bytes_num, + sizeof(prp.total_bytes), OCI_NUMBER_UNSIGNED, + &prp.total_bytes)); + + for (prop_elem = *prop_pval; + prop_elem != (prop_pval_t *)NULL; + prop_elem = prop_elem->next_prop) + { + cur_prop = prop_elem; + if ((prop_elem->src_queueid == queueid) + && (prop_elem->destination_len == prp.destination_len) + && !memcmp((void *)prop_elem->destination, (void *)prp.destination, + prp.destination_len)) + { + cur_prop_exists = TRUE; + + if (opts->short_opt) + { + /* In case the propagation process was brought down and restarted */ + if (prp.total_number >= prop_elem->total_number) + { + printf(" | PS%02u ", *pnum_ptr); + printf("%u", (prp.total_number - prop_elem->total_number)*100 + /opts->elapstim); + printf(" "); + printf("%d ",(prp.total_bytes - prop_elem->total_bytes)*100 + /opts->elapstim); + + print_bytes((prp.total_bytes - prop_elem->total_bytes)*100 + /opts->elapstim); + } + } + + /* update the data for the current propagation process */ + prop_elem->total_number = prp.total_number; + prop_elem->total_bytes = prp.total_bytes; + + break; + } + } + if (!cur_prop_exists) + { + /* add the data for the new propagation process into the linked list*/ + new_elem = (prop_pval_t *)malloc (sizeof(prop_pval_t)); + new_elem->src_queueid = queueid; + memcpy((void *)new_elem->src_queuename, (void *)(prp.src_queuename), + (prp.src_queuenamelen)); + new_elem->src_queuenamelen = prp.src_queuenamelen; + memcpy((void *)new_elem->src_schemaname, (void *)(prp.src_schemaname), + (prp.src_schemanamelen)); + new_elem->src_schemanamelen = prp.src_schemanamelen; + new_elem->destination_len = prp.destination_len; + memcpy((void *)new_elem->destination, (void *)prp.destination, + prp.destination_len); + new_elem->total_number = prp.total_number; + new_elem->total_bytes = prp.total_bytes; + new_elem->pevent_sender = NULL; + new_elem->pevent_receiver = NULL; + new_elem->next_prop = (prop_pval_t *)NULL; + if (*prop_pval == (prop_pval_t *)NULL) + { + *prop_pval = new_elem; + } + else + { + cur_prop->next_prop = new_elem; + } + cur_prop = new_elem; + + + if (connp->version >= VERSION_10gR2 && connp->sysdba) { + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt3p, ocip->errp, + (oratext *) PROPAGATION_SENDER_SIDS, + sizeof(PROPAGATION_SENDER_SIDS), + OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 1, + (void *) &(cur_prop->src_queueid), + (sword) sizeof(cur_prop->src_queueid), + SQLT_UIN, + (void *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 2, + (void *) &(cur_prop->destination), + (sword) sizeof(cur_prop->destination), + SQLT_CHR, + (void *) 0, (ub2 *)&(cur_prop->destination_len), + (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 3, + (void *) &(cur_prop->destination), + (sword) sizeof(cur_prop->destination), + SQLT_CHR, + (void *) 0, (ub2 *)&(cur_prop->destination_len), + (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmt3p, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt3p, &defnp, ocip->errp, 1, + &sidval.sid, + sizeof(sidval.sid), SQLT_UIN, NULL, + NULL, NULL, + OCI_DEFAULT)); + + while (OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmt3p, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + new_sid = (sid_pval_t *)malloc(sizeof(sid_pval_t)); + new_sid->sid = sidval.sid; + new_sid->pval = new_elem; + new_sid->type = PR_SENDER_PROCESS; + new_sid->next = connp->sid_pval; + + connp->sid_pval = new_sid; + connp->num_sid ++; + } + } + + } + + if (!opts->short_opt) + { + printf(" | PS%02u %u %llu/%u", *pnum_ptr, prp.total_number, prp.total_bytes, + prp.total_time); + } + + if (cur_prop != NULL &&(connp->version >= VERSION_10gR2) && connp->sysdba) + { + print_event_stats(opts, (void *)cur_prop, PR_SENDER_PROCESS); + } + } + + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | PS ", FALSE); + } + + /* finish fetching from the propagation cursor */ + OCICALL(ocip, + OCIStmtFetch2(ocip->stmt2p, ocip->errp, 0, OCI_DEFAULT, 0, + OCI_DEFAULT)); +} + +typedef struct apply +{ + ub4 sid; + ub4 applynum; + oratext applyname[128]; + ub2 applynamelen; + ub4 msgs_deqd; + OCINumber dequeue_scn; + oratext dequeue_scn_str[128]; + ub4 dequeue_scn_strlen; + ub4 txns_recvd; + ub4 txns_assigned; + ub4 txns_applied; + OCINumber hwm_scn; + oratext hwm_scn_str[128]; + ub4 hwm_scn_strlen; + sb4 hwm_latency; + sb4 dequeue_latency; + ub4 total_applied; +} apply_t; + +#define APPLY_SHORT_STATS "select ac.apply# applynum, \ +ac.apply_name, \ +nvl((ac.hwm_time - ac.hwm_message_create_time)*86400, -1) HWM_LATENCY, \ +sum(aps.TOTAL_MESSAGES_APPLIED), ac.total_received, \ +ac.total_assigned, ac.total_applied \ +from v$streams_apply_coordinator ac, \ +v$streams_apply_server aps where ac.apply#=aps.apply# \ +group by ac.apply#, ac.apply_name, ac.hwm_time, ac.hwm_message_create_time, \ +ac.total_assigned, ac.total_received, ac.total_applied order by 1" + +#define APPLY_READER_SERVER_SIDS \ +"(select sid, 4 process_type from v$streams_apply_reader where APPLY#=:1) UNION (select sid, 5 from v$streams_apply_server where APPLY#=:1) order by 1" + +static void print_short_apply_stats(options_t * opts, connection_t * connp, + oci_t * ocip, + app_pval_t ** app_pval) +{ + OCIBind *bndp; + OCIDefine *defnp; + apply_t app; + sb4 diff = 0; + sword status = OCI_SUCCESS; + app_pval_t *app_elem; + app_pval_t *new_elem; + app_pval_t *cur_app; + boolean cur_app_exists = FALSE; + sid_pval_t sidval; + sid_pval_t *new_sid = 0; + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, + (oratext *) APPLY_SHORT_STATS, + sizeof(APPLY_SHORT_STATS), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &app.applynum, + sizeof(app.applynum), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 2, &app.applyname, + sizeof(app.applyname), SQLT_CHR, NULL, + &app.applynamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 3, &app.hwm_latency, + sizeof(app.hwm_latency), SQLT_INT, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 4, + &app.total_applied, + sizeof(app.total_applied), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 5, &app.txns_recvd, + sizeof(app.txns_recvd), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 6, &app.txns_assigned, + sizeof(app.txns_assigned), SQLT_UIN, NULL, NULL,NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 7, &app.txns_applied, + sizeof(app.txns_applied), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmtp, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + cur_app_exists = FALSE; + + printf(" | "); + + for (app_elem = *app_pval; + app_elem != (app_pval_t *)NULL; + app_elem = app_elem->next_app) + { + cur_app = app_elem; + if ((app_elem->applynamelen == app.applynamelen) && + !memcmp((void *)app_elem->applyname, (void *)app.applyname, + (size_t)app_elem->applynamelen)) + { + cur_app_exists = TRUE; + + /* In case the apply had been brought down and then restarted */ + if (app.total_applied >= app_elem->total_applied) + { + if ((diff=(sb4)(app.txns_recvd - app.txns_assigned)) > 10) + { + printf(""); /* indicate apply as the potential bottleneck */ + } + else + { + printf(" - "); /* for alignment */ + } + + printf(" A%03u %u %u", app.applynum, + (app.total_applied - app_elem->total_applied)*100/opts->elapstim, + (app.txns_applied - app_elem->txns_applied)*100/opts->elapstim); + print_latency(app.hwm_latency); + + if (connp->version >= VERSION_10g) + { + print_event_stats(opts, (void *)cur_app, APPLY_READER); + print_event_stats(opts, (void *)cur_app, APPLY_SERVER); + } + + } + else + { + printf(" "); /* for alignment */ + } + + /* update the data for the current apply process */ + app_elem->total_applied = app.total_applied; + app_elem->txns_applied = app.txns_applied; + + break; + } + } + + if (!cur_app_exists) + { + printf(" "); /* for alignment */ + + /* add the data for the new apply process to the linked list */ + new_elem = (app_pval_t *)malloc(sizeof(app_pval_t)); + new_elem->applynum = app.applynum; + memcpy((void *)new_elem->applyname, (void *)app.applyname, + (size_t)app.applynamelen); + new_elem->applynamelen = app.applynamelen; + new_elem->total_applied = app.total_applied; + new_elem->txns_applied = app.txns_applied; + new_elem->server_num = 0; + + new_elem->pevent_reader = NULL; + new_elem->pevent_server = NULL; + new_elem->next_app = (app_pval_t *)NULL; + if (*app_pval == (app_pval_t *)NULL) + { + *app_pval = new_elem; + } + else + { + cur_app->next_app = new_elem; + } + cur_app = new_elem; + + if (connp->version >= VERSION_10g) + { + + /* Add the new sid info to sid_pval list */ + new_sid = (sid_pval_t *)malloc(sizeof(sid_pval_t)); + new_sid->sid = app.sid; + new_sid->pval = new_elem; + new_sid->type = APPLY_READER; + new_sid->next = connp->sid_pval; + + connp->sid_pval = new_sid; + connp->num_sid ++; + + /* Query to find the sids of the apply servers */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, + (oratext *) APPLY_READER_SERVER_SIDS, + sizeof(APPLY_READER_SERVER_SIDS), + OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt2p, &bndp, ocip->errp, 1, + (void *) &(app.applynum), + (sword) sizeof(app.applynum), + SQLT_UIN, + (void *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmt2p, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 1, + &sidval.sid, + sizeof(sidval.sid), SQLT_UIN, NULL, + NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 2, + &sidval.type, + sizeof(sidval.type), SQLT_UIN, NULL, + NULL, NULL, + OCI_DEFAULT)); + + while (OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmt2p, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + new_sid = (sid_pval_t *)malloc(sizeof(sid_pval_t)); + new_sid->sid = sidval.sid; + new_sid->pval = new_elem; + new_sid->type = sidval.type; + new_sid->next = connp->sid_pval; + + connp->sid_pval = new_sid; + connp->num_sid ++; + + if (new_sid->type == APPLY_SERVER) + { + new_elem->server_num++; + } + } + } + } + + } + + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | A ", FALSE); + } + + /* finish the cursor */ + OCICALL(ocip, + OCIStmtFetch2(ocip->stmtp, ocip->errp, 0, OCI_DEFAULT, 0, OCI_DEFAULT)); +} + +#define APPLY_STATS "select ar.sid, ac.apply# applynum, ac.apply_name, ar.TOTAL_MESSAGES_DEQUEUED, \ +nvl(ar.DEQUEUED_MESSAGE_NUMBER,0) DEQUEUED_MESSAGE_NUMBER, ac.total_received, \ +ac.total_assigned, ac.total_applied, nvl(ac.hwm_message_number,0) \ +HWM_MESSAGE_NUMBER, \ +nvl((ac.hwm_time - hwm_message_create_time)*86400, -1) HWM_LATENCY, \ +nvl((ar.dequeue_time - \ + ar.dequeued_message_create_time)*86400, -1) DEQUEUE_LATENCY \ +from v$streams_apply_coordinator ac, \ +v$streams_apply_reader ar where ac.apply#=ar.apply# order by 1" + +#define APPLY_SERVER_SIDS \ +"select sid from v$streams_apply_server where APPLY#=:1 order by 1" + +static void print_apply_stats(options_t * opts, connection_t * connp, + oci_t * ocip, + app_pval_t ** app_pval) +{ + OCIBind *bndp; + OCIDefine *defnp; + apply_t app; + sb4 diff = 0; + sword status = OCI_SUCCESS; + app_pval_t *app_elem; + app_pval_t *new_elem; + app_pval_t *cur_app; + boolean cur_app_exists = FALSE; + sid_pval_t sidval; + sid_pval_t *new_sid = 0; + + /* prepare the apply query */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) APPLY_STATS, + sizeof(APPLY_STATS), OCI_NTV_SYNTAX, OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &app.sid, + sizeof(app.sid), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 2, &app.applynum, + sizeof(app.applynum), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 3, &app.applyname, + sizeof(app.applyname), SQLT_CHR, NULL, + &app.applynamelen, NULL, + OCI_DEFAULT)); + + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 4, &app.msgs_deqd, + sizeof(app.msgs_deqd), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 5, &app.dequeue_scn, + sizeof(app.dequeue_scn), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 6, &app.txns_recvd, + sizeof(app.txns_recvd), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 7,&app.txns_assigned, + sizeof(app.txns_assigned), SQLT_UIN, NULL, NULL,NULL, + OCI_DEFAULT)); + + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 8, &app.txns_applied, + sizeof(app.txns_applied), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 9, &app.hwm_scn, + sizeof(app.hwm_scn), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 10, + &app.hwm_latency, + sizeof(app.hwm_latency), SQLT_INT, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 11, + &app.dequeue_latency, + sizeof(app.txns_recvd), SQLT_INT, NULL, NULL, NULL, + OCI_DEFAULT)); + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmtp, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + cur_app_exists = FALSE; + + for (app_elem = *app_pval; + app_elem != (app_pval_t *)NULL; + app_elem = app_elem->next_app) + { + cur_app = app_elem; + if ((app_elem->applynamelen == app.applynamelen) && + !memcmp((void *)app_elem->applyname, (void *)app.applyname, + (size_t)app_elem->applynamelen)) + { + cur_app_exists = TRUE; + + /* update the data for the current apply process */ + app_elem->total_applied = app.total_applied; + app_elem->txns_applied = app.txns_applied; + + break; + } + } + + if (!cur_app_exists) + { + new_elem = (app_pval_t *)malloc(sizeof(app_pval_t)); + new_elem->applynum = app.applynum; + memcpy((void *)new_elem->applyname, (void *)app.applyname, + (size_t)app.applynamelen); + new_elem->applynamelen = app.applynamelen; + new_elem->total_applied = app.total_applied; + new_elem->txns_applied = app.txns_applied; + new_elem->pevent_reader = NULL; + new_elem->pevent_server = NULL; + new_elem->server_num = 0; + new_elem->next_app = (app_pval_t *)NULL; + if (*app_pval == (app_pval_t *)NULL) + { + *app_pval = new_elem; + } + else + { + cur_app->next_app = new_elem; + } + cur_app = new_elem; + + if (connp->version >= VERSION_10g) + { + + /* Add the new sid info to sid_pval list */ + new_sid = (sid_pval_t *)malloc(sizeof(sid_pval_t)); + new_sid->sid = app.sid; + new_sid->pval = new_elem; + new_sid->type = APPLY_READER; + new_sid->next = connp->sid_pval; + + connp->sid_pval = new_sid; + connp->num_sid ++; + + /* Query to find the sids of the apply servers */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, + (oratext *) APPLY_SERVER_SIDS, + sizeof(APPLY_SERVER_SIDS), + OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt2p, &bndp, ocip->errp, 1, + (void *) &(app.applynum), + (sword) sizeof(app.applynum), + SQLT_UIN, + (void *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmt2p, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 1, + &sidval.sid, + sizeof(sidval.sid), SQLT_UIN, NULL, + NULL, NULL, + OCI_DEFAULT)); + + while (OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmt2p, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + new_sid = (sid_pval_t *)malloc(sizeof(sid_pval_t)); + new_sid->sid = sidval.sid; + new_sid->pval = new_elem; + new_sid->type = APPLY_SERVER; + new_sid->next = connp->sid_pval; + + connp->sid_pval = new_sid; + connp->num_sid ++; + new_elem->server_num++; + } + } + } + + app.dequeue_scn_strlen = 128; + OCICALL(ocip, + OCINumberToText(ocip->errp, &app.dequeue_scn, + (const oratext *)"TM9", 3, (oratext *)0, 0, + &app.dequeue_scn_strlen, app.dequeue_scn_str)); + + app.hwm_scn_strlen = 128; + OCICALL(ocip, + OCINumberToText(ocip->errp, &app.hwm_scn, + (const oratext *)"TM9", 3, (oratext *)0, 0, + &app.hwm_scn_strlen, app.hwm_scn_str)); + + printf(" | "); + + if ((diff=(sb4)(app.txns_recvd - app.txns_assigned)) > 10) + { + printf(" "); /* indicate apply as the potential bottleneck */ + } + else + { + printf(" - "); /* for alignment */ + } + + printf(" A%03u %5u %.*s", app.applynum, app.msgs_deqd, + app.dequeue_scn_strlen, app.dequeue_scn_str); + + print_latency(app.dequeue_latency); + + printf(" %5u %5u %5u %.*s", + app.txns_recvd, app.txns_assigned, app.txns_applied, + app.hwm_scn_strlen, app.hwm_scn_str); + + print_latency(app.hwm_latency); + + if (connp->version >= VERSION_10g) + { + print_event_stats(opts, (void *)cur_app, APPLY_READER); + print_event_stats(opts, (void *)cur_app, APPLY_SERVER); + } + } + + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | A ", FALSE); + } + + /* finish the cursor */ + OCICALL(ocip, + OCIStmtFetch2(ocip->stmtp, ocip->errp, 0, OCI_DEFAULT, 0, OCI_DEFAULT)); +} + +#define MEM_STATS_10g "select frused_kwqbpmt from x$kwqbpmt" + +static void print_mem_stats(options_t * opts, oci_t * ocip) +{ + OCIDefine *defnp; + ub2 mem_used; + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) MEM_STATS_10g, + sizeof(MEM_STATS_10g), OCI_NTV_SYNTAX, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &mem_used, + sizeof(mem_used), SQLT_UIN, NULL, + NULL, NULL, OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 1, 0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_EXACT_FETCH)); + + printf(" | MEM %u %% ", mem_used); + print_pool_size(ocip); +} + + +#define VERSION_SQL "select version, instance_name from v$instance" + +static void get_version(connection_t * connp) +{ + OCIDefine *defnp; + ub2 i; + oratext tempstr[20]; + ub2 tempstrlen; + oci_t *ocip = connp->ocip; + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) VERSION_SQL, + sizeof(VERSION_SQL), OCI_NTV_SYNTAX, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, + (void *)connp->versionstr, + sizeof(connp->versionstr), SQLT_CHR, NULL, + &connp->versionstrlen, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 2, + (void *)connp->instname, + sizeof(connp->instname), SQLT_CHR, NULL, + &connp->instnamelen, NULL, OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 1, 0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_EXACT_FETCH)); + + tempstrlen = 0; + for (i=0; iversionstrlen; i++) + { + if (connp->versionstr[i] == '.') + { + continue; + } + tempstr[tempstrlen++] = connp->versionstr[i]; + } + tempstr[tempstrlen] = '\0'; + sscanf((char *)tempstr,"%u", &connp->version); + + if (connp->version < VERSION_9iR2) + { + printf("Error: ORACLE version %.*s didn't have STREAMS\n", + connp->versionstrlen, connp->versionstr); + exit(1); + } +} + +static void print_latency(sb4 latency) +{ + if (latency < 0) + { + printf(" -"); + } + else if (latency < 60) + { + printf(" %usec", latency); + } + else if (latency < 60*60) + { + printf(" %umin", (latency/60)); + } + else if (latency < 60*60*24) + { + printf(" %uhr ", (latency/(60*60))); + } + else if (latency < 60*60*24*12) + { + printf(" %uday", (latency/(60*60*24))); + } + else if (latency < 60*60*24*12*30) + { + printf(" %umon", (latency/(60*60*24*12))); + } + else + { + printf(" %uyr ", (latency/(60*60*24*12))); + } +} + +#define LGWR_STATS_SCN "select (LAST_WRITE_SCN_BAS + \ +(4294967296*LAST_WRITE_SCN_WRP)) LAST_WRITE_SCN from x$kcrfws" + +#define LGWR_STATS_BLKS "select value from v$sysstat where name =\ +'redo blocks written'" + +typedef struct lgwr +{ + OCINumber last_scn; + OCINumber last_blk; +} lgwr_t; + +static void print_log_stats(options_t * opts, oci_t * ocip, ub4 *lgwr_pval) +{ + + lgwr_t log; + OCIBind *bndp; + OCIDefine *defnp; + sb4 redo_rate; + OCINumber result; + ub4 int_result; + ub4 diff; + + /* get the count of blocks written */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) LGWR_STATS_BLKS, + sizeof(LGWR_STATS_BLKS), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + defnp = (OCIDefine *)0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &log.last_blk, + sizeof(log.last_blk), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_EXACT_FETCH)); + + /* for long option, we need to get the last scn also and print out + * the number of blocks and last scn as a string */ + if (!opts->short_opt) + { + oratext last_scn_str[128]; + ub4 last_scn_strlen = 128; + oratext last_blk_str[128]; + ub4 last_blk_strlen = 128; + + /* get the last scn written */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) LGWR_STATS_SCN, + sizeof(LGWR_STATS_SCN), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + defnp = (OCIDefine *)0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &log.last_scn, + sizeof(log.last_scn), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_EXACT_FETCH)); + + OCICALL(ocip, + OCINumberToText(ocip->errp, &log.last_scn, + (const oratext *)"TM9", 3, (oratext *)0, 0, + &last_scn_strlen, last_scn_str)); + + OCICALL(ocip, + OCINumberToText(ocip->errp, &log.last_blk, + (const oratext *)"TM9", 3, (oratext *)0, 0, + &last_blk_strlen, last_blk_str)); + + printf(" | LOG %s %6s", last_scn_str, last_blk_str); + } + else + { + OCICALL(ocip, + OCINumberToInt(ocip->errp, &log.last_blk, sizeof(int_result), + OCI_NUMBER_UNSIGNED, &int_result)); + + if (*lgwr_pval) + { + /* take care of the case where the block number wraps around */ + if (int_result < *lgwr_pval) + { + printf(" | LOG - "); + } + else + { + redo_rate = (sb4)(((int_result - *lgwr_pval)*512*100)/(opts->elapstim)); + + printf(" | LOG "); + print_bytes((ub8)redo_rate); + } + } + + /* update the previous value last block number */ + *lgwr_pval = int_result; + } +} + +#define NET_STATS_CLIENT "select sum(value) from v$sysstat where name like\ +'bytes%client'" + +#define NET_STATS_DBLINK "select sum(value) from v$sysstat where name like\ +'bytes%dblink'" + +static void print_net_stats(options_t * opts, connection_t * connp) +{ + oci_t *ocip = connp->ocip; + OCIBind *bndp; + OCIDefine *defnp; + OCINumber client_bytes_num; + OCINumber dblink_bytes_num; + ub8 client_bytes; + ub8 dblink_bytes; + + /* get the client stats */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) NET_STATS_CLIENT, + sizeof(NET_STATS_CLIENT), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + defnp = (OCIDefine *)0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &client_bytes_num, + sizeof(client_bytes_num), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_EXACT_FETCH)); + + /* get the dblink stats */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) NET_STATS_DBLINK, + sizeof(NET_STATS_DBLINK), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + defnp = (OCIDefine *)0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &dblink_bytes_num, + sizeof(dblink_bytes_num), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_EXACT_FETCH)); + + + /* convert OCI Numbers to ub8s */ + OCICALL(ocip, OCINumberToInt(ocip->errp, &client_bytes_num, + sizeof(client_bytes), OCI_NUMBER_UNSIGNED, + &client_bytes)); + + OCICALL(ocip, OCINumberToInt(ocip->errp, &dblink_bytes_num, + sizeof(dblink_bytes), OCI_NUMBER_UNSIGNED, + &dblink_bytes)); + + if (opts->short_opt) + { + if (connp->client_bytes || connp->dblink_bytes) + { + printf(" | NET "); + print_bytes((client_bytes - connp->client_bytes)*100/opts->elapstim); + printf(" "); + print_bytes((dblink_bytes - connp->dblink_bytes)*100/opts->elapstim); + } + + connp->client_bytes = client_bytes; + connp->dblink_bytes = dblink_bytes; + } + else + { + printf(" | NET %llu %llu", client_bytes, dblink_bytes); + } +} + + +static void print_event_stats (options_t * opts, void* pval, process_type_t type) +{ + ub8 idleTime = 0; + ub8 flowControlTime = 0; + ub8 maxEventTime = 0; + + ub8 idle_rate = 0; + ub8 flowcontrol_rate = 0; + ub8 max_event_rate = 0; + ub8 sum_rate = 0; + ub8 total_rate = 100; + ub8 time_diff; + + event_pval_t** pevt; + event_pval_t* cur = NULL; + event_pval_t* maxEvt = NULL; + ub2 i = 0; + const char* idle_events; + const char* flowcontrol_events; + char event_name[800]; + OCIBind *bndp; + + if (pval == NULL) + return; + + /*Construct the sqlcommand*/ + if (type == CAPTURE_PROCESS) + { + cap_pval_t * cap_pval = (cap_pval_t *)pval; + pevt = &(cap_pval->pevent); + + idle_events = capture_idle_events; + flowcontrol_events = capture_flowcontrol_events; + } + + else if (type == PR_SENDER_PROCESS) + { + + prop_pval_t * prop_pval = (prop_pval_t *)pval; + pevt = &(prop_pval->pevent_sender); + + idle_events = propagation_sender_idle_events; + flowcontrol_events = propagation_sender_flowcontrol_events; + } + else if (type == PR_RECEIVER_PROCESS) + { + + prop_pval_t * prop_pval = (prop_pval_t *)pval; + pevt = &(prop_pval->pevent_receiver); + + idle_events = propagation_receiver_idle_events; + flowcontrol_events = propagation_receiver_flowcontrol_events; + } + else if (type == APPLY_READER) + { + app_pval_t * app_pval = (app_pval_t *)pval; + pevt = &(app_pval->pevent_reader); + + printf(" AR:"); + + idle_events = apply_reader_idle_events; + flowcontrol_events = apply_reader_flowcontrol_events; + } + else if (type == APPLY_SERVER) + { + app_pval_t * app_pval = (app_pval_t *)pval; + pevt = &(app_pval->pevent_server); + + /* For apply server, maxEvt contains the number of apply server + process. total rate is 100 * number of apply server process. + */ + if (app_pval->server_num > 0) + total_rate = 100 * app_pval->server_num; + + printf(" AS(%d)", app_pval->server_num); + + idle_events = apply_server_idle_events; + flowcontrol_events = apply_server_flowcontrol_events; + } + + if (*pevt == NULL) return; + + for (cur = (*pevt); cur != NULL; cur = cur->next_event) + { + + sprintf(event_name, "|%.*s|\0",cur->event_namelen, cur->event_name); + time_diff = cur->time_in_micro_second - cur->time_in_micro_second_old; + if (strstr(idle_events,event_name)) + { + idleTime += time_diff; + continue; + } + + else if (strstr(flowcontrol_events,event_name)) + { + flowControlTime += time_diff; + continue; + } + else if (time_diff > maxEventTime) + { + maxEventTime = time_diff; + maxEvt = cur; + } + } + + /* printf("\nidle: %llu, flowcontrol: %llu, maxeventtime: %llu \n", idleTime, flowControlTime, maxEventTime); + */ + idle_rate = idleTime/opts->elapstim/100; + + flowcontrol_rate = flowControlTime/opts->elapstim/100; + + max_event_rate = maxEventTime/opts->elapstim/100; + + sum_rate = idle_rate + flowcontrol_rate + max_event_rate; + + if (sum_rate > total_rate) + { + idle_rate = (idle_rate * total_rate) / sum_rate; + flowcontrol_rate = (flowcontrol_rate * total_rate) / sum_rate; + max_event_rate = (max_event_rate * total_rate) / sum_rate; + } + + if ((opts->short_opt && max_event_rate < 5) || max_event_rate < 1) + { + printf(" <%llu%%I %llu%%F -> ", idle_rate, flowcontrol_rate); + } + else + printf(" <%llu%%I %llu%%F %llu%%\"%.*s\"> ", idle_rate, flowcontrol_rate, max_event_rate, maxEvt->event_namelen, maxEvt->event_name); + + fflush(stdout); + +} + +#define WAIT_EVENT_STATS \ + "select sid, event, TIME_WAITED_MICRO from V$SESSION_EVENT s where sid in %s order by 1" + +static void collect_event_data (options_t * opts, connection_t *connp) +{ + oci_t *ocip = connp->ocip; + OCIDefine *defnp; + event_pval_t wevt; + event_pval_t **pevt; + event_pval_t *cur = NULL; + sword status = OCI_SUCCESS; + OCINumber time_in_micro_second; + ub2 found; + char eventquery[3072]; + ub4 eventquerylen; + sid_pval_t *sidpval; + char *curpos; + ub4 in_process_sid = 0; + + if (connp->num_sid <= 0) return; + + if (connp->num_sid != connp->org_sid) { + sidpval = connp->sid_pval; + sprintf(connp->sidstr, "(%d", sidpval->sid); + sidpval = sidpval->next; + curpos = connp->sidstr + strlen(connp->sidstr); + + while (sidpval != NULL) { + sprintf(curpos, ",%d", sidpval->sid); + sidpval = sidpval->next; + curpos = curpos + strlen(curpos); + } + + sprintf(curpos, ")"); + + connp->org_sid = connp->num_sid; + + /* Reinitial sidpval to NULL */ + sidpval = NULL; + + } + + (ub4)sprintf(eventquery, WAIT_EVENT_STATS, connp->sidstr); + eventquerylen = strlen(eventquery); + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt3p, ocip->errp, + (oratext *) eventquery, + eventquerylen, OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + /* Start to query V$SESSION_EVENT to get the wait_event data.*/ + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmt3p, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt3p, &defnp, ocip->errp, 1, &wevt.sidnum, + sizeof(wevt.sidnum), SQLT_UIN, NULL, + NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt3p, &defnp, ocip->errp, 2, + &wevt.event_name, sizeof(wevt.event_name), + SQLT_CHR, NULL, &wevt.event_namelen, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt3p, &defnp, ocip->errp, 3, &time_in_micro_second, + sizeof(time_in_micro_second), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmt3p, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + OCICALL(ocip, + OCINumberToInt(ocip->errp, &time_in_micro_second, 8, OCI_NUMBER_UNSIGNED, &(wevt.time_in_micro_second))); + + + if (wevt.sidnum != in_process_sid || sidpval == NULL) + { + in_process_sid = wevt.sidnum; + + sidpval = connp->sid_pval; + while ( sidpval != NULL && sidpval->sid != in_process_sid) + { + sidpval = sidpval->next; + } + } + + if (sidpval == NULL) + { + /* error out */ + } + + if (sidpval->type == CAPTURE_PROCESS) + { + pevt = &(((cap_pval_t *)sidpval->pval)->pevent); + } + else if (sidpval->type == PR_SENDER_PROCESS) + { + pevt = &(((prop_pval_t *)sidpval->pval)->pevent_sender); + } + else if (sidpval->type == PR_RECEIVER_PROCESS) + { + pevt = &(((prop_pval_t *)sidpval->pval)->pevent_receiver); + } + else if (sidpval->type == APPLY_READER) + { + pevt = &(((app_pval_t *)sidpval->pval)->pevent_reader); + } + else if (sidpval->type == APPLY_SERVER) + { + pevt = &(((app_pval_t *)sidpval->pval)->pevent_server); + } + + found = 0; + + for (cur = *pevt; cur != NULL; cur = cur->next_event) + { + if ((cur->event_namelen == wevt.event_namelen) && !strncmp((const char *)cur->event_name, (const char *)wevt.event_name, wevt.event_namelen)) + { + found = 1; + break; + } + } + + if(found) + { + if (opts->iters > cur->iters) + { + /* Save old time_in_micro_second */ + cur->time_in_micro_second_old = cur->time_in_micro_second; + + /* Update time_in_micro_second */ + cur->time_in_micro_second = wevt.time_in_micro_second; + cur->iters = opts->iters; + } + /* Where there are multiple apply servers */ + else if ( opts->iters == cur->iters) + { + cur->time_in_micro_second += wevt.time_in_micro_second; + } + } + else { + /* Two possibilities: First time monitor or new wait event */ + event_pval_t *evt = (event_pval_t *)malloc(sizeof(event_pval_t)); + + evt->sidnum = wevt.sidnum; + memcpy((void *)evt->event_name, (void *)wevt.event_name, (size_t)wevt.event_namelen); + evt->event_namelen = wevt.event_namelen; + + evt->time_in_micro_second = wevt.time_in_micro_second; + evt->time_in_micro_second_old = 0; + evt->iters = opts->iters; + evt->next_event = NULL; + + if (*pevt == NULL) + { + *pevt = evt; + } + else { + evt->next_event = *pevt; + *pevt = evt; + } + } + } + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | A ", FALSE); + } + +} + +static void print_bytes(ub8 bytes) +{ + if (bytes < 1024) + { + printf("%llu", bytes); + } + else if (bytes < (1024*1024)) + { + printf("%lluK", bytes/1024); + } + else if (bytes < 1000000000) + { + printf("%lluM", bytes/(1024*1024)); + } + else + { + printf("%lluG", bytes/(1024*1024*1024)); + } +} + +/* end of file strmmon.c */ + diff --git a/strmmv1.sql b/strmmv1.sql new file mode 100644 index 0000000..37385f3 --- /dev/null +++ b/strmmv1.sql @@ -0,0 +1,363 @@ +Rem +Rem $Header: strmmv1.sql 13-dec-2006.02:59:43 davzhang Exp $ +Rem +Rem strmmv1.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem strmmv1.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem davzhang 12/13/06 - drop job before drop user +Rem davzhang 08/29/06 - where clause when selecting from +Rem dba_apply_instantiated_objects +Rem liwong 05/16/06 - sync capture cleanup +Rem davzhang 04/18/06 - wait for job queue before drop user +Rem wesmith 01/19/06 - Created +Rem + +set echo on +set pages 10000 +set serveroutput on +COLUMN STREAMS_TYPE HEADING 'STREAMS_TYPE' FORMAT A19 + +connect system/manager + +-- +-- create user for MVs +-- +drop user tabowner cascade; +grant connect, resource, create materialized view to tabowner + identified by tabowner; + +-- +-- create procedure to wait for job queue processes to finish +-- +set echo off +grant create any job to system; +CREATE OR REPLACE PROCEDURE wait_for_jobq AS + JQ_COUNT NUMBER :=1; + WAIT_SEC NUMBER :=600; + cursor stradm_jobs is + select owner,job_name from dba_scheduler_jobs + where owner='STRADM'; +BEGIN + for rec in stradm_jobs loop + sys.dbms_scheduler.drop_job( + job_name => rec.owner || '.' || rec.job_name, + force => true); + end loop; + -- disable job queue, make sure no jobs are started from now + -- wait for given time + SYS.DBMS_IJOB.SET_ENABLED(FALSE); + WAIT_SEC := WAIT_SEC * 2; + FOR I IN 1..WAIT_SEC LOOP + DBMS_LOCK.SLEEP(0.5); + -- any removed job still running? + SELECT COUNT(*) INTO JQ_COUNT + FROM V$LOCK V + WHERE V.TYPE = 'JQ' AND NOT EXISTS + (SELECT * FROM DBA_JOBS J WHERE V.ID2=J.JOB); + IF JQ_COUNT<=0 THEN + EXIT; + END IF; + END LOOP; + IF JQ_COUNT>0 THEN + -- ISSUE USER-DEFINED ERROR MESSAGE. + RAISE_APPLICATION_ERROR(-20101, 'Time Out Waiting Jobs To Finish'); + END IF; + SYS.DBMS_IJOB.SET_ENABLED(TRUE); +END; +/ +set echo on +-- +-- create tables, mvlogs, mvs +-- +connect tabowner/tabowner +create table foo (c1 number primary key, c2 varchar2(20)); +create table bar (c1 number, c2 varchar2(20)); + +create materialized view log on foo; +create materialized view log on bar with rowid; + +create materialized view foo_s refresh fast as select * from foo; +create materialized view bar_s refresh fast with rowid as select * from bar; + + +-- grant necessary privileges for streams admin +connect system/manager + +drop user stradm cascade; +grant dba to stradm identified by stradm; +begin + dbms_streams_auth.grant_admin_privilege( + grantee => 'stradm', + grant_privileges => true); +end; +/ + +-- +-- create package async_mv_pkg for async on-commit MV support +-- +connect stradm/stradm +set echo off +@strmmvp1 +set echo on + +-- +-- streams setup +-- +begin + dbms_streams_adm.set_up_queue( + queue_table => 'stradm.ASYNC_MV_QT', + queue_name => 'stradm.ASYNC_MV_Q'); +end; +/ + +variable site1 varchar2(80); +execute select global_name into :site1 from global_name; +print site1; + +-- set up streams for all tables with MV logs +exec async_mv_pkg.register_tables('CAPTURE_MV', 'APPLY_MV'); + +begin + dbms_apply_adm.set_parameter( + apply_name => 'APPLY_MV', + parameter => 'disable_on_error', + value => 'n'); +end; +/ + +-- assign precommit handler to apply process +begin + dbms_apply_adm.alter_apply( + apply_name => 'APPLY_MV', + precommit_handler => 'stradm.async_mv_pkg.async_mv_commit_hdlr'); +end; +/ + +begin + dbms_apply_adm.start_apply( + apply_name => 'APPLY_MV'); +end; +/ + +begin + dbms_capture_adm.start_capture( + capture_name => 'CAPTURE_MV'); +end; +/ + +-- check streams metadata +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE_MV', 'APPLY_MV') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='TABOWNER' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV' +order by object_owner, object_name, operation_name; + +-- do some DMLs +connect tabowner/tabowner +insert into foo values (1, 'foo_a'); +insert into foo values (2, 'foo_b'); +insert into bar values (1, 'bar_a'); +insert into bar values (2, 'bar_b'); +commit; + +update foo set c2 = 'foo_b_updated' where c1=2; +delete from foo where c1=1; +commit; + +update bar set c2 = 'bar_b_updated' where c1=2; +delete from bar where c1=1; +commit; + +-- wait for streams to finish +set serveroutput on +set timing on +exec verify_tables('foo','foo_s'); +exec verify_tables('bar','bar_s'); +set timing off + +-- check for convergence (verify that refresh_dependent was called) +select * from foo; +select * from foo_s; + +select * from bar; +select * from bar_s; + +-- submit a job to register new tables having MV logs every minute +connect stradm/stradm +declare + l_jobnum number; + str varchar2(100); +begin + str := + 'begin ' || + ' stradm.async_mv_pkg.register_tables(''CAPTURE_MV'',''APPLY_MV''); ' || + ' commit; ' || + 'end;'; + + dbms_scheduler.create_job( + job_name => dbms_scheduler.generate_job_name, + job_type => 'PLSQL_BLOCK', + job_action => str, + start_date => sysdate, + repeat_interval => 'FREQ=minutely', + enabled => TRUE); + + commit; +end; +/ + +-- create another table with an MV log and MV on it and verify that +-- it is set up for streams +connect tabowner/tabowner +create table foo2 (c1 number primary key, c2 varchar2(20)); +create materialized view log on foo2; +create materialized view foo2_s refresh fast as select * from foo2; + +-- wait for the register_tables() job to finish +set serveroutput on +exec verify_table_rules('TABOWNER', 'FOO2', true); + +-- do some dmls +insert into foo2 values (1, 'foo_a'); +insert into foo2 values (2, 'foo_b'); +commit; +update foo2 set c2 = 'foo2_b_updated' where c1=2; +delete from foo2 where c1=1; +commit; + +-- check streams metadata: should include foo2 +connect stradm/stradm +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE_MV', 'APPLY_MV') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='TABOWNER' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV' +order by object_owner, object_name, operation_name; + +-- wait for streams to finish +connect tabowner/tabowner +set serveroutput on +set timing on +exec verify_tables('foo2','foo2_s'); +set timing off + +-- check for convergence (verify that refresh_dependent was called) +select * from foo2; +select * from foo2_s; + +-- submit a job to unregister tables no longer having MV logs every minute +connect stradm/stradm +declare + l_jobnum number; + str varchar2(100); +begin + str := + 'begin ' || + ' stradm.async_mv_pkg.unregister_tables(''CAPTURE_MV'',''APPLY_MV''); ' || + ' commit; ' || + 'end;'; + + dbms_scheduler.create_job( + job_name => dbms_scheduler.generate_job_name, + job_type => 'PLSQL_BLOCK', + job_action => str, + start_date => sysdate, + repeat_interval => 'FREQ=minutely', + enabled => TRUE); + + commit; +end; +/ + +--- now drop an mvlog from foo, all streams metadata should be removed for foo +connect tabowner/tabowner +drop materialized view log on foo; + +-- wait for the unregister_tables() job to finish +set serveroutput on +exec verify_table_rules('TABOWNER', 'FOO', false); + +-- check streams metadata: should not include foo +connect stradm/stradm +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE_MV', 'APPLY_MV') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='TABOWNER' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV' +order by object_owner, object_name, operation_name; + +-- drop mvlog on bar, foo2 +connect tabowner/tabowner +drop materialized view log on bar; +drop materialized view log on foo2; + +-- remove async_mv streams configuration +connect stradm/stradm +exec async_mv_pkg.remove_async_mv_streams('CAPTURE_MV', 'APPLY_MV'); + +select 1 from dba_capture where capture_name = 'CAPTURE_MV'; +select 1 from dba_apply where apply_name = 'APPLY_MV'; + +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE_MV', 'APPLY_MV'); + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='TABOWNER' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV' +order by object_owner, object_name, operation_name; + +-- cleanup +connect system/manager +exec wait_for_jobq; +drop user tabowner cascade; +drop user stradm cascade; diff --git a/strmmv1README.txt b/strmmv1README.txt new file mode 100644 index 0000000..d154e89 --- /dev/null +++ b/strmmv1README.txt @@ -0,0 +1,62 @@ +/ +/ $Header: strmmv1README.txt 24-jan-2006.16:01:05 wesmith Exp $ +/ +/ strmmv1README.txt +/ +/ Copyright (c) 2006, Oracle. All Rights Reserved. +/ +/ NAME +/ strmmv1README.txt - +/ +/ DESCRIPTION +/ +/ +/ NOTES +/ +/ +/ MODIFIED (MM/DD/YY) +/ wesmith 01/24/06 - Creation +/ + +Asynchronous commit-time MV refresh using Streams + +This script creates a package with the following procedures: +- register_tables() which sets up streams for all tables with MV logs +- unregister_tables() which removes streams for all tables that no longer + have MV logs +- apply DML handler which caches all tables involved in a transaction in + a package state variable +- apply pre-commit handler which submits a job to call refresh_dependent + (in this package) on all tables that were cached. +- refresh_dependent() which calls dbms_mview.refresh_dependent() after + possibly eliminating tables that no longer have any dependent MVs that + need refreshing (due to other concurrent refresh_dependent() jobs). + Nested MVs are refreshed too, if required. +- remove_async_mv_streams() which removes ASYNC_MV streams configuration +Using this package will allow you to set up local MVs that will refresh +asynchronously at commit-time using Streams. + +NOTES: +- refresh_dependent() references all_refresh_dependencies which gives the + oldest refresh scn for a master table, so + commit_scn > oldest_refresh_scn implies that at least one dependent MV + is stale. So calling dbms_mview.refresh_dependent() may still + result in null refreshes. It may be possible to modify this procedure + to consider the last refresh scn of each dependent MV. + +- refresh_dependent() does not consider refresh groups. It may be possible + to modify this to consider additional refresh group views. + +Instructions: +- create streams administrator +- create streams queue +- call async_mv_pkg.register_tables() passing a special capture and apply name +- set applicable apply parameters +- call dbms_apply_adm.alter_apply to assign precommit handler to apply process +- start capture and apply +- you can submit jobs for async_mv_pkg.register_tables(), + async_mv_pkg.unregister_tables() + to keep track of new tables with MV logs, or tables that no longer have + MV logs, simplifying the administration. +- call async_mv_pkg.remove_async_mv_streams() to remove the streams + configuration for async MV refresh. diff --git a/strmmv2.sql b/strmmv2.sql new file mode 100644 index 0000000..1d5d77f --- /dev/null +++ b/strmmv2.sql @@ -0,0 +1,493 @@ +Rem +Rem $Header: strmmv2.sql 27-sep-2006.15:36:22 davzhang Exp $ +Rem +Rem strmmv2.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem strmmv2.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem davzhang 09/27/06 - grant create view explicitly +Rem davzhang 08/29/06 - where clause when selecting from +Rem dba_apply_instantiated_objects +Rem wesmith 06/23/06 - register_mv: add parameter queue_name +Rem wesmith 06/12/06 - remove wait_for_jobq() call and misc cleanup +Rem liwong 05/16/06 - sync capture cleanup +Rem davzhang 04/18/06 - wait for job queue before drop user +Rem wesmith 01/19/06 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 10000 +SET SERVEROUTPUT ON + +COLUMN SRC_LONG_CNAME FORMAT A15 +COLUMN SCHEMA_NAME FORMAT A15 +COLUMN OBJECT_NAME FORMAT A15 +COLUMN STREAMS_TYPE HEADING 'STREAMS_TYPE' FORMAT A19 + +variable site1 varchar2(80); + +-- grant necessary privileges for streams admin +connect system/manager + +drop user stradm cascade; +grant dba to stradm identified by stradm; +grant execute on SYS.DBMS_SYSTEM to stradm; +begin + dbms_streams_auth.grant_admin_privilege( + grantee => 'stradm', + grant_privileges => true); +end; +/ + +-- create user for MVs +drop user sqst cascade; +grant connect, resource to sqst identified by sqst; +grant create materialized view, create view to sqst; + +connect sqst/sqst + +-- create base tables and load +set echo off +@strmmv2s +set echo on + +-- create views to aid data verification +create view orders_v as +select o_id, orders.c_id c_id, ol_num, + orders.rowid o_rid, customer.rowid c_rid +from orders, customer +where orders.c_id = customer.c_id +and customer.zip >= 19555; + +create view oline_v as +select ol_id, order_line.o_id, i_id, + order_line.rowid ol_rid, orders.rowid o_rid, customer.rowid c_rid +from order_line, orders, customer +where order_line.o_id = orders.o_id +and orders.c_id = customer.c_id +and customer.zip >= 19555; + +-- MV logs +--create materialized view log on orders with primary key, rowid; +--create materialized view log on order_line with rowid; +--create materialized view log on customer with primary key, rowid(zip); + +-- MJV +create materialized view orders_mv refresh force as +select o_id, orders.c_id, ol_num, orders.rowid o_rid, customer.rowid c_rid +from orders, customer +where orders.c_id = customer.c_id +and customer.zip >= 19555; + +-- another MJV +create materialized view oline_mv refresh force as +select ol_id, order_line.o_id, i_id, + order_line.rowid ol_rid, orders.rowid o_rid, customer.rowid c_rid +from order_line, orders, customer +where order_line.o_id = orders.o_id +and orders.c_id = customer.c_id +and customer.zip >= 19555; + +create unique index oline_mv_u1 on oline_mv(ol_rid, o_rid, c_rid); + +-- pk-based MV (single table) +create materialized view customer_mv refresh force as select * from customer; + +-- +-- create unsupported MVs +-- + +-- rowid MV +create materialized view bad_rowid refresh force with rowid as +select * from customer; + +-- on-commit MV +create materialized view bad_oncmt refresh force with rowid on commit as +select * from customer; + +-- updatable MV +create materialized view bad_upd refresh force for update as +select * from customer; + +-- subquery MV +create materialized view bad_sq refresh force as +select o_id, orders.c_id, ol_num from orders + where exists + (select c_id from customer + where zip >= 19555 and orders.c_id = customer.c_id); + +-- union all MJV +create materialized view bad_mjv_union_all refresh force as +select '1' mark, o_id, orders.c_id, ol_num, orders.rowid o_rid, + customer.rowid c_rid +from orders, customer +where orders.c_id = customer.c_id +and customer.zip >= 19555 +union all +select '2' mark, o_id, orders.c_id, ol_num, orders.rowid o_rid, + customer.rowid c_rid +from orders, customer +where orders.c_id = customer.c_id +and customer.zip <= 11005; + +-- MV with objects +create or replace type t1 as object (a1 number, a2 date) +/ +create table objreltab (c1 number primary key, c2 t1, c3 varchar2(10)); +create snapshot log on objreltab; +create materialized view bad_obj refresh force as select * from objreltab; + + +-- create supporting objects and packages for streams refresh metadata +connect stradm/stradm +set echo off +@strmmvp2 +set echo on + +-- +-- streams setup +-- +begin + dbms_streams_adm.set_up_queue + (queue_user => 'stradm', queue_name => 'mv_master_q', + queue_table => 'mv_master_qt'); +end; +/ + +-- setting key columns is mandatory if a primary key does not exist on the MV +exec dbms_apply_adm.set_key_columns('SQST.ORDERS_MV', 'o_rid, c_rid'); +exec dbms_apply_adm.set_key_columns('SQST.OLINE_MV', 'ol_rid, o_rid, c_rid'); + +-- register orders_mv for dbms_mview.refresh() +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'"SQST"', mv_name=>'"ORDERS_MV"', + capture_name=>'"CAPTURE"', apply_name=>'"APPLY_MV_MASTER"', + queue_name=>'mv_master_q', + instantiate=>FALSE, use_streams_refresh=>FALSE); +end; +/ + +-- register oline_mv, customer_mv for streams-based refresh +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'sqst', mv_name=>'oline_mv', + capture_name=>'capture', apply_name=>'apply_mv_master', + instantiate=>TRUE, use_streams_refresh=>TRUE); +end; +/ + +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'SQST', mv_name=>'CUSTOMER_MV', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + instantiate=>FALSE, use_streams_refresh=>TRUE); +end; +/ + +-- FAIL: non-existent MV +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'SQST', mv_name=>'no_such_mv', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + instantiate=>FALSE, use_streams_refresh=>TRUE); +end; +/ + +-- +-- unsupported registrations for streams-based refresh (neg testcases) +-- +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'SQST', mv_name=>'BAD_ROWID', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + instantiate=>FALSE, use_streams_refresh=>TRUE); +end; +/ +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'SQST', mv_name=>'BAD_ONCMT', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + instantiate=>FALSE, use_streams_refresh=>TRUE); +end; +/ +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'SQST', mv_name=>'BAD_UPD', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + instantiate=>FALSE, use_streams_refresh=>TRUE); +end; +/ +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'SQST', mv_name=>'BAD_SQ', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + instantiate=>FALSE, use_streams_refresh=>TRUE); +end; +/ +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'SQST', mv_name=>'BAD_MJV_UNION_ALL', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + instantiate=>FALSE, use_streams_refresh=>TRUE); +end; +/ + + +connect stradm/stradm +exec dbms_capture_adm.start_capture('CAPTURE'); + +exec dbms_apply_adm.set_parameter('APPLY_MV_MASTER','DISABLE_ON_ERROR','N'); + +-- assign precommit handler to apply process +begin + dbms_apply_adm.alter_apply( + apply_name => 'APPLY_MV_MASTER', + precommit_handler => 'streams_mv_refresh.source_commit_hdlr'); +end; +/ +exec dbms_apply_adm.start_apply('APPLY_MV_MASTER'); + +-- check streams metadata +select apply_name, status from dba_apply order by apply_name; +select capture_name, status from dba_capture order by 1,2; + +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='SQST' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +-- check MV registration metadata +select mv_owner, mv_name from stmv_reg order by mv_owner, mv_name; + +-- do some DMLs +connect sqst/sqst +set serveroutput on +update customer set zip = 0; +update order_line set i_id = 101 where ol_id < 800; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('customer','customer_mv'); +set timing off + +-- 0 rows expected +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; + +update customer set zip = 19555 where c_id > 5; +update order_line set i_id = 61 where ol_id >= 800; +-- update primary key +update order_line set ol_id = 599 where ol_id = 522; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('customer','customer_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; + +update customer set zip = -19555 where zip > 19455; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('customer','customer_mv'); +set timing off + +--0 rows +select o_id, c_id, ol_num from orders_mv order by o_id; +--0 rows +select ol_id, o_id, i_id from oline_mv order by ol_id; + + +update customer set zip = 19556 where zip = -19555; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('customer','customer_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; + +delete from order_line where o_id = 71; +delete from orders where c_id = 6; +delete from customer where c_id = 9; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('customer','customer_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; + +insert into customer (c_id, zip) values (101, 29555); +insert into orders (o_id, c_id, ol_num) values (1001, 101, 11); +insert into orders (o_id, c_id, ol_num) values (1002, 101, 11); +delete from orders where o_id < 22; +update orders set c_id = 7 where c_id = 5; +update order_line set o_id = 2 where o_id = 82; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('customer','customer_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; + +-- Cleanup +connect stradm/stradm + +-- FAIL: apply must be stopped before you can unregister an MV +begin + streams_mv_refresh_adm.unregister_mv( + mv_owner=>'sqst', mv_name=>'"OLINE_MV"', + capture_name=>'CAPTURE', apply_name=>'apply_mv_master'); +end; +/ + +exec dbms_apply_adm.stop_apply('APPLY_MV_MASTER'); + +-- unregister one MV +begin + streams_mv_refresh_adm.unregister_mv( + mv_owner=>'sqst', mv_name=>'"OLINE_MV"', + capture_name=>'CAPTURE', apply_name=>'apply_mv_master'); +end; +/ + +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='SQST' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +select mv_owner, mv_name from stmv_reg order by mv_owner, mv_name; + +-- unregister the remaining MVs +begin + streams_mv_refresh_adm.unregister_mv( + mv_owner=>'SQST', mv_name=>'ORDERS_MV', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER'); +end; +/ + +begin + streams_mv_refresh_adm.unregister_mv( + mv_owner=>'sqst', mv_name=>'customer_mv', + capture_name=>'capture', apply_name=>'apply_mv_master'); +end; +/ + +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='SQST' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +select mv_owner, mv_name from stmv_reg order by mv_owner, mv_name; + +-- remove streams configuration +begin + streams_mv_refresh_adm.remove_streams_mv_refresh( + 'CAPTURE', 'apply_mv_master'); +end; +/ + +select 1 from dba_capture where capture_name = 'CAPTURE'; +select 1 from dba_apply where apply_name = 'APPLY_MV_MASTER'; + +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER'); + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='SQST' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +-- check mvs +select name, refresh_method, type, refresh_mode +from dba_snapshots where owner = 'SQST' order by name; + +-- cleanup +connect system/manager +drop user stradm cascade; +drop user sqst cascade; diff --git a/strmmv2README.txt b/strmmv2README.txt new file mode 100644 index 0000000..ee51075 --- /dev/null +++ b/strmmv2README.txt @@ -0,0 +1,272 @@ +/ +/ $Header: strmmv2README.txt 08-sep-2006.14:04:06 wesmith Exp $ +/ +/ strmmv2README.txt +/ +/ Copyright (c) 2006, Oracle. All Rights Reserved. +/ +/ NAME +/ strmmv2README.txt - +/ +/ DESCRIPTION +/ +/ +/ NOTES +/ +/ +/ MODIFIED (MM/DD/YY) +/ wesmith 06/23/06 - register_mv: add parameter queue_name +/ wesmith 06/12/06 - corrections +/ wesmith 01/24/06 - Creation +/ + +Streams-driven MV refresh +------------------------- +A set of packages is provided that allows the user to set up an MV for +streams-driven refresh. Whenever a user transaction commits that modifies +the MV's master tables, the MV will be refreshed, either using +dbms_mview.refresh() or a streams-based refresh algorithm. This provides +on-commit MV behavior asynchronously. + +In addition, MV refresh changes may be processed using user-supplied +plsql code. + +Packages: +streams_mv_refresh_adm +streams_mv_refresh +streams_mv_lcr + + +Package streams_mv_refresh_adm +============================== +1. register_mv: sets up an MV for streams-driven refresh + +procedure register_mv(mv_owner varchar2, + mv_name varchar2, + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER', + queue_name varchar2 := NULL, + instantiate boolean := FALSE, + use_streams_refresh boolean := FALSE, + mv_dml_handler varchar2 := NULL); + +Parameters +---------- +mv_owner, mv_name: MV to register + +capture_name: + name of the capture process to use. It is recommended to specify a capture + that does not already exist. + +apply_name: + name of the apply process to use. It is recommended to specify an apply + that does not already exist. + +queue_name: + name of the streams queue associated with the capture and apply process. + If NULL, then the queue_name is derived from the capture process + metadata, if it exists. + +instantiate: + if TRUE, then the MV is refreshed (FAST if possible) and + the refresh scn is used for the streams instantiation scn. If FALSE, + then the MV is not refreshed and the current scn is used (the MV is + assumed to be fresh with respect to its dependent master tables.) + +use_streams_refresh: + if TRUE, then streams-based refresh is used (only supported for limited + types of MVs). If FALSE, then the standard MV refresh API is used + (dbms_mview.refresh) + +mv_dml_handler: + if NOT NULL, then the MV is set up for capture/apply and mv_dml_handler + is registered as the dml handler for the MV. This allows MV changes to + be processed in a specific way by the user (ex: for notification to + a middle tier). This parameter is most useful when + use_streams_refresh = FALSE. If use_streams_refresh = TRUE, then there + is a more efficient way for the user to process an MV refresh LCR + (mentioned below.) + + +Description +----------- +This procedure does the following: + - if use_streams_refresh = TRUE, validates that the MV is supported + - if instantiate = TRUE, refreshes the MV and uses the refresh scn as + the instantiation_scn + else uses the current scn as the instantiation scn + - sets up all the MV's master tables for capture/apply + - sets streams_mv_refresh.source_dml_handler() as the dml handler + - set the instantiation_scn + - sets up capture to include rowids + - if mv_dml_handler is NOT NULL: + - sets up the MV for capture/apply + - sets mv_dml_handler as the dml handler for the MV + +Notes +----- +- WARNING: this api should be used only if a separate apply + process was created, otherwise it could effect other applications + (since it may change the dml handler to a table) +- this API assumes that the streams queue used for the capture and + apply process exists in the stream admin's schema +- for use_streams_refresh = TRUE, the default behavior is that + MV refresh LCRs are applied to the MV. If the user wishes to perform + other steps in addition to or in lieu of applying the LCR, they may + modify the procedure streams_mv_lcr.process_lcr(). For example, the + user may send a notification to a middle tier in addition to applying + the LCR to the MV (similar to passing a non-NULL mv_dml_handler) +- table stmv_reg is used to store registration information and + must exist (in the stream admin's schema) + +table stmv_reg: + + mv_owner varchar2(30), /* MV owner */ + mv_name varchar2(30), /* MV name */ + inst_scn number, /* MV instantiation scn */ + use_str_refresh number, /* streams-based refresh ? 1=yes, 0=no */ + mjv number, /* materialized join view? 1=yes, 0=no */ + key_cols stmv_column_list, /* MV key columns */ + select_list varchar2(4000), /* MV select list */ + base_tabs stmv_table_list, /* MV base tables */ + where_clause varchar2(4000) /* MV where clause */ + + +2. unregister_mv: removes an MV from streams-driven refresh + +procedure unregister_mv(mv_owner varchar2, + mv_name varchar2, + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER'); + +Parameters +---------- +mv_owner, mv_name: MV to unregister + +capture_name: + name of the capture process to used for streams-driven refresh + +apply_name: + name of the apply process to used for streams-driven refresh + +Description +----------- +This procedure does the following: + - remove all MV dml handlers and table rules, it they exist + - removes dml handlers and table rules for the MV's master tables + if they are not used by an existing registered MV. + - deletes registration metadata for the MV + +Notes +----- +- WARNING: this api should be used only if a separate capture and apply + process was created, otherwise it could effect other applications. +- the apply process must be disabled in order to use this procedure +- table stmv_reg is used to store registration information and + must exist (in the stream admin's schema) + + +3. remove_streams_mv_refresh: removes streams configuration for + streams-driven MV refresh + +procedure remove_streams_mv_refresh( + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER'); + + +Parameters +---------- +capture_name: + name of the capture process to used for streams-driven refresh + +apply_name: + name of the apply process to used for streams-driven refresh + +Description +----------- +This procedure does the following: + - stops capture and apply + - remove all dml handlers associated with the apply + - drops capture and apply + - removes the queue and queue table + - removes table instantiation scns, if possible + - deletes any MV registration metadata + + + +package streams_mv_refresh +========================== +1. source_dml_handler: + dml handler used by streams-driven refresh + classic refresh: + if an LCR belongs to a table referenced by MVs registered for + classic refresh, store all such MVs in a package state collection + for commit-time processing. + streams-based refresh: + if an LCR belongs to a table referenced by MVs registered for + streams-based refresh, store the table name, the LCR's dmltype + and rowid in a package state collection for commit-time processing. + +2. source_commit_hdlr: + pre-commit handler used by streams-driven refresh + classic refresh: + submits a job to call dbms_mview.refresh() on all MVs that were collected + in the DML handler + streams-based refresh: + - derives delete and insert deltas based on the information collected + in the DML handler + - creates LCRs from these deltas and calls streams_mv_lcr.process_lcr() + for each LCR. + - for OJ MJVs, special processing for antijoin rows (AJ) + + +package streams_mv_lcr +====================== +1. procedure process_lcr(lcr sys.lcr$_row_record) + +- this procedure applies an LCR to an MV during streams-based refresh + +NOTE: this procedure may be modified by the user to perform + other steps in addition to or in lieu of applying the LCR + + + +Instructions: +- create streams administrator +- create streams-driven refresh supporting objects +- load streams-driven refresh packages +- create streams queue +- call streams_mv_refresh_adm.register_mv() passing a special capture + and apply name +- set applicable apply parameters +- call dbms_apply_adm.alter_apply to assign precommit handler to apply process +- start capture and apply +- call streams_mv_refresh_adm.remove_async_mv_streams() to remove the streams + configuration for async MV refresh. +- to register a new MV or unregister an MV, stop the apply process first + +See the script for a demonstration of this. + + +Restrictions +------------ +- supports single table PK-based MVs or MJVs +- MJVs: + - no UNION ALL + - no inline views +- must be read-only MV +- no on-commit MV +- no objects +- all registered MVs must be registered w/ same capture and apply ! +- no MVs with new column aliasing feature + + +Usage notes +----------- +- MJVs: + - must have a unique index on the MV container table's rowid columns + - call set_key_columns() on the MV container's rowid columns +- MV will be converted to NEVER REFRESH after calling register_mv +- MV logs are not necessary when registering an MV to use streams-based refresh +- all SQL is parsed as the stream admin, so everything in where clause must + be qualified by the owner (at least function calls must be) diff --git a/strmmv2s.sql b/strmmv2s.sql new file mode 100644 index 0000000..2f45fad --- /dev/null +++ b/strmmv2s.sql @@ -0,0 +1,142 @@ +Rem +Rem $Header: strmmv2s.sql 19-jan-2006.16:52:08 wesmith Exp $ +Rem +Rem strmmv2s.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem strmmv2s.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem wesmith 01/19/06 - Created +Rem + +create table customer ( + c_id number primary key, + zip number, + c_name varchar(30) default NULL /* non-filter column */ +); + +create table orders ( + o_id number primary key, + c_id number, + ol_num number default 0 /* non-filter column */ +); + +create table order_line ( + ol_id number, + o_id number, + i_id number default NULL /* non-filter column */ +); + + +create index c_ind on orders(c_id); +create index oid_ind on order_line(o_id); + +alter table order_line add SUPPLEMENTAL LOG DATA (ALL) columns; +alter table orders add SUPPLEMENTAL LOG DATA (ALL) columns; +alter table customer add SUPPLEMENTAL LOG DATA (ALL) columns; + +create table sales (region varchar2(10), amt number); +alter table sales add SUPPLEMENTAL LOG DATA (ALL) columns; + +-- This sleep is needed to as the min flashback window should be >= 3 seconds +exec dbms_lock.sleep(10); + +set echo off +Rem -------------------------------------------------------. +Rem Insert rows into the master tables(2-1 fanout) which are +Rem not part of the snapshot definitions. The pk columns of +Rem these rows start with digits between 0-4 +Rem -------------------------------------------------------. +insert into customer (c_id, zip) values (0, 1); +insert into customer (c_id, zip) values (1, 1); +insert into customer (c_id, zip) values (2, 1); +insert into customer (c_id, zip) values (3, 1); +insert into customer (c_id, zip) values (4, 1); + +insert into orders (o_id, c_id) values (01, 0); +insert into orders (o_id, c_id) values (02, 0); +insert into orders (o_id, c_id) values (11, 1); +insert into orders (o_id, c_id) values (12, 1); +insert into orders (o_id, c_id) values (21, 2); +insert into orders (o_id, c_id) values (22, 2); +insert into orders (o_id, c_id) values (31, 3); +insert into orders (o_id, c_id) values (32, 3); +insert into orders (o_id, c_id) values (41, 4); +insert into orders (o_id, c_id) values (42, 4); + +insert into order_line (ol_id, o_id) values (011, 01); +insert into order_line (ol_id, o_id) values (012, 01); +insert into order_line (ol_id, o_id) values (021, 02); +insert into order_line (ol_id, o_id) values (022, 02); +insert into order_line (ol_id, o_id) values (111, 11); +insert into order_line (ol_id, o_id) values (112, 11); +insert into order_line (ol_id, o_id) values (121, 12); +insert into order_line (ol_id, o_id) values (122, 12); +insert into order_line (ol_id, o_id) values (211, 21); +insert into order_line (ol_id, o_id) values (212, 21); +insert into order_line (ol_id, o_id) values (221, 22); +insert into order_line (ol_id, o_id) values (222, 22); +insert into order_line (ol_id, o_id) values (311, 31); +insert into order_line (ol_id, o_id) values (312, 31); +insert into order_line (ol_id, o_id) values (321, 32); +insert into order_line (ol_id, o_id) values (322, 32); +insert into order_line (ol_id, o_id) values (411, 41); +insert into order_line (ol_id, o_id) values (412, 41); +insert into order_line (ol_id, o_id) values (421, 42); +insert into order_line (ol_id, o_id) values (422, 42); + +Rem -------------------------------------------------------. +Rem Insert rows into the master tables(2-1 fanout) which +Rem are a part of the snapshot definition. The pk columns +Rem of these rows start with digits between 5-9 +Rem -------------------------------------------------------. +insert into customer (c_id, zip) values (5, 19555); +insert into customer (c_id, zip) values (6, 19555); +insert into customer (c_id, zip) values (7, 19555); +insert into customer (c_id, zip) values (8, 19555); +insert into customer (c_id, zip) values (9, 19555); + +insert into orders (o_id, c_id) values (51, 5); +insert into orders (o_id, c_id) values (52, 5); +insert into orders (o_id, c_id) values (61, 6); +insert into orders (o_id, c_id) values (62, 6); +insert into orders (o_id, c_id) values (71, 7); +insert into orders (o_id, c_id) values (72, 7); +insert into orders (o_id, c_id) values (81, 8); +insert into orders (o_id, c_id) values (82, 8); +insert into orders (o_id, c_id) values (91, 9); +insert into orders (o_id, c_id) values (92, 9); + +insert into order_line (ol_id, o_id) values (511, 51); +insert into order_line (ol_id, o_id) values (512, 51); +insert into order_line (ol_id, o_id) values (521, 52); +insert into order_line (ol_id, o_id) values (522, 52); +insert into order_line (ol_id, o_id) values (611, 61); +insert into order_line (ol_id, o_id) values (612, 61); +insert into order_line (ol_id, o_id) values (621, 62); +insert into order_line (ol_id, o_id) values (622, 62); +insert into order_line (ol_id, o_id) values (711, 71); +insert into order_line (ol_id, o_id) values (712, 71); +insert into order_line (ol_id, o_id) values (721, 72); +insert into order_line (ol_id, o_id) values (722, 72); +insert into order_line (ol_id, o_id) values (811, 81); +insert into order_line (ol_id, o_id) values (812, 81); +insert into order_line (ol_id, o_id) values (821, 82); +insert into order_line (ol_id, o_id) values (822, 82); +insert into order_line (ol_id, o_id) values (911, 91); +insert into order_line (ol_id, o_id) values (912, 91); +insert into order_line (ol_id, o_id) values (921, 92); +insert into order_line (ol_id, o_id) values (922, 92); +commit; + +insert into sales values ('West', null); +commit; diff --git a/strmmvp1.sql b/strmmvp1.sql new file mode 100644 index 0000000..81cd054 --- /dev/null +++ b/strmmvp1.sql @@ -0,0 +1,607 @@ +Rem +Rem $Header: strmmvp1.sql 29-jan-2007.10:31:25 davzhang Exp $ +Rem +Rem strmmvp1.sql +Rem +Rem Copyright (c) 2006, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem strmmvp1.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem davzhang 01/29/07 - increase max_time for verify_table_rules +Rem wesmith 03/28/06 - Created +Rem + +create or replace package async_mv_pkg AUTHID CURRENT_USER as + type name_arr is table of varchar2(30); + type mycurtyp IS REF cursor; + + -- collection of table owners + tab_owners name_arr := name_arr(); + -- collection of table names + tab_names name_arr := name_arr(); + + -- sets up streams, if necessary, for all tables with MV logs + procedure register_tables (capture_name varchar2, apply_name varchar2); + + -- removes streams, if necessary, for all tables that no longer have MV logs + procedure unregister_tables (capture_name varchar2, apply_name varchar2); + + -- removes ASYNC_MV streams configuration + procedure remove_async_mv_streams(capture_name varchar2, + apply_name varchar2); + + -- apply DML handler + procedure async_mv_dml_hdlr(in_any IN ANYDATA); + + -- apply pre-commit handler + procedure async_mv_commit_hdlr(commit_scn number); + + -- calls dbms_mview.refresh_dependent() if required + procedure refresh_dependent(tab_owners name_arr, + tab_names name_arr, commit_scn number); +end; +/ + +create or replace package body async_mv_pkg as + +-- Sets up streams for all tables with MV logs +-- Does the following: +-- set table instatiation scn +-- add apply rule +-- assign dml handler for insert/update/delete +-- add capture rule +procedure register_tables (capture_name varchar2, apply_name varchar2) is + + owner_name varchar2(80); -- table_owner.table_name + inst_scn number; -- instantiation SCN + db varchar2(128); + cnt pls_integer := 0; + + -- tables with MV logs that are not set up for streams + mycur mycurtyp; + need_reg varchar2(10000) := + 'select log_owner tabown, master tabname ' || + 'from dba_mview_logs ' || + 'minus ' || + 'select table_owner tabown, table_name tabname ' || + 'from dba_streams_table_rules ' || + 'where streams_type = ''APPLY'' ' || + 'and streams_name = :apply_name'; + tabowner varchar2(30); + tabname varchar2(30); + + +begin + select global_name into db from global_name; + + open mycur for need_reg using apply_name; + + -- set up streams for all tables needing registration + loop + FETCH mycur INTO tabowner, tabname; + EXIT WHEN mycur%NOTFOUND; -- exit loop when last row is fetched + + -- construct ""."" + owner_name := '"' || tabowner || '"."' || tabname || '"'; + + inst_scn := dbms_flashback.get_system_change_number(); + + -- if table already has an instantiation scn registered, don't call + -- dbms_apply_adm.set_table_instantiation_scn() + select count(*) into cnt + from dba_apply_instantiated_objects + where source_object_owner = tabowner + and source_object_name = tabname + and source_object_type = 'TABLE' + and source_database = db; + + if (cnt = 0) then + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => db, + instantiation_scn => inst_scn); + end if; + + -- add apply rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'apply', + streams_name => apply_name, + queue_name => 'stradm.ASYNC_MV_Q', + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + source_database => db); + + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => 'stradm.async_mv_pkg.async_mv_dml_hdlr', + apply_database_link => NULL, + apply_name => apply_name); + + -- add capture rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'capture', + streams_name => capture_name, + queue_name => 'stradm.ASYNC_MV_Q', + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + inclusion_rule => true); + + end loop; + close mycur; + +exception when others then + if mycur%isopen then + close mycur; + end if; + raise; +end; + +-- Removes streams for all tables no longer having MV logs +-- For each table, it does the following: +-- removes dml handler for insert/update/delete +-- remove capture rule +-- remove apply rule +procedure unregister_tables (capture_name varchar2, apply_name varchar2) is + owner_name varchar2(80); + inst_scn number; + db varchar2(128); + + mycur mycurtyp; --- declare cursor variable + tabowner varchar2(30); + tabname varchar2(30); + rowner varchar2(30); + rname varchar2(30); + strtype varchar2(11); + strname varchar2(30); + + -- tables set up for streams that no longer have MV logs + need_unreg varchar2(10000) := + 'select table_owner tabowner, table_name tabname ' || + 'from dba_streams_table_rules str ' || + 'where streams_type = ''APPLY'' ' || + 'and streams_name = :apply_name ' || + 'minus ' || + 'select log_owner tabowner, master tabname ' || + 'from dba_mview_logs'; + + -- corresponding capture/apply rules to remove for the tables + -- in the cursor need_unreg + remove_rules varchar2(10000) := + 'select streams_name, streams_type, rule_owner, rule_name ' || + 'from dba_streams_table_rules str ' || + 'where ((streams_type = ''CAPTURE'' and streams_name = :capture_name ) ' || + ' OR ' || + ' (streams_type = ''APPLY'' and streams_name = :apply_name )) ' || + 'and not exists ' || + '(select 1 from dba_mview_logs mvl ' || + ' where str.table_owner = mvl.log_owner ' || + ' and str.table_name = mvl.master)'; + +begin + select global_name into db from global_name; + + open mycur for need_unreg using apply_name; + + loop + FETCH mycur INTO tabowner, tabname; + EXIT WHEN mycur%NOTFOUND; -- exit loop when last row is fetched + + -- construct ""."" + owner_name := '"' || tabowner || '"."' || tabname || '"'; + + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + + end loop; + close mycur; + + open mycur for remove_rules using capture_name, apply_name; + loop + FETCH mycur INTO strname, strtype, rowner, rname; + EXIT WHEN mycur%NOTFOUND; -- exit loop when last row is fetched + + -- construct ""."" + owner_name := '"' || rowner || '"."' || rname || '"'; + + dbms_streams_adm.remove_rule( + rule_name => owner_name, + streams_type => strtype, + streams_name => strname); + end loop; + close mycur; + +exception when others then + if mycur%isopen then + close mycur; + end if; + raise; +end; + +-- removes ASYNC_MV streams configuration +procedure remove_async_mv_streams(capture_name varchar2, + apply_name varchar2) is + + owner_name varchar2(80); + inst_scn number; + db varchar2(128); + cnt pls_integer := 0; + + -- selects tables set up for ASYNC_MV apply + cursor apply_tables(apply_name varchar2) is + select table_owner, table_name + from dba_streams_table_rules + where streams_type = 'APPLY' + and streams_name = apply_name; + + cursor instantiated_objects is + select source_object_owner table_owner, source_object_name table_name + from dba_apply_instantiated_objects + where SOURCE_OBJECT_TYPE = 'TABLE'; + +begin + select global_name into db from global_name; + + -- stop capture and apply + dbms_capture_adm.stop_capture(capture_name); + dbms_apply_adm.stop_apply(apply_name); + + for rec in apply_tables(apply_name) loop + -- construct ""."" + owner_name := '"' || rec.table_owner || '"."' || rec.table_name || '"'; + + -- remove dml handlers + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + + end loop; + + -- remove capture and apply + dbms_apply_adm.drop_apply(apply_name, true); + dbms_capture_adm.drop_capture(capture_name, true); + + -- remove queues + dbms_streams_adm.remove_queue('ASYNC_MV_Q'); + + -- if there are no apply processes left, remove any dangling + -- table instantiation scns + select count(*) into cnt + from dba_apply; + + if (cnt = 0) then + for rec in instantiated_objects loop + -- construct ""."" + owner_name := '"' || rec.table_owner || '"."' || rec.table_name || '"'; + + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => db, + instantiation_scn => null); + end loop; + else + -- other apply processes exist, so print a message to the caller + dbms_output.put_line('NOTE: Other apply processes exist so '|| + 'table instantiation scns were not removed.'); + dbms_output.put_line('To remove them, call ' || + 'dbms_apply_adm.set_table_instantiation_scn'); + dbms_output.put_line('Example:'); + dbms_output.put_line(' dbms_apply_adm.set_table_instantiation_scn('); + dbms_output.put_line(' source_object_name => ''tabowner.foo'','); + dbms_output.put_line(' source_database_name => db,'); + dbms_output.put_line(' instantiation_scn => null);'); + end if; + +end; + +-- apply DML handler +procedure async_mv_dml_hdlr(in_any IN ANYDATA) is + lcr SYS.LCR$_ROW_RECORD; + rc PLS_INTEGER; + tab_owner varchar2(30); + tab_name varchar2(30); + next_pos pls_integer; + source_db varchar2(128); +begin + -- get LCR info + rc := in_any.getobject(lcr); + tab_owner := lcr.get_object_owner(); + tab_name := lcr.get_object_name(); + source_db := lcr.get_source_database_name(); + + -- see if name already exists in table cache + if (async_mv_pkg.tab_owners.count > 0) then + for i in async_mv_pkg.tab_owners.first..async_mv_pkg.tab_owners.last loop + if (tab_owner = async_mv_pkg.tab_owners(i) and + tab_name = async_mv_pkg.tab_names(i)) then + return; -- found entry, done + end if; + end loop; + end if; + + -- new table: add to pkg state cache + if (async_mv_pkg.tab_owners.count = 0) then + next_pos := 1; + else + next_pos := async_mv_pkg.tab_owners.last + 1; + end if; + + async_mv_pkg.tab_owners.extend; + async_mv_pkg.tab_owners(next_pos) := tab_owner; + async_mv_pkg.tab_names.extend; + async_mv_pkg.tab_names(next_pos) := tab_name; + +end; + +-- +-- autonmous block to create a scheduler job (this api commits) +-- +procedure create_scheduler_job(str varchar2) is + pragma autonomous_transaction; +begin + -- submit the refresh job + dbms_scheduler.create_job( + job_name => dbms_scheduler.generate_job_name, + job_type => 'PLSQL_BLOCK', + job_action => str, + start_date => sysdate, + enabled => TRUE); +end; + +-- pre-commit handler +procedure async_mv_commit_hdlr(commit_scn number) is + l_jobnum number; + str varchar2(10000); + ownerlist varchar2(10000); + namelist varchar2(10000); +begin + + -- no table to process, done + if (async_mv_pkg.tab_owners.count = 0) then + return; + end if; + + -- create comma-separated list of table owners and table names + for i in async_mv_pkg.tab_owners.first..async_mv_pkg.tab_owners.last loop + if (i > async_mv_pkg.tab_owners.first) then + ownerlist := ownerlist || ','; + namelist := namelist || ','; + end if; + ownerlist := ownerlist || '''' || async_mv_pkg.tab_owners(i) || ''''; + namelist := namelist || '''' || async_mv_pkg.tab_names(i) || ''''; + end loop; + + -- submit a stradm.async_mv_pkg.refresh_dependent() job + str := + 'begin ' || + 'stradm.async_mv_pkg.refresh_dependent(' || + 'async_mv_pkg.name_arr(' || ownerlist || '), ' || + 'async_mv_pkg.name_arr(' || namelist || '), ' || + commit_scn || '); ' || + 'end;'; + + create_scheduler_job(str); + + -- reset tab_owners, tab_names collections + async_mv_pkg.tab_owners.delete; + async_mv_pkg.tab_names.delete; +end; + +-- Given a collection of tables, this determines the minimal set of +-- tables to pass to dbms_mview.refresh_dependent() +-- by comparing the commit scn of a transaction with the minimum +-- refresh scns of all MVs dependent on the tables. +procedure refresh_dependent(tab_owners name_arr, tab_names name_arr, + commit_scn number) is + min_refscn number; + tablist varchar2(10000); + is_first boolean := TRUE; + num_fail number :=0; +begin + + -- construct comma-separated list of table names, + -- skipping tables if dependent MVs do not need refreshing + for i in tab_owners.first..tab_owners.last loop + begin + select oldest_refresh_scn into min_refscn + from all_refresh_dependencies + where owner = tab_owners(i) + and table_name = tab_names(i); + + if commit_scn >= min_refscn then + -- add table to the list + if not is_first then + tablist := tablist || ','; + end if; + tablist := tablist || + '"' || tab_owners(i) || '"."' || tab_names(i) || '"'; + is_first := FALSE; + end if; + + exception when no_data_found then + null; + end; + end loop; + + -- do the refresh + if tablist is not null then + dbms_mview.refresh_dependent(number_of_failures => num_fail, + list => tablist, + refresh_after_errors => TRUE, + atomic_refresh => FALSE, + nested => TRUE); + end if; +end; + +end async_mv_pkg; +/ + +-- Procedure for verifying results +create or replace procedure verify_tables(tab1 in varchar2, + tab2 in varchar2, + max_time in integer default 3600) + authid current_user as + + tab2_sql varchar2(1000); + tab1_sql varchar2(1000); + diff_sql varchar2(1000); + cur integer; + ret integer; + num_rows integer; + slept integer := 0; + wait_for_convergence boolean := true; + +begin + dbms_output.enable ( 10000 ) ; + + tab1_sql := 'select * from ' || tab1; + + tab2_sql := 'select * from ' || tab2; + +-- diff_sql is the query that should return 0 rows if the snapshot rows +-- have converged + diff_sql := '(' || + tab1_sql || + ' minus ' || + tab2_sql || + ')' || + ' union ' || + '(' || + tab2_sql || + ' minus ' || + tab1_sql || + ')' ; + + +-- get the no. of rows returned by diff_sql. + cur := dbms_sql.open_cursor; + dbms_sql.parse(cur, + 'select count(*) from ( ' || diff_sql || ' )', dbms_sql.v7); + sys.dbms_sql.define_column(cur, 1, num_rows); + begin + ret := dbms_sql.execute_and_fetch(cur); + dbms_sql.column_value(cur,1,num_rows); + exception when others then + if dbms_sql.is_open(cur) then + dbms_sql.close_cursor(cur); + end if; + dbms_output.put_line ('-- error while counting rows in diff_sql'); + raise; + end; + +while (wait_for_convergence) loop + ret := dbms_sql.execute_and_fetch(cur); + dbms_sql.column_value(cur,1,num_rows); + +-- begin num_rows if + if num_rows = 0 then + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + dbms_output.put_line('-- Tables/views '||tab1 ||' and '||tab2 || ' are identical'); + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + wait_for_convergence := false; + else + dbms_lock.sleep(3); + slept := slept + 3; + if (slept >= max_time ) then + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + dbms_output.put_line('-- WARNING: maximum wait time of '|| slept ||' seconds exceeded'); + dbms_output.put_line('-- Tables/views '||tab1 ||' and '||tab2 || ' are NOT identical'); + dbms_output.put_line('-- Check trace files to determine what is going wrong'); + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + wait_for_convergence := false; + end if; + end if; +end loop; + dbms_sql.close_cursor(cur); + +end; +/ + +create or replace public synonym verify_tables for verify_tables; +grant execute on verify_tables to public; + +-- verifies that a table's rules have been added or removed +-- if check_exists = TRUE, it waits until the rules exist +-- else if FALSE, it waits until the rules no longer exist +create or replace procedure verify_table_rules(towner varchar2, + tname varchar2, + check_exists boolean, + max_time pls_integer := 600) +is + sleep_total pls_integer := 0; + cnt1 pls_integer; + cnt2 pls_integer; + done boolean := false; +begin + + while (not done) loop + select count(*) into cnt1 + from dba_streams_table_rules + where streams_name = 'CAPTURE_MV' + and table_owner = towner + and table_name = tname; + + select count(*) into cnt2 + from dba_streams_table_rules + where streams_name = 'APPLY_MV' + and table_owner = towner + and table_name = tname; + + if (check_exists) then + -- check if table is set up for capture/apply + if (cnt1 > 0 and cnt2 > 0) then + exit; + end if; + else + -- check if table is not set up for capture/apply + if (cnt1 = 0 and cnt2 = 0) then + exit; + end if; + end if; + + -- try again after 3 seconds + dbms_lock.sleep(3); + sleep_total := sleep_total + 3; + if (sleep_total >= max_time ) then + dbms_output.put_line('-- Tables rules are NOT verified'); + end if; + end loop; + dbms_output.put_line('-- Tables rules are verified'); +end; +/ + +create or replace public synonym verify_table_rules for verify_table_rules; +grant execute on verify_table_rules to public; diff --git a/strmmvp2.sql b/strmmvp2.sql new file mode 100644 index 0000000..5665a87 --- /dev/null +++ b/strmmvp2.sql @@ -0,0 +1,2267 @@ +Rem +Rem $Header: strmmvp2.sql 23-jun-2006.13:43:59 wesmith Exp $ +Rem +Rem strmmvp2.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem strmmvp2.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem wesmith 06/23/06 - register_mv: add parameter queue_name +Rem wesmith 06/12/06 - LRG 2247322: remove insert append hint +Rem wesmith 01/19/06 - Created +Rem + +---------------------- +-- supporting objects +---------------------- +create or replace type stmv_num_list is table of number +/ +create or replace type stmv_name_list is table of varchar2(30) +/ +create or replace type stmv_anydata_list is table of anydata +/ +create or replace type stmv_column_list is table of varchar2(30) +/ + +-- master table metadata +create or replace type stmv_table_t as object ( + table_owner varchar2(30), + table_name varchar2(30), + table_alias varchar2(30), + key_cols stmv_column_list +) +/ +create or replace type stmv_table_list is table of stmv_table_t +/ + +-- MV metadata +create or replace type stmv_mv_t as object ( + mv_owner varchar2(30), /* MV owner */ + mv_name varchar2(30), /* MV name */ + inst_scn number, /* MV instantiation scn */ + use_str_refresh number, /* streams-based refresh ? 1=yes, 0=no */ + mjv number, /* obsolete */ + flags number, /* MV properties */ + key_cols stmv_column_list, /* MV key columns */ + select_list varchar2(4000), /* MV select list */ + base_tabs stmv_table_list, /* MV base tables */ + where_clause varchar2(4000) /* MV where clause */ +) +/ +create or replace type stmv_mvs_t is table of stmv_mv_t +/ + +-- store streams MV metadata +create table stmv_reg of stmv_mv_t (primary key(mv_owner, mv_name)) + nested table key_cols store as stmv_mv_keycol_st + nested table base_tabs store as stmv_tab_st + (nested table key_cols store as stmv_tab_keycol_st); + +-- temp table to store rowids for a transaction +create global temporary table stmv_rid +(table_owner varchar2(30), + table_name varchar2(30), + dml_type number, + rid rowid +) +on commit delete rows; + +create index rid_i1 on stmv_rid(table_owner, table_name, dml_type); + + +------------ +-- packages +------------ +create or replace package streams_mv_refresh_adm AUTHID CURRENT_USER as + type mycurtyp IS REF cursor; + reg_mvs stmv_mvs_t := stmv_mvs_t(); + + -- constants + source_dbname constant varchar2(256) := dbms_standard.database_name; + + -- constants for flags + flg_mjv constant pls_integer := 1; + flg_hasoj constant pls_integer := 2; + + -- returns primary key columns for a table + function get_pkcols(tabowner in varchar2, tabname in varchar2) + return stmv_column_list; + + -- returns key columns for a table + -- (PK or from the api dbms_apply_adm.set_key_columns) + function get_keycols(tabowner in varchar2, tabname in varchar2) + return stmv_column_list; + + -- sets up an MV for streams-driven refresh + procedure register_mv(mv_owner varchar2, + mv_name varchar2, + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER', + queue_name varchar2 := NULL, + instantiate boolean := FALSE, + use_streams_refresh boolean := FALSE, + mv_dml_handler varchar2 := NULL); + + -- removes an MV from streams-driven refresh + procedure unregister_mv(mv_owner varchar2, + mv_name varchar2, + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER'); + + -- removes streams configuration for streams-driven MV refresh + procedure remove_streams_mv_refresh( + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER'); + +end streams_mv_refresh_adm; +/ + + +create or replace package streams_mv_refresh AUTHID CURRENT_USER as + type rowid_list is table of varchar2(18); + type txn_tab_t is record ( + table_owner varchar2(30), + table_name varchar2(30), + dmltypes pls_integer, + delete_rowids rowid_list, + insert_rowids rowid_list + ); + type txn_tab_list is table of txn_tab_t; + + -- collection of MV owners, names + txn_mvs txn_tab_list := txn_tab_list(); + + -- collection of table owners, names + txn_tabs txn_tab_list := txn_tab_list(); + + -- dml types + insert_dml constant pls_integer := 1; + update_dml constant pls_integer := 2; + delete_dml constant pls_integer := 4; + + rowid_col constant varchar2(5) := 'ROWID'; + scn_bind constant varchar2(5) := 'SCN'; + rowid_bind constant varchar2(5) := 'RID'; + + -- dml handler used by streams-driven refresh + procedure source_dml_handler(lcr_anydata in sys.anydata); + + -- pre-commit handler used by streams-driven refresh + procedure source_commit_hdlr(commit_scn number); + + procedure add_to_table_coll(tab_owner IN varchar2, + tab_name IN varchar2, + tab_dmltype IN pls_integer, + tab_rowid IN urowid, + tab_coll IN OUT NOCOPY txn_tab_list); + + procedure define_columns(sql_cursor pls_integer, + num_cols pls_integer, + desc_table sys.dbms_sql.desc_tab); + + procedure get_column_values(sql_cursor pls_integer, + num_cols pls_integer, + desc_table sys.dbms_sql.desc_tab, + is_key_col stmv_num_list, + lcr in out nocopy sys.lcr$_row_record, + cmd_type varchar2, + first_time boolean); + + procedure print_trace(mesg varchar2); + +end streams_mv_refresh; +/ + + +create or replace package streams_mv_lcr AUTHID CURRENT_USER as + -- applies an LCR to an MV during streams-based refresh + procedure process_lcr(lcr sys.lcr$_row_record); + + procedure print_lcr_cols(cols sys.lcr$_row_list); + procedure do_an_insert(lcr sys.lcr$_row_record); +end streams_mv_lcr; +/ + + +create or replace package body streams_mv_refresh_adm as + cursor mv_group is select sys_nc_rowinfo$ from stmv_reg; + +-- +-- returns primary key columns for a table, if they exist +-- +function get_pkcols(tabowner in varchar2, tabname in varchar2) + return stmv_column_list is + + pk_columns stmv_column_list := stmv_column_list(); + pkcol_array dbms_utility.uncl_array; -- 1-based plsql table + pk_name varchar2(30); + pk_type pls_integer; + pk_cols varchar2(32000); + pk_idx_name varchar2(30); + idx_cols varchar2(32000); + dummy pls_integer; + canon_pkcol varchar2(30); + +begin + streams_mv_refresh.print_trace('get_pkcols()+'); + + -- get pk cols as comma-separated list + sys.dbms_snapshot_utl.get_pk_constraint_info( + tabowner, tabname, pk_name, pk_type, pk_cols, pk_idx_name, idx_cols); + + if (pk_cols is null) then + return pk_columns; + end if; + + -- convert comma-separated list to collection + dbms_utility.comma_to_table(rtrim(pk_cols, ','), dummy, pkcol_array); + + -- move collection to collection of type stmv_column_list + for i in 1 .. pkcol_array.last loop + exit when pkcol_array(i) is null; + -- strip double quotes in pkcol_array(i) + dbms_utility.canonicalize(pkcol_array(i), canon_pkcol, 30); + pk_columns.extend; + pk_columns(pk_columns.last) := canon_pkcol; + end loop; + + streams_mv_refresh.print_trace('get_pkcols()-'); + return pk_columns; +end; + + +-- +-- get a table's key columns (PK or via api dbms_apply_adm.set_key_columns) +-- +function get_keycols(tabowner in varchar2, tabname in varchar2) + return stmv_column_list is + + key_cols stmv_column_list := stmv_column_list(); + + cursor key_columns(table_owner varchar2, table_name varchar2) is + select column_name + from dba_apply_key_columns + where object_owner = table_owner + and object_name = table_name + and apply_database_link is null; + +begin + streams_mv_refresh.print_trace('get_keycols()+'); + + -- first, see if the table has a PK constraint + key_cols := get_pkcols(tabowner, tabname); + + if (key_cols.count = 0) then + -- no PK, try and see if there are key columns defined + -- (via dbms_apply_adm.set_key_columns) + for rec in key_columns(tabowner, tabname) loop + key_cols.extend; + key_cols(key_cols.last) := rec.column_name; + end loop; + end if; + + streams_mv_refresh.print_trace('get_keycols()-'); + return key_cols; +end; + +-- +-- register an MV for streams-driven refresh +-- +procedure register_mv(mv_owner varchar2, + mv_name varchar2, + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER', + queue_name varchar2 := NULL, + instantiate boolean := FALSE, + use_streams_refresh boolean := FALSE, + mv_dml_handler varchar2 := NULL) is + + mycur mycurtyp; + mvinfo stmv_mv_t; + str_refresh pls_integer; + flags pls_integer := 0; + can_use_log varchar2(3); + updatable varchar2(3); + ref_method varchar2(15); -- rowid, pk, etc. + ref_type varchar2(10); -- complete, fast, never, etc. + ref_mode varchar2(10); -- demand, commit, never + mv_query varchar2(32000); + mastabs pls_integer; -- # master tables + has_obj pls_integer; -- MV with objects ? 1=yes, 0=no + has_oj pls_integer; -- MV with outer joins ? 1=yes, 0=no + cnt pls_integer; + select_pos pls_integer := 0; + select_start pls_integer := 0; + from_pos pls_integer := 0; + where_pos pls_integer := 0; + where_start pls_integer := 0; + tabowner varchar2(30); + tabname varchar2(30); + tabalias varchar2(30); + owner_name varchar2(80); -- table_owner.table_name + inst_scn number; -- instantiation SCN + tablist stmv_table_list := stmv_table_list(); + canon_mv_owner varchar2(30); + canon_mv_name varchar2(30); + canon_capture varchar2(30); + canon_apply varchar2(30); + canon_queue varchar2(30); + canon_hdlr varchar2(98); + key_cols stmv_column_list; + + -- MV metadata + check_mv varchar2(32000) := +'select refresh_method, can_use_log, updatable, type, refresh_mode, query + from dba_snapshots + where owner = :mv_owner + and name = :mv_name'; + + check_mv2 varchar2(32000) := +'select mastabs, decode(bitand(flag, 268435456), 0, 0, 1) has_obj, + decode(bitand(flag2, 256), 0, 0, 1) has_oj + from sys.exu9snap + where owner = :mv_owner + and name =:mv_name'; + + -- MV last refresh scn + get_refscn varchar2(32000) := +'select rscn + from sys.exu9snap + where owner = :mv_owner + and name =:mv_name'; + + -- MV master tables + mv_master_tables varchar2(32000) := +'select detail_owner, detail_relation, detail_alias + from dba_summary_detail_tables + where owner = :mv_owner + and summary_name = :mv_name'; + +begin + -- print param values + streams_mv_refresh.print_trace('register_mv()+'); + streams_mv_refresh.print_trace('mv_owner='||mv_owner); + streams_mv_refresh.print_trace('mv_name='||mv_name); + streams_mv_refresh.print_trace('capture_name='||capture_name); + streams_mv_refresh.print_trace('apply_name='||apply_name); + streams_mv_refresh.print_trace('queue_name='||queue_name); + if (instantiate) then + streams_mv_refresh.print_trace('instantiate=TRUE'); + else + streams_mv_refresh.print_trace('instantiate=FALSE'); + end if; + if (use_streams_refresh) then + streams_mv_refresh.print_trace('use_streams_refresh=TRUE'); + else + streams_mv_refresh.print_trace('use_streams_refresh=FALSE'); + end if; + streams_mv_refresh.print_trace('mv_dml_handler='||mv_dml_handler); + + -- canonicalize inputs + dbms_utility.canonicalize(mv_owner, canon_mv_owner, 30); + dbms_utility.canonicalize(mv_name, canon_mv_name, 30); + dbms_utility.canonicalize(capture_name, canon_capture, 30); + dbms_utility.canonicalize(apply_name, canon_apply, 30); + dbms_utility.canonicalize(queue_name, canon_queue, 30); + dbms_utility.canonicalize(mv_dml_handler, canon_hdlr, 30); + + -- make sure the apply process is down + select count(*) into cnt from dba_apply + where apply_name = canon_apply + and status = 'ENABLED'; + if (cnt > 0) then + raise_application_error(-20000, + 'Apply process must be disabled'); + end if; + + -- get queue_name from capture and apply process views if NULL + if (canon_queue is NULL) then + declare + apply_queue varchar2(30); + capture_queue varchar2(30); + begin + -- get queue for capture and apply + select queue_name into capture_queue + from dba_capture + where capture_name = canon_capture; + + select queue_name into apply_queue + from dba_apply + where apply_name = canon_apply; + + -- capture and apply must share the same queue + if apply_queue != capture_queue then + raise_application_error(-20000, + 'capture and apply must share the same queue'); + end if; + + canon_queue := capture_queue; + + exception + when NO_DATA_FOUND then + raise_application_error(-20000, 'must specify queue_name'); + end; + end if; + + -- + -- get MV metadata + -- + begin + execute immediate check_mv + into ref_method, can_use_log, updatable, ref_type, ref_mode, mv_query + using canon_mv_owner, canon_mv_name; + + execute immediate check_mv2 + into mastabs, has_obj, has_oj + using canon_mv_owner, canon_mv_name; + exception + when NO_DATA_FOUND then + raise_application_error(-20000, 'MV does not exist'); + end; + + streams_mv_refresh.print_trace('ref_method='||ref_method); + streams_mv_refresh.print_trace('can_use_log='||can_use_log); + streams_mv_refresh.print_trace('updatable='||updatable); + streams_mv_refresh.print_trace('ref_type='||ref_type); + streams_mv_refresh.print_trace('ref_mode='||ref_mode); + streams_mv_refresh.print_trace('mastabs='||mastabs); + streams_mv_refresh.print_trace('has_obj='||has_obj); + + -- for streams-based refresh, validate the MV + if (use_streams_refresh = TRUE) then + if (can_use_log = 'NO' or -- not fast refreshable + updatable = 'YES' or -- updatable MV + ref_mode = 'COMMIT' or -- on-commit MV + has_obj = 1 or -- MV with objects + -- not pk-based and not an MJV + (ref_method != 'PRIMARY KEY' and ref_method != 'JOIN VIEW') or + (ref_method = 'PRIMARY KEY' and mastabs > 1) or -- pk MV w/ >1 table + instr(upper(mv_query), 'SELECT', 1, 2) > 0 or -- nested queries + instr(upper(mv_query), 'FROM', 1, 2) > 0 or -- nested queries + instr(upper(mv_query), 'UNION') > 0 -- UNION clause + ) then + raise_application_error(-20000, + 'MV not supported for streams-based refresh'); + end if; + end if; + + -- get MV PK columns, else get key columns, else error + key_cols := get_keycols(canon_mv_owner, canon_mv_name); + if (key_cols.count = 0 and use_streams_refresh = TRUE) then + raise_application_error(-20000, + 'MV must have a PK or use dbms_apply_adm.set_key_columns()'); + end if; + if (key_cols.count > 0) then + for i in key_cols.first .. key_cols.last loop + streams_mv_refresh.print_trace('key_col='||key_cols(i)); + end loop; + end if; + + if (use_streams_refresh = TRUE) then + str_refresh := 1; + else + str_refresh := 0; + end if; + + -- check if an MJV + if (ref_method = 'JOIN VIEW') then + flags := flags + flg_mjv; + end if; + + -- MV has outerjoin predicates ? + if (has_oj = 1) then + flags := flags + flg_hasoj; + end if; + + -- + -- initialize MV metadata + -- + mvinfo := stmv_mv_t(canon_mv_owner, canon_mv_name, null, str_refresh, 0, + flags, stmv_column_list(), null, stmv_table_list(), + null); + + -- parse mv_query for select list and where clause + select_pos := instr(upper(mv_query), 'SELECT'); + select_start := select_pos + length('SELECT') + 1; + from_pos := instr(upper(mv_query), 'FROM'); + + -- copy select list to MV metadata object + mvinfo.select_list := + substr(mv_query, select_start, from_pos - select_start); + + -- copy where clause to MV metadata object by parsing the MV query + where_pos := instr(upper(mv_query), 'WHERE'); + if (where_pos != 0) then + where_start := where_pos + length('WHERE') + 1; + mvinfo.where_clause := substr(mv_query, where_start); + end if; + + -- get MV keycols + mvinfo.key_cols := key_cols; + + -- + -- get MV base tables + -- + open mycur for mv_master_tables using canon_mv_owner, canon_mv_name; + + streams_mv_refresh.print_trace('getting base tables'); + loop + fetch mycur into tabowner, tabname, tabalias; + exit when mycur%notfound; -- exit loop when last row is fetched + + streams_mv_refresh.print_trace('tabowner='||tabowner); + streams_mv_refresh.print_trace('tabname='||tabname); + streams_mv_refresh.print_trace('tabalias='||tabalias); + + -- store table information + tablist.extend; + tablist(tablist.last) := stmv_table_t(tabowner, tabname, tabalias, + stmv_column_list()); + + -- construct ""."" + owner_name := '"' || tabowner || '"."' || tabname || '"'; + + -- add apply rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'apply', + streams_name => canon_apply, + queue_name => canon_queue, + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + source_database => streams_mv_refresh_adm.source_dbname); + + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => 'streams_mv_refresh.source_dml_handler', + apply_database_link => NULL, + apply_name => canon_apply); + + -- add capture rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'capture', + streams_name => canon_capture, + queue_name => canon_queue, + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + inclusion_rule => true); + + end loop; + close mycur; + + -- capture rowids, too + dbms_capture_adm.include_extra_attribute(canon_capture, 'row_id', true); + + mvinfo.base_tabs := tablist; + + -- + -- get instantiation scn by refreshing MV or using current scn + -- (must be done after setting capture and apply table rules) + -- + if (instantiate = TRUE) then + -- construct ""."" + owner_name := '"' || canon_mv_owner || '"."' || canon_mv_name || '"'; + + -- refresh the MV + dbms_mview.refresh(owner_name); + + -- get the refresh scn + execute immediate get_refscn into inst_scn using + canon_mv_owner, canon_mv_name; + + else + -- use the current scn for the instantiation scn + inst_scn := dbms_flashback.get_system_change_number(); + end if; + + mvinfo.inst_scn := inst_scn; -- store instantiation scn + + -- for streams-based refresh, set MV to never refresh to prevent + -- user from refreshing MV using dbms_snapshot.refresh(), which + -- could cause incorrect results + owner_name := '"' || canon_mv_owner || '"."' || canon_mv_name || '"'; + if (use_streams_refresh = TRUE) then + execute immediate + 'alter materialized view '|| owner_name || ' never refresh'; + end if; + + -- + -- set table instantiation scn for all master tables + -- + open mycur for mv_master_tables using canon_mv_owner, canon_mv_name; + + loop + fetch mycur into tabowner, tabname, tabalias; + exit when mycur%notfound; -- exit loop when last row is fetched + + -- construct ""."" + owner_name := '"' || tabowner || '"."' || tabname || '"'; + + -- if table already has an instantiation scn registered, don't call + -- dbms_apply_adm.set_table_instantiation_scn() + select count(*) into cnt + from dba_apply_instantiated_objects + where source_object_owner = tabowner + and source_object_name = tabname + and source_object_type = 'TABLE' + and source_database = streams_mv_refresh_adm.source_dbname; + + if (cnt = 0) then + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => streams_mv_refresh_adm.source_dbname, + instantiation_scn => inst_scn); + end if; + end loop; + + -- if user passed in an mv_dml_handler, then set up the MV for capture/apply + if (mv_dml_handler is not null) then + + -- construct ""."" + owner_name := '"' || canon_mv_owner || '"."' || canon_mv_name || '"'; + + inst_scn := dbms_flashback.get_system_change_number(); + + -- add apply rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'apply', + streams_name => canon_apply, + queue_name => canon_queue, + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + source_database => streams_mv_refresh_adm.source_dbname); + + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => canon_hdlr, + apply_database_link => NULL, + apply_name => canon_apply); + + -- add capture rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'capture', + streams_name => canon_capture, + queue_name => canon_queue, + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + inclusion_rule => true); + + -- if table already has an instantiation scn registered, don't call + -- dbms_apply_adm.set_table_instantiation_scn() + select count(*) into cnt + from dba_apply_instantiated_objects + where source_object_owner = canon_mv_owner + and source_object_name = canon_mv_name + and source_object_type = 'TABLE' + and source_database = streams_mv_refresh_adm.source_dbname; + + if (cnt = 0) then + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => streams_mv_refresh_adm.source_dbname, + instantiation_scn => inst_scn); + end if; + + end if; + + -- + -- save MV registration metadata to disk + -- + insert into stmv_reg values (mvinfo); + commit; + + streams_mv_refresh.print_trace('register_mv()-'); +exception when others then + if mycur%isopen then + close mycur; + end if; + raise; +end; + + +-- +-- remove an MV from streams-driven refresh +-- +procedure unregister_mv(mv_owner varchar2, + mv_name varchar2, + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER') is + + mycur mycurtyp; + tabowner varchar2(30); + tabname varchar2(30); + owner_name varchar2(80); + cnt pls_integer; + canon_mv_owner varchar2(30); + canon_mv_name varchar2(30); + canon_capture varchar2(30); + canon_apply varchar2(30); + + -- all table rules associated with the specified capture, apply and table + cursor table_rules(capture_name varchar2, apply_name varchar2, + table_owner varchar2, table_name varchar2) is + select streams_name, streams_type, rule_owner, rule_name + from dba_streams_table_rules str + where streams_type = 'CAPTURE' + and streams_name = capture_name + and table_owner = table_rules.table_owner + and table_name = table_rules.table_name + union + select streams_name, streams_type, rule_owner, rule_name + from dba_streams_table_rules str + where streams_type = 'APPLY' + and streams_name = apply_name + and table_owner = table_rules.table_owner + and table_name = table_rules.table_name; + + -- select all master tables registered by this MV that is not used + -- by other registered MVs + mv_master_tables varchar2(32000) := +'select mt.table_owner, mt.table_name + from stmv_reg mv, table(mv.base_tabs) mt + where mv.mv_owner = :mv_owner + and mv.mv_name = :mv_name + and not exists + (select 1 + from stmv_reg mv2, table(mv2.base_tabs) mt2 + where not (mv2.mv_owner = mv.mv_owner + and mv2.mv_name = mv.mv_name) + and mt.table_owner = mt2.table_owner + and mt.table_name = mt2.table_name)'; + +begin + streams_mv_refresh.print_trace('unregister_mv()+'); + + -- canonicalize inputs + dbms_utility.canonicalize(mv_owner, canon_mv_owner, 30); + dbms_utility.canonicalize(mv_name, canon_mv_name, 30); + dbms_utility.canonicalize(capture_name, canon_capture, 30); + dbms_utility.canonicalize(apply_name, canon_apply, 30); + + -- make sure the apply process is down + select count(*) into cnt from dba_apply + where apply_name = canon_apply + and status = 'ENABLED'; + if (cnt > 0) then + raise_application_error(-20000, + 'Apply process must be disabled'); + end if; + + owner_name := '"' || canon_mv_owner || '"."' || canon_mv_name || '"'; + + -- remove MV DML handlers + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => canon_apply); + + -- remove all MV rules, if they exist + for rec in table_rules(canon_capture, canon_apply, + canon_mv_owner, canon_mv_name) loop + + -- construct ""."" + owner_name := '"' || rec.rule_owner || '"."' || rec.rule_name || '"'; + + dbms_streams_adm.remove_rule( + rule_name => owner_name, + streams_type => rec.streams_type, + streams_name => rec.streams_name); + end loop; + + -- + -- get MV base tables + -- + open mycur for mv_master_tables using canon_mv_owner, canon_mv_name; + + loop + fetch mycur into tabowner, tabname; + exit when mycur%notfound; -- exit loop when last row is fetched + + -- construct ""."" + owner_name := '"' || tabowner || '"."' || tabname || '"'; + + -- remove DML handlers + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => canon_apply); + + -- remove rules + for rec in table_rules(canon_capture, canon_apply, tabowner, tabname) loop + -- construct ""."" + owner_name := '"' || rec.rule_owner || '"."' || rec.rule_name || '"'; + + dbms_streams_adm.remove_rule( + rule_name => owner_name, + streams_type => rec.streams_type, + streams_name => rec.streams_name); + end loop; + end loop; + + -- delete MV from registration metadata + delete from stmv_reg + where mv_owner = canon_mv_owner + and mv_name = canon_mv_name; + + commit; + + streams_mv_refresh.print_trace('unregister_mv()-'); + +exception when others then + if mycur%isopen then + close mycur; + end if; + raise; +end; + + +-- +-- remove streams used for streams-driven refresh +-- +procedure remove_streams_mv_refresh( + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER') is + + owner_name varchar2(80); + inst_scn number; + db varchar2(128); + cnt pls_integer := 0; + canon_capture varchar2(30); + canon_apply varchar2(30); + capture_queue varchar2(30); + apply_queue varchar2(30); + + -- selects tables set up for MV refresh apply + cursor apply_tables(apply_name varchar2) is + select table_owner, table_name + from dba_streams_table_rules + where streams_type = 'APPLY' + and streams_name = apply_name; + + cursor instantiated_objects is + select source_object_owner table_owner, source_object_name table_name + from dba_apply_instantiated_objects + where SOURCE_OBJECT_TYPE = 'TABLE'; + +begin + streams_mv_refresh.print_trace('remove_streams_mv_refresh()+'); + + -- canonicalize inputs + dbms_utility.canonicalize(capture_name, canon_capture, 30); + dbms_utility.canonicalize(apply_name, canon_apply, 30); + + -- stop capture and apply + dbms_capture_adm.stop_capture(canon_capture); + dbms_apply_adm.stop_apply(canon_apply); + + -- get queue_name from capture process + begin + select queue_name into capture_queue + from dba_capture + where capture_name = canon_capture; + exception + when NO_DATA_FOUND then + raise_application_error(-20000, 'capture not found'); + end; + + -- get queue_name from apply process + begin + select queue_name into apply_queue + from dba_apply + where apply_name = canon_apply; + exception + when NO_DATA_FOUND then + raise_application_error(-20000, 'apply not found'); + end; + + -- capture and apply must share the same queue + if apply_queue != capture_queue then + raise_application_error(-20000, + 'capture and apply must share the same queue'); + end if; + + for rec in apply_tables(canon_apply) loop + -- construct ""."" + owner_name := '"' || rec.table_owner || '"."' || rec.table_name || '"'; + + -- remove dml handlers + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => canon_apply); + + end loop; + + -- remove capture and apply + dbms_apply_adm.drop_apply(canon_apply, true); + dbms_capture_adm.drop_capture(canon_capture, true); + + -- remove queues + dbms_streams_adm.remove_queue(capture_queue); + + -- if there are no apply processes left, remove any dangling + -- table instantiation scns + select count(*) into cnt + from dba_apply; + + if (cnt = 0) then + for rec in instantiated_objects loop + -- construct ""."" + owner_name := '"' || rec.table_owner || '"."' || rec.table_name || '"'; + + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => streams_mv_refresh_adm.source_dbname, + instantiation_scn => null); + end loop; + else + -- other apply processes exist, so print a message to the caller + dbms_output.put_line('NOTE: Other apply processes exist so '|| + 'table instantiation scns were not removed.'); + dbms_output.put_line('To remove them, call ' || + 'dbms_apply_adm.set_table_instantiation_scn'); + dbms_output.put_line('Example:'); + dbms_output.put_line(' dbms_apply_adm.set_table_instantiation_scn('); + dbms_output.put_line(' source_object_name => ''tabowner.foo'','); + dbms_output.put_line(' source_database_name => db,'); + dbms_output.put_line(' instantiation_scn => null);'); + end if; + + -- delete any MV registration metadata + delete from stmv_reg; + commit; + + streams_mv_refresh.print_trace('remove_streams_mv_refresh()-'); + +end; + + +-- +-- package instantiation code +-- +begin + -- read in MV registration metadata + for rec in mv_group loop + reg_mvs.extend; + reg_mvs(reg_mvs.last) := rec.sys_nc_rowinfo$; + end loop; +end streams_mv_refresh_adm; +/ + + +create or replace package body streams_mv_refresh as + +first_in_session boolean := TRUE; -- do once per apply session + +-- +-- prints debug statements to the trace file +-- +procedure print_trace(mesg varchar2) is +begin + -- enable this line if you want tracing + --sys.dbms_system.ksdwrt(1, mesg); + + null; +end; + + +-- +-- returns list of registered MVs +-- +function get_mvs return stmv_mvs_t is +begin + return streams_mv_refresh_adm.reg_mvs; +end; + + +-- +-- determines an anydata value's datatype and binds it appropriately +-- +procedure bind_anydata(sql_cursor pls_integer, + name varchar2, + value sys.anydata) is + + tmp sys.anytype; + col_type pls_integer; + col_max_len pls_integer := 4000; + haslob boolean := FALSE; + +begin + print_trace('bind_anydata()+'); + + col_type := value.getType(tmp); + print_trace('col_type='||col_type); + + if col_type = 1 then + dbms_sql.bind_variable(sql_cursor, name, value.AccessChar, col_max_len); + elsif col_type = 2 then -- number + dbms_sql.bind_variable(sql_cursor, name, value.AccessNumber); + elsif col_type = DBMS_TYPES.TYPECODE_UROWID then -- rowid + -- anydata doesn't support rowid in 9i + dbms_sql.bind_variable(sql_cursor, name, value.AccessURowid); + elsif col_type = 12 then -- date + dbms_sql.bind_variable(sql_cursor, name, value.Accessdate); + elsif col_type = 23 then -- raw + dbms_sql.bind_variable_raw(sql_cursor, name, value.AccessRaw); + elsif col_type = 96 then + dbms_sql.bind_variable_char(sql_cursor, name, value.AccessChar, + col_max_len); + elsif col_type = DBMS_TYPES.TYPECODE_NCHAR then + dbms_sql.bind_variable_char(sql_cursor, name, value.AccessNChar, + col_max_len); + elsif col_type = 112 then -- clob + dbms_sql.bind_variable(sql_cursor, name, value.Accessclob); + haslob := true; + elsif col_type = DBMS_TYPES.TYPECODE_NCLOB then + dbms_sql.bind_variable(sql_cursor, name, value.Accessnclob); + haslob := true; + elsif col_type = 113 then -- blob + dbms_sql.bind_variable(sql_cursor, name, value.Accessblob); + haslob := true; + elsif col_type = 180 then -- timestamp + dbms_sql.bind_variable(sql_cursor, name, value.AccessTimestamp); + elsif col_type = 181 then -- timestamp with time zone + dbms_sql.bind_variable(sql_cursor, name, value.AccessTimestampTZ()); + elsif col_type=231 then -- timestamp with local time zone + dbms_sql.bind_variable(sql_cursor, name, value.AccessTimestampLTZ()); + elsif col_type = 182 then -- interval year to month + dbms_sql.bind_variable(sql_cursor, name, value.AccessIntervalYM()); + elsif col_type = 183 then -- interval day to second + dbms_sql.bind_variable(sql_cursor, name, value.AccessIntervalDS()); + end if; + + print_trace('bind_anydata()-'); +end; + + +-- +-- Given an MV, returns a comma-separated list of tables with a flashback +-- clause. Will be used for the FROM clause in a refresh query. +-- +function get_mvtab_list(mv_no pls_integer, + old_new varchar2, + null_check boolean) return varchar2 is + mvtab_list varchar2(32000); + flashback_clause varchar2(20); +begin + if (old_new = 'NEW') then + flashback_clause := ' AS OF SCN(:scn) '; + else + flashback_clause := ' AS OF SCN(:scn-1) '; + end if; + + for i in get_mvs()(mv_no).base_tabs.first .. + get_mvs()(mv_no).base_tabs.last loop + + -- add comma separator + if (i > get_mvs()(mv_no).base_tabs.first) then + mvtab_list := mvtab_list || ', '; + end if; + + mvtab_list := mvtab_list || '"' + || get_mvs()(mv_no).base_tabs(i).table_owner + || '"."' || get_mvs()(mv_no).base_tabs(i).table_name || '"' + || flashback_clause; + + if (get_mvs()(mv_no).base_tabs(i).table_alias is not null) then + mvtab_list := mvtab_list || '"' || + get_mvs()(mv_no).base_tabs(i).table_alias || '"'; + end if; + + end loop; + + if (not null_check) then + -- add rowid temp table + mvtab_list := mvtab_list || ', stmv_rid'; + end if; + + return mvtab_list; +end; + + +-- +-- constructs selection predicates to uniquely identify a row in a master table +-- +function append_tab_cond(mv_no pls_integer, + tab_no pls_integer, + delete_or_upsert varchar2, + null_check boolean := FALSE) return varchar2 is + + tab_cond varchar2(32000); + +begin + print_trace('append_tab_cond()+'); + + -- table alias or owner.table + if (get_mvs()(mv_no).base_tabs(tab_no).table_alias is not null) then + tab_cond := tab_cond || '"' || + get_mvs()(mv_no).base_tabs(tab_no).table_alias || '"'; + else + tab_cond := tab_cond || '"' || + get_mvs()(mv_no).base_tabs(tab_no).table_owner || '"."' || + get_mvs()(mv_no).base_tabs(tab_no).table_name || '"'; + end if; + + -- rowid column: check for null or rowid match + if (null_check) then + tab_cond := tab_cond ||'.' || streams_mv_refresh.rowid_col || ' is null '; + else + -- join with stmv_rid (rowid table) on rowid, table owner, table name, + -- and dml_type + tab_cond := tab_cond ||'.' || streams_mv_refresh.rowid_col || + ' = stmv_rid.rid '; + tab_cond := tab_cond || + 'and stmv_rid.table_owner = ' || '''' || + get_mvs()(mv_no).base_tabs(tab_no).table_owner || '''' || + ' and stmv_rid.table_name = ' || '''' || + get_mvs()(mv_no).base_tabs(tab_no).table_name || ''' '; + + if (delete_or_upsert = 'DELETE') then + tab_cond := tab_cond || 'and stmv_rid.dml_type in (2,4) '; + else + tab_cond := tab_cond || 'and stmv_rid.dml_type in (1,2) '; + end if; + end if; + + print_trace('append_tab_cond()-'); + + return tab_cond; +end; + + +-- +-- create flashback query relative to a base table in the MV query +-- +function create_query(delete_or_upsert varchar2, + mv_no pls_integer, + tab_no pls_integer, + null_check boolean := FALSE) return varchar2 is + + query varchar2(32000); + orig_where varchar2(32000); -- MV where clause + oldnew1 varchar2(5); + oldnew2 varchar2(5); + +begin + print_trace('create_query()+'); + + -- for deletes, get all MV rows removed due to the delete + -- otherwise, get all MV rows added due to the update/insert dml + if (delete_or_upsert = 'DELETE') then + oldnew1 := 'OLD'; + oldnew2 := 'NEW'; + else + oldnew1 := 'NEW'; + oldnew2 := 'OLD'; + end if; + + -- get original MV where clause + orig_where := get_mvs()(mv_no).where_clause; + if (orig_where is not null) then + orig_where := ' AND ' || orig_where; + end if; + + query := 'SELECT /*+ leading(stmv_rid) */ ' || + get_mvs()(mv_no).select_list || + ' FROM ' || get_mvtab_list(mv_no, oldnew1, null_check) || + ' WHERE ' || append_tab_cond(mv_no, tab_no, delete_or_upsert, + null_check) || orig_where || + ' MINUS ' || + 'SELECT /*+ leading(stmv_rid) */ ' || + get_mvs()(mv_no).select_list || + ' FROM ' || get_mvtab_list(mv_no, oldnew2, null_check) || + ' WHERE ' || append_tab_cond(mv_no,tab_no, delete_or_upsert, + null_check) || orig_where; + + print_trace('sql_stmt='||query); + print_trace('create_query()-'); + return query; +end create_query; + + +-- +-- find the next MV that has owner.name as a base table +-- mv_no, tab_no keeps track of current position in MV registration metadata +-- +function find_next_mv(owner varchar2, + name varchar2, + streams_refresh boolean, + mv_no in out nocopy pls_integer, + tab_no in out nocopy pls_integer) +return boolean is + + str_ref pls_integer; + +begin + print_trace('find_next_mv()+'); + + if (streams_refresh) then + str_ref := 1; + else + str_ref := 0; + end if; + + -- MVs can be registered for streams-based refresh or traditional refresh. + -- MV registration metadata keeps track of the refresh method registered. + if mv_no is null then + mv_no := get_mvs().first; + tab_no := get_mvs()(mv_no).base_tabs.first; + else + tab_no := get_mvs()(mv_no).base_tabs.next(tab_no); + if tab_no is null then + mv_no := get_mvs().next(mv_no); + if mv_no is not null then + tab_no := get_mvs()(mv_no).base_tabs.first; + end if; + end if; + end if; + + -- find next MV that has owner.name as a base table + while mv_no is not null loop + -- make sure MV stream_refresh flag = streams_refresh param + if (get_mvs()(mv_no).use_str_refresh = str_ref) then + while tab_no is not null loop + if (get_mvs()(mv_no).base_tabs(tab_no).table_owner = owner + and get_mvs()(mv_no).base_tabs(tab_no).table_name = name) then + + print_trace('found MV: '|| + get_mvs()(mv_no).mv_owner || '.' || get_mvs()(mv_no).mv_name); + print_trace('find_next_mv()-'); + return TRUE; + end if; + + tab_no := get_mvs()(mv_no).base_tabs.next(tab_no); + end loop; + end if; + + mv_no := get_mvs().next(mv_no); + if (mv_no is not null) then + tab_no := get_mvs()(mv_no).base_tabs.first; + end if; + + end loop; + + print_trace('find_next_mv()-'); + return FALSE; +end find_next_mv; + + +-- +-- +-- +procedure define_columns(sql_cursor pls_integer, + num_cols pls_integer, + desc_table sys.dbms_sql.desc_tab) is + + col_type pls_integer; + vcval varchar2(32000); + dateval date; + numval number; + rowidval rowid; + nvcval nvarchar2(15000); + rawval raw(2000); + charval char(2000); + ncval nchar(1000); + clobval clob; + blobval blob; + nclobval nclob; + -- tmval time(9); + -- tmtzval time(9) with time zone; + tmstpval timestamp(9); + tmstptzval timestamp(9) with time zone; + tmstpltzval timestamp(9) with local time zone; + ytomintval interval year(9) to month; + dtosintval interval day(9) to second(9); + haslob boolean := false; + +begin + for ctr in 1..num_cols loop + col_type := desc_table(ctr).col_type; + + if (col_type = 1) then + if (desc_table(ctr).col_charsetform != 2) then -- varchar2 + dbms_sql.define_column(sql_cursor,ctr,vcval, + desc_table(ctr).col_max_len); + else -- nvarchar2 + dbms_sql.define_column(sql_cursor,ctr,vcval, + desc_table(ctr).col_max_len); + end if; + elsif (col_type = 2) then -- number + dbms_sql.define_column(sql_cursor,ctr,numval); + elsif (col_type = 11) then -- rowid + dbms_sql.define_column_rowid(sql_cursor,ctr,rowidval); + elsif (col_type = 12) then -- date + dbms_sql.define_column(sql_cursor,ctr,dateval); + elsif (col_type = 23) then -- raw + dbms_sql.define_column_raw(sql_cursor,ctr,rawval, + desc_table(ctr).col_max_len); + elsif (col_type = 96) then + if (desc_table(ctr).col_charsetform != 2) then -- char + dbms_sql.define_column_char(sql_cursor,ctr,charval, + desc_table(ctr).col_max_len); + else -- nchar + dbms_sql.define_column_char(sql_cursor,ctr,ncval, + desc_table(ctr).col_max_len); + end if; + elsif (col_type = 112) then -- clob + if (desc_table(ctr).col_charsetform) != 2 then + dbms_sql.define_column(sql_cursor,ctr,clobval); + else + dbms_sql.define_column(sql_cursor,ctr,nclobval); + end if; + haslob := true; + elsif (col_type = 113) then -- blob + dbms_sql.define_column(sql_cursor,ctr,blobval); + haslob := true; +-- elsif (col_type = 178) then -- time +-- dbms_sql.define_column(sql_cursor,ctr,tmval); +-- elsif (col_type = 179) then -- time with time zone +-- dbms_sql.define_column(sql_cursor,ctr,tmtzval); + elsif (col_type = 180) then -- timestamp + dbms_sql.define_column(sql_cursor,ctr,tmstpval); + elsif (col_type = 181) then -- timestamp with time zone + dbms_sql.define_column(sql_cursor,ctr,tmstptzval); + elsif (col_type = 231) then -- timestamp with local time zone + dbms_sql.define_column(sql_cursor,ctr,tmstpltzval); + elsif (col_type = 182) then -- interval year to month + dbms_sql.define_column(sql_cursor,ctr,ytomintval); + elsif (col_type = 183) then -- interval day to second + dbms_sql.define_column(sql_cursor,ctr,dtosintval); + end if; + end loop; + +end; + + +-- +-- +-- +procedure get_column_values(sql_cursor pls_integer, + num_cols pls_integer, + desc_table sys.dbms_sql.desc_tab, + is_key_col stmv_num_list, + lcr in out nocopy sys.lcr$_row_record, + cmd_type varchar2, + first_time boolean) is + + col_type pls_integer; + col_name varchar2(32); + vcval varchar2(32000); + dateval date; + numval number; + rowidval rowid; + nvcval nvarchar2(15000); + rawval raw(2000); + charval char(2000); + ncval nchar(1000); + clobval clob; + blobval blob; + nclobval nclob; + -- tmval time(9); + -- tmtzval time(9) with time zone; + tmstpval timestamp(9); + tmstptzval timestamp(9) with time zone; + tmstpltzval timestamp(9) with local time zone; + ytomintval interval year(9) to month; + dtosintval interval day(9) to second(9); + myany sys.anydata; + is_key boolean; + +begin + -- build the lcr based upon the data type of + -- the column selected... + for ctr in 1..num_cols loop + col_type := desc_table(ctr).col_type; + col_name := '"' || desc_table(ctr).col_name || '"'; + is_key := (is_key_col(ctr) = 1); + + -- DELETE: only process key columns + if (cmd_type = 'DELETE' and not is_key) then + goto next_col; + end if; + + if (col_type = 1) then + if (desc_table(ctr).col_charsetform != 2) then -- varchar2 + dbms_sql.column_value(sql_cursor,ctr,vcval); + myany := Sys.AnyData.ConvertVarchar2(vcval); + else -- nvarchar2 + dbms_sql.column_value(sql_cursor,ctr,vcval); + myany := Sys.AnyData.ConvertNVarchar2(vcval); + end if; + elsif (col_type = 2) then -- number + dbms_sql.column_value(sql_cursor,ctr,numval); + myany := Sys.AnyData.ConvertNumber(numval); + elsif (col_type = 11) then -- rowid + dbms_sql.column_value_rowid(sql_cursor,ctr,rowidval); + -- in 10i, rowid will be supported; for now put in a char + print_trace('rowidval='||rowidval); + vcval := rowidval; + myany := Sys.AnyData.ConvertVarchar2(vcval); + elsif (col_type = 12) then -- date + dbms_sql.column_value(sql_cursor,ctr,dateval); + myany := Sys.AnyData.ConvertDate(dateval); + elsif (col_type = 23) then -- raw + dbms_sql.column_value_raw(sql_cursor,ctr,rawval); + myany := Sys.AnyData.ConvertRaw(rawval); + elsif (col_type = 96) then + if desc_table(ctr).col_charsetform != 2 then -- char + dbms_sql.column_value_char(sql_cursor,ctr,charval); + myany := Sys.AnyData.ConvertChar( -- trim charval to col_max_len + substr(charval, 1, desc_table(ctr).col_max_len)); + else -- nchar + dbms_sql.column_value_char(sql_cursor,ctr,ncval); + myany := Sys.AnyData.ConvertNchar( -- trim ncval to col_max_len + substr(ncval, 1, desc_table(ctr).col_max_len)); + end if; + elsif (col_type = 112) then -- clob + -- not supported for now + null; + elsif (col_type = 113) then -- blob + -- not supported for now + null; +-- elsif col_type = 178 then -- time +-- dbms_sql.column_value(sql_cursor,ctr,tmval); +-- -- anydata and time type??? +-- myany := Sys.AnyData.ConvertTimestamp(tmval); +-- elsif col_type = 179 then -- time with time zone +-- -- time type??? +-- dbms_sql.column_value(sql_cursor,ctr,tmtzval); +-- myany := Sys.AnyData.ConvertTimestampTZ(tmtzval); + elsif (col_type = 180) then -- timestamp + dbms_sql.column_value(sql_cursor,ctr,tmstpval); + myany := Sys.AnyData.ConvertTimestamp(tmstpval); + elsif (col_type = 181) then -- timestamp with time zone + dbms_sql.column_value(sql_cursor,ctr,tmstptzval); + myany := Sys.AnyData.ConvertTimestampTZ(tmstptzval); + elsif (col_type = 231) then -- timestamp with local timezone + dbms_sql.column_value(sql_cursor,ctr,tmstpltzval); + myany := Sys.AnyData.ConvertTimestampLTZ(tmstpltzval); + elsif (col_type = 182) then -- interval year to month + dbms_sql.column_value(sql_cursor,ctr,ytomintval); + myany := Sys.AnyData.ConvertIntervalYM(ytomintval); + elsif (col_type = 183) then -- interval day to second + dbms_sql.column_value(sql_cursor,ctr,dtosintval); + myany := Sys.AnyData.ConvertIntervalDS(dtosintval); + end if; + + if ((cmd_type = 'DELETE' or cmd_type = 'UPDATE') + and is_key) then + if (first_time) then + lcr.add_column('OLD', col_name, myany); + else + lcr.set_value('OLD', col_name, myany); + end if; + end if; + + if (cmd_type = 'INSERT' or cmd_type = 'UPDATE') then + if (first_time) then + lcr.add_column('NEW', col_name, myany); + else + lcr.set_value('NEW', col_name, myany); + end if; + end if; + + <> + null; + end loop; +end; + + +-- +-- for each row fetched from flashback query, creates and executes LCRs +-- +-- NOTE: no lobs in this version +procedure build_and_process_lcrs(sql_cursor pls_integer, + num_cols pls_integer, + desc_table sys.dbms_sql.desc_tab, + source_dbname varchar2, + cmd_type varchar2, + obj_owner varchar2, + obj_name varchar2, + key_cols stmv_column_list) is + + num_rows pls_integer; + lcr sys.lcr$_row_record; + is_key_col stmv_num_list := stmv_num_list(0); + first_time boolean := TRUE; + +begin + print_trace('build_and_process_lcrs()+'); + print_trace('cmd_type='||cmd_type); + print_trace('obj_owner='||obj_owner); + print_trace('obj_name='||obj_name); + + -- set up is_key_col array + -- initialize + is_key_col.extend(num_cols-1,1); + -- set elements that are key cols + for i in 1..num_cols loop + for j in key_cols.first .. key_cols.last loop + if (key_cols(j) = desc_table(i).col_name) then + is_key_col(i) := 1; + exit; + end if; + end loop; + end loop; + + -- execute the select statement + print_trace('before execute'); + num_rows := dbms_sql.execute(sql_cursor); + print_trace('after execute'); + + lcr := sys.lcr$_row_record.construct( + source_database_name=>source_dbname, + command_type=>cmd_type, + object_owner=>obj_owner, + object_name=>obj_name, + old_values=>NULL, + new_values=>NULL); + + -- loop until no more rows are returned + while dbms_sql.fetch_rows(sql_cursor) > 0 loop + print_trace('fetched row '); + + get_column_values(sql_cursor, num_cols, desc_table, is_key_col, + lcr, cmd_type, first_time); + + first_time := FALSE; + + streams_mv_lcr.process_lcr(lcr); + + end loop; + + print_trace('build_and_process_lcrs()-'); +end; + + +-- +-- +-- +procedure execute_delta_query(mv_idx pls_integer, + tab_idx pls_integer, + dml_type varchar2, + null_check boolean, + commit_scn number) is + + sql_stmt varchar2(32000); + sql_cursor pls_integer; + num_cols pls_integer; + desc_table sys.dbms_sql.desc_tab; + mv_owner varchar2(30); + mv_name varchar2(30); + key_cols stmv_column_list; + +begin + print_trace('execute_delta_query()+'); + + mv_owner := get_mvs()(mv_idx).mv_owner; + mv_name := get_mvs()(mv_idx).mv_name; + key_cols := get_mvs()(mv_idx).key_cols; + + sql_stmt := create_query(dml_type, mv_idx, tab_idx, null_check); + + print_trace('start parse and describe'); + sql_cursor := dbms_sql.open_cursor; + dbms_sql.parse(sql_cursor, sql_stmt, sys.dbms_sql.v7); + dbms_sql.describe_columns(sql_cursor, num_cols, desc_table); + print_trace('end parse and describe'); + + -- loop through the columns and do the define columns + print_trace('start define_columns'); + define_columns(sql_cursor, num_cols, desc_table); + print_trace('end define_columns'); + + -- bind the scn variable once + dbms_sql.bind_variable(sql_cursor, streams_mv_refresh.scn_bind, commit_scn); + + if (null_check) then + build_and_process_lcrs( + sql_cursor, + num_cols, + desc_table, + streams_mv_refresh_adm.source_dbname, + dml_type, + mv_owner, + mv_name, + key_cols); + else + print_trace('start process rowids'); + + build_and_process_lcrs( + sql_cursor, + num_cols, + desc_table, + streams_mv_refresh_adm.source_dbname, + dml_type, + mv_owner, + mv_name, + key_cols); + + print_trace('end process rowids'); + end if; + + dbms_sql.close_cursor(sql_cursor); + + print_trace('execute_delta_query()-'); +exception + when others then + if dbms_sql.is_open(sql_cursor) then + dbms_sql.close_cursor(sql_cursor); + end if; + raise; +end; + + +-- +-- adds rowid value to the rowid collection +-- +procedure add_to_rowid_coll(tab_rowid IN urowid, + rowid_coll IN OUT NOCOPY rowid_list) is + + found boolean := FALSE; + +begin + print_trace('add_to_rowid_coll()+'); + + -- see if rowid already exists in collection + if (rowid_coll.count > 0) then + for i in rowid_coll.first..rowid_coll.last loop + if (tab_rowid = rowid_coll(i)) then + found := TRUE; + exit; + end if; + end loop; + end if; + + -- new rowid: add to collection + if (found = FALSE) then + print_trace('new rowid'); + rowid_coll.extend; + rowid_coll(rowid_coll.last) := tab_rowid; + end if; + + print_trace('add_to_rowid_coll()-'); +end; + + +-- +-- adds to table collection that keeps track of DMLs and associated rowids +-- done to a table during a transaction +-- +procedure add_to_table_coll(tab_owner IN varchar2, + tab_name IN varchar2, + tab_dmltype IN pls_integer, + tab_rowid IN urowid, + tab_coll IN OUT NOCOPY txn_tab_list) is + + found boolean := FALSE; + +begin + print_trace('add_to_table_coll()+'); + + -- see if name already exists in table collection + if (tab_coll.count > 0) then + for i in tab_coll.first..tab_coll.last loop + if (tab_owner = tab_coll(i).table_owner and + tab_name = tab_coll(i).table_name) then + found := TRUE; + if (tab_dmltype is not null) then + if (bitand(tab_coll(i).dmltypes, tab_dmltype) = 0) then + tab_coll(i).dmltypes := tab_coll(i).dmltypes + tab_dmltype; + end if; + if (tab_rowid is not null) then + if (tab_dmltype = streams_mv_refresh.delete_dml or + tab_dmltype = streams_mv_refresh.update_dml) then + + add_to_rowid_coll(tab_rowid, tab_coll(i).delete_rowids); + + end if; + if (tab_dmltype = streams_mv_refresh.insert_dml or + tab_dmltype = streams_mv_refresh.update_dml) then + + add_to_rowid_coll(tab_rowid, tab_coll(i).insert_rowids); + + end if; + end if; + end if; + exit; + end if; + end loop; + end if; + + -- new table: add to collection + if (found = FALSE) then + print_trace('new table'); + tab_coll.extend; + tab_coll(tab_coll.last).table_owner := tab_owner; + tab_coll(tab_coll.last).table_name := tab_name; + tab_coll(tab_coll.last).dmltypes := tab_dmltype; + tab_coll(tab_coll.last).delete_rowids := rowid_list(); + tab_coll(tab_coll.last).insert_rowids := rowid_list(); + -- add rowid + if (tab_rowid is not null) then + if (tab_dmltype = streams_mv_refresh.delete_dml or + tab_dmltype = streams_mv_refresh.update_dml) then + + print_trace('adding delete rowid'); + tab_coll(tab_coll.last).delete_rowids:= rowid_list(tab_rowid); + + end if; + if (tab_dmltype = streams_mv_refresh.insert_dml or + tab_dmltype = streams_mv_refresh.update_dml) then + + print_trace('adding insert rowid'); + tab_coll(tab_coll.last).insert_rowids:= rowid_list(tab_rowid); + + end if; + end if; + end if; + + print_trace('add_to_table_coll()-'); +end; + + +-- +-- DML handler +-- +procedure source_dml_handler(lcr_anydata sys.anydata) is + + lcr sys.lcr$_row_record; + t pls_integer; + stmv_i pls_integer := null; -- iterator + tab_i pls_integer := null; -- iterator + commit_scn number := null; + dml_type varchar2(10); + dml_code pls_integer; + ridany sys.anydata; + ridval urowid; + object_owner varchar2(30); + object_name varchar2(30); + +BEGIN + print_trace('source_dml_handler()+'); + + t := lcr_anydata.getObject(lcr); + + commit_scn := lcr.get_commit_scn(); + print_trace('commit_scn='||commit_scn); + + -- get rowid from the lcr, if it exists + ridany := lcr.get_extra_attribute('row_id'); + + object_owner := lcr.get_object_owner; + object_name := lcr.get_object_name; + + print_trace('table=' || object_owner || '.' || object_name); + + if (first_in_session) then + -- do_enq_message('SET CONSTRAINTS ALL DEFERRED;'); + first_in_session := FALSE; + end if; + + -- + -- dbms_mview.refresh() codepath + -- + print_trace('processing MVs for dbms_mview.refresh()'); + + while (find_next_mv(object_owner, object_name, FALSE, + stmv_i, tab_i)) loop + + print_trace('MV=' || get_mvs()(stmv_i).mv_owner || '.' || + get_mvs()(stmv_i).mv_name); + + -- skip this MV if commit scn of this LCR <= the MV's instantiation scn + if (commit_scn > get_mvs()(stmv_i).inst_scn) then + + add_to_table_coll(get_mvs()(stmv_i).mv_owner, + get_mvs()(stmv_i).mv_name, + NULL, NULL, streams_mv_refresh.txn_mvs); + end if; + end loop; + + -- + -- streams refresh codepath + -- + print_trace('processing MVs for streams-based refresh'); + + stmv_i := null; + tab_i := null; + -- store table and lcr rowid if there is some MV dependent on the table + if find_next_mv(object_owner, object_name, TRUE, + stmv_i, tab_i) then + + -- need rowid for streams refresh + if (ridany is null) then + raise_application_error(-20000, + 'supplemental logging missing for rowid on ' || + object_owner || '.' || object_name); + end if; + ridval := ridany.AccessURowid; + print_trace('ridval='||ridval); + + dml_type := lcr.get_command_type; + print_trace('command_type=' || dml_type); + + if (dml_type = 'INSERT') then + dml_code := streams_mv_refresh.insert_dml; + elsif (dml_type = 'UPDATE') then + dml_code := streams_mv_refresh.update_dml; + elsif (dml_type = 'DELETE') then + dml_code := streams_mv_refresh.delete_dml; + else + dml_code := 0; + end if; + + -- add table to collection for commit-time processing + add_to_table_coll(object_owner, object_name, + dml_code, NULL, streams_mv_refresh.txn_tabs); + + print_trace('inserting into stmv_rid: '); + print_trace('table_owner='||object_owner); + print_trace('table_name='||object_name); + print_trace('dml_type='||dml_code); + print_trace('rid='||ridval); + + -- add rowid to temporary table for later processing + insert into stmv_rid (table_owner, table_name, dml_type, rid) + values (object_owner, object_name, dml_code, ridval); + end if; + + print_trace('source_dml_handler()-'); + +end; + +-- +-- autonmous block to create a scheduler job (this api commits) +-- +procedure create_scheduler_job(str varchar2) is + pragma autonomous_transaction; +begin + -- submit the refresh job + dbms_scheduler.create_job( + job_name => dbms_scheduler.generate_job_name, + job_type => 'PLSQL_BLOCK', + job_action => str, + start_date => sysdate, + enabled => TRUE); +end; + +-- +-- pre-commit handler +-- +procedure source_commit_hdlr(commit_scn number) is + l_jobnum pls_integer; + str varchar2(32000); + mvlist varchar2(32000); + is_first boolean := TRUE; + ref_scn number; -- refresh SCN + stmv_i pls_integer := null; -- iterator + tab_i pls_integer := null; -- iterator + dml_type varchar2(10); + is_mjv boolean; + is_ojmjv boolean; + tab_owner varchar2(30); + tab_name varchar2(30); + has_deletes boolean; + has_inserts boolean; + + -- MV last refresh scn + get_refscn varchar2(32000) := +'select rscn from sys.exu9snap + where owner = :mv_owner and name =:mv_name'; + +begin + print_trace('source_commit_hdlr()+'); + print_trace('commit_scn='||commit_scn); + + -- + -- dbms_mview.refresh() + -- + -- create comma-separated list of table owners and table names + if (streams_mv_refresh.txn_mvs.count > 0) then + + print_trace('processing MVs for dbms_mview.refresh()'); + + for i in streams_mv_refresh.txn_mvs.first.. + streams_mv_refresh.txn_mvs.last loop + + print_trace('MV=' || streams_mv_refresh.txn_mvs(i).table_owner || '.' || + streams_mv_refresh.txn_mvs(i).table_name); + + -- get the refresh scn + execute immediate get_refscn into ref_scn + using streams_mv_refresh.txn_mvs(i).table_owner, + streams_mv_refresh.txn_mvs(i).table_name; + + -- don't refresh the MV if it is current (this could happen if there + -- were any interim refreshes to the MV) + if (commit_scn >= ref_scn) then + -- add table to the list + if not is_first then + mvlist := mvlist || ','; + end if; + mvlist := mvlist || '"' || + streams_mv_refresh.txn_mvs(i).table_owner || '"."' || + streams_mv_refresh.txn_mvs(i).table_name || '"'; + is_first := FALSE; + end if; + end loop; + + -- submit a refresh job + str := + 'begin + dbms_mview.refresh(list=>''' || mvlist || ''',' || + 'atomic_refresh=>FALSE); + end;'; + + create_scheduler_job(str); + + -- reset mv_owners, mv_names collections + streams_mv_refresh.txn_mvs.delete; + end if; + + -- + -- streams-based refresh + -- + if (streams_mv_refresh.txn_tabs.count > 0) then + print_trace('processing MVs for streams-based refresh'); + + -- loop through all tables and DMLs done in the transaction + for i in streams_mv_refresh.txn_tabs.first.. + streams_mv_refresh.txn_tabs.last loop + + tab_owner := streams_mv_refresh.txn_tabs(i).table_owner; + tab_name := streams_mv_refresh.txn_tabs(i).table_name; + + -- determine if deletes or inserts were done (updates are considered + -- a delete followed by and insert) + has_deletes := (bitand(streams_mv_refresh.txn_tabs(i).dmltypes, + streams_mv_refresh.delete_dml) = + streams_mv_refresh.delete_dml + or + bitand(streams_mv_refresh.txn_tabs(i).dmltypes, + streams_mv_refresh.update_dml) = + streams_mv_refresh.update_dml); + + has_inserts := (bitand(streams_mv_refresh.txn_tabs(i).dmltypes, + streams_mv_refresh.insert_dml) = + streams_mv_refresh.insert_dml + or + bitand(streams_mv_refresh.txn_tabs(i).dmltypes, + streams_mv_refresh.update_dml) = + streams_mv_refresh.update_dml); + + print_trace('table=' || tab_owner || '.' || tab_name); + + while find_next_mv(tab_owner, tab_name, TRUE, stmv_i, tab_i) loop + + print_trace('MV=' || get_mvs()(stmv_i).mv_owner || '.' || + get_mvs()(stmv_i).mv_name); + + print_trace('MV inst_scn=' || get_mvs()(stmv_i).inst_scn); + if (commit_scn > get_mvs()(stmv_i).inst_scn) then + + print_trace('mv_flags='||get_mvs()(stmv_i).flags); + -- determine if an MJV + is_mjv := bitand(get_mvs()(stmv_i).flags, + streams_mv_refresh_adm.flg_mjv) = + streams_mv_refresh_adm.flg_mjv; + + -- determine if an outerjoin MJV + is_ojmjv := bitand(get_mvs()(stmv_i).flags, + streams_mv_refresh_adm.flg_mjv + + streams_mv_refresh_adm.flg_hasoj) = + streams_mv_refresh_adm.flg_mjv + + streams_mv_refresh_adm.flg_hasoj; + + -- join row processing + if (has_deletes) then + print_trace('delete phase: joins'); + + execute_delta_query(stmv_i, tab_i, 'DELETE', FALSE, commit_scn); + end if; + + if (has_inserts) then + print_trace('insert phase: joins'); + + if (is_mjv) then + dml_type := 'INSERT'; +-- dml_type := 'UPDATE'; + else + dml_type := 'INSERT'; + end if; + + execute_delta_query(stmv_i, tab_i, dml_type, FALSE, commit_scn); + end if; + + -- outer-join MJVs: take care of anti-join rows + if (is_ojmjv) then + + print_trace('is_ojmjv=true'); + + -- if INSERT or UPDATE was done, delete antijoins + if (has_inserts) then + print_trace('delete phase: antijoins'); + + execute_delta_query(stmv_i, tab_i, 'DELETE', TRUE, commit_scn); + end if; + + -- if DELETE or UPDATE was done, insert antijoins + if (has_deletes) then + print_trace('insert phase: antijoins'); + + execute_delta_query(stmv_i, tab_i, 'UPDATE', TRUE, commit_scn); + end if; + end if; + end if; + end loop; + + end loop; + + -- reset tab_owners, tab_names collections + streams_mv_refresh.txn_tabs.delete; + + end if; + + print_trace('source_commit_hdlr()-'); +end; + +end streams_mv_refresh; +/ + + +create or replace package body streams_mv_lcr as + +-- print LCR columns for debugging +procedure print_lcr_cols(cols sys.lcr$_row_list) is + col_type pls_integer; + tmp sys.anytype; + +begin + streams_mv_refresh.print_trace('print_lcr_cols()+'); + + -- make sure cols collection is non-empty + if (cols.count = 0) then + return; + end if; + + for i in cols.first..cols.last loop + streams_mv_refresh.print_trace('colname='||cols(i).column_name); + + col_type := cols(i).data.getType(tmp); + + if col_type = 1 then -- varchar2 + streams_mv_refresh.print_trace('colval='||cols(i).data.accessvarchar2); + elsif col_type = 2 then -- number + streams_mv_refresh.print_trace('colval='||cols(i).data.accessnumber); + else + streams_mv_refresh.print_trace('colval='||cols(i).data.accessvarchar2); + end if; + end loop; + + streams_mv_refresh.print_trace('print_lcr_cols()-'); +end; + + +-- +-- convert UPDATE LCR to an INSERT +-- +procedure do_an_insert(lcr sys.lcr$_row_record) is + tmp sys.anydata; + mv_no pls_integer; + i pls_integer; + found boolean := FALSE; + lcr_new sys.lcr$_row_record; + newvals sys.lcr$_row_list := sys.lcr$_row_list(); +begin + streams_mv_refresh.print_trace('do_an_insert()+'); + + if ( lcr.get_command_type = 'UPDATE' ) then + newvals := lcr.get_values('NEW', 'N'); + + -- double-quote all column names + for i in newvals.first..newvals.last loop + newvals(i).column_name := '"' || newvals(i).column_name || '"'; + end loop; + + lcr_new := sys.lcr$_row_record.construct( + source_database_name=>lcr.get_source_database_name, + command_type=>'INSERT', + object_owner=>lcr.get_object_owner, + object_name=>lcr.get_object_name, + old_values=>NULL, + new_values=>newvals); + + streams_mv_refresh.print_trace('printing newvals:'); +-- streams_mv_lcr.print_lcr_cols(newvals); + + lcr_new.execute(false); + end if; + + streams_mv_refresh.print_trace('do_an_insert()-'); +end; + + +-- +-- apply the LCR +-- +procedure process_lcr(lcr sys.lcr$_row_record) is + + -- new exception raised during apply to replace ora-1403 + row_does_not_exist exception; + pragma exception_init(row_does_not_exist, -26787); + +begin + streams_mv_refresh.print_trace('process_lcr()+'); + + -- this function may be customized to call a different procedure + begin + dbms_mview.set_i_am_a_refresh(true); -- allows the MV to be updated + lcr.execute(false); + streams_mv_refresh.print_trace('applied LCR'); + dbms_mview.set_i_am_a_refresh(false); + + exception + when DUP_VAL_ON_INDEX then + streams_mv_refresh.print_trace('DUP_VAL_ON_INDEX, type='|| + lcr.get_command_type); + + when NO_DATA_FOUND or row_does_not_exist then + streams_mv_refresh.print_trace('NO_DATA_FOUND, type='|| + lcr.get_command_type); + do_an_insert(lcr); + when others then + raise; + end; + + streams_mv_refresh.print_trace('process_lcr()-'); +end; + +end streams_mv_lcr; +/ + +-- Procedure for verifying results +create or replace procedure verify_tables(tab1 in varchar2, + tab2 in varchar2, + max_time in integer default 3600) + authid current_user as + + tab2_sql varchar2(32000); + tab1_sql varchar2(32000); + diff_sql varchar2(32000); + cur integer; + ret integer; + num_rows integer; + slept integer := 0; + wait_for_convergence boolean := true; + +begin + dbms_output.enable ( 10000 ) ; + + tab1_sql := 'select * from ' || tab1; + + tab2_sql := 'select * from ' || tab2; + +-- diff_sql is the query that should return 0 rows if the snapshot rows +-- have converged + diff_sql := '(' || + tab1_sql || + ' minus ' || + tab2_sql || + ')' || + ' union ' || + '(' || + tab2_sql || + ' minus ' || + tab1_sql || + ')' ; + + +-- get the no. of rows returned by diff_sql. + cur := dbms_sql.open_cursor; + dbms_sql.parse(cur, + 'select count(*) from ( ' || diff_sql || ' )', dbms_sql.v7); + sys.dbms_sql.define_column(cur, 1, num_rows); + begin + ret := dbms_sql.execute_and_fetch(cur); + dbms_sql.column_value(cur,1,num_rows); + exception when others then + if dbms_sql.is_open(cur) then + dbms_sql.close_cursor(cur); + end if; + dbms_output.put_line ('-- error while counting rows in diff_sql'); + raise; + end; + +while (wait_for_convergence) loop + ret := dbms_sql.execute_and_fetch(cur); + dbms_sql.column_value(cur,1,num_rows); + +-- begin num_rows if + if num_rows = 0 then + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + dbms_output.put_line('-- Tables/views '||tab1 ||' and '||tab2 || ' are identical'); + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + wait_for_convergence := false; + else + dbms_lock.sleep(3); + slept := slept + 3; + if (slept >= max_time ) then + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + dbms_output.put_line('-- WARNING: maximum wait time of '|| slept ||' seconds exceeded'); + dbms_output.put_line('-- Tables/views '||tab1 ||' and '||tab2 || ' are NOT identical'); + dbms_output.put_line('-- Check trace files to determine what is going wrong'); + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + wait_for_convergence := false; + end if; + end if; +end loop; + dbms_sql.close_cursor(cur); + +end; +/ + +create or replace public synonym verify_tables for verify_tables; +grant execute on verify_tables to public; diff --git a/strmqp1.sql b/strmqp1.sql new file mode 100644 index 0000000..bd8a060 --- /dev/null +++ b/strmqp1.sql @@ -0,0 +1,1098 @@ +Rem +Rem $Header: strmqp1.sql 23-jun-2006.15:31:45 wesmith Exp $ +Rem +Rem strmqp1.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem strmqp1.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem wesmith 06/23/06 - register_query: add parameter queue_name +Rem wesmith 06/12/06 - register_query: add include_extra_attribute() +Rem wesmith 01/19/06 - Created +Rem + +---------------------- +-- supporting objects +---------------------- + +-- master table metadata +create or replace type stq_table_t as object ( + table_owner varchar2(30), /* base table owner */ + table_name varchar2(30), /* base table name */ + refresh_query varchar2(4000), /* refresh query used by the dml handler */ + commit_query varchar2(4000) /* refresh query used by the pre-commit hdlr */ +) +/ +create or replace type stq_table_list is table of stq_table_t +/ + +-- query metadata +create or replace type stq_query_t as object ( + query_owner varchar2(30), /* query table owner */ + query_name varchar2(30), /* query table name */ + inst_scn number, /* query table instantiation scn */ + key_cols stmv_column_list, /* query table key columns */ + base_tabs stq_table_list /* MV base tables */ +) +/ +create or replace type stq_queries_t is table of stq_query_t +/ + +-- store streams query registration metadata +create table stq_reg of stq_query_t (primary key(query_owner, query_name)) + nested table key_cols store as stq_qry_keycol_st + nested table base_tabs store as stq_tab_st; + + +------------ +-- packages +------------ +create or replace package streams_qry_refresh_adm AUTHID CURRENT_USER as + type mycurtyp IS REF cursor; + reg_qrys stq_queries_t := stq_queries_t(); + + -- constants + source_dbname constant varchar2(256) := dbms_standard.database_name; + + -- sets up a query for streams-driven refresh + procedure register_query(query_owner varchar2, + query_name varchar2, + base_tables stq_table_list, + capture_name varchar2 :='CAPTURE_QRY_MASTER', + apply_name varchar2 :='APPLY_QRY_MASTER', + queue_name varchar2 := NULL); + + -- removes a query from streams-driven refresh + procedure unregister_query(query_owner varchar2, + query_name varchar2, + capture_name varchar2 := 'CAPTURE_QRY_MASTER', + apply_name varchar2 := 'APPLY_QRY_MASTER'); + + -- removes streams configuration for streams-driven query refresh + procedure remove_streams_qry_refresh( + capture_name varchar2 := 'CAPTURE_QRY_MASTER', + apply_name varchar2 := 'APPLY_QRY_MASTER'); + +end streams_qry_refresh_adm; +/ + + +-- +create or replace package streams_qry_refresh AUTHID CURRENT_USER as + + -- collection of table owners, names in a transaction + txn_tabs streams_mv_refresh.txn_tab_list := + streams_mv_refresh.txn_tab_list(); + + -- dml types + insert_dml constant pls_integer := 1; + update_dml constant pls_integer := 2; + delete_dml constant pls_integer := 4; + + rowid_col constant varchar2(5) := 'ROWID'; + scn_bind constant varchar2(5) := 'SCN'; + rowid_bind constant varchar2(5) := 'RID'; + + -- dml handler used by streams-driven refresh + procedure source_dml_handler(lcr_anydata in sys.anydata); + + -- pre-commit handler used by streams-driven refresh + procedure source_commit_hdlr(commit_scn number); + + procedure print_trace(mesg varchar2); +end streams_qry_refresh; +/ + + +-- +create or replace package streams_qry_lcr AUTHID CURRENT_USER as + -- applies an LCR to an MV during streams-based refresh + procedure process_lcr(lcr sys.lcr$_row_record); +end streams_qry_lcr; +/ + + +-- +create or replace package body streams_qry_refresh_adm as + + cursor query_reg is select sys_nc_rowinfo$ from stq_reg; + +-- +-- register a query for streams-driven refresh +-- +procedure register_query(query_owner varchar2, + query_name varchar2, + base_tables stq_table_list, + capture_name varchar2 := 'CAPTURE_QRY_MASTER', + apply_name varchar2 := 'APPLY_QRY_MASTER', + queue_name varchar2 := NULL) is + + canon_qry_owner varchar2(30); + canon_qry_name varchar2(30); + canon_tab_owner varchar2(30); + canon_tab_name varchar2(30); + canon_capture varchar2(30); + canon_apply varchar2(30); + canon_queue varchar2(30); + owner_name varchar2(80); -- table_owner.table_name + qryinfo stq_query_t := NULL; + cnt pls_integer; + select_pos pls_integer := 0; + select_start pls_integer := 0; + inst_scn number; -- instantiation SCN + key_cols stmv_column_list; + + canon_schema varchar2(30); + canon_part1 varchar2(30); + canon_part2 varchar2(30); + canon_dblink varchar2(128); + canon_part1_type number; + object_number number; + +begin + streams_qry_refresh.print_trace('register_query()+'); + streams_qry_refresh.print_trace('query_owner='||query_owner); + streams_qry_refresh.print_trace('query_name='||query_name); + streams_qry_refresh.print_trace('capture_name='||capture_name); + streams_qry_refresh.print_trace('apply_name='||apply_name); + streams_qry_refresh.print_trace('queue_name='||queue_name); + + -- canonicalize inputs + dbms_utility.canonicalize(query_owner, canon_qry_owner, 30); + dbms_utility.canonicalize(query_name, canon_qry_name, 30); + dbms_utility.canonicalize(capture_name, canon_capture, 30); + dbms_utility.canonicalize(apply_name, canon_apply, 30); + dbms_utility.canonicalize(queue_name, canon_queue, 30); + + -- make sure the apply process is down + select count(*) into cnt from dba_apply + where apply_name = canon_apply + and status = 'ENABLED'; + if (cnt > 0) then + raise_application_error(-20000, 'Apply process must be disabled'); + end if; + + -- get queue_name from capture and apply process views if NULL + if (canon_queue is NULL) then + declare + apply_queue varchar2(30); + capture_queue varchar2(30); + begin + -- get queue for capture and apply + select queue_name into capture_queue + from dba_capture + where capture_name = canon_capture; + + select queue_name into apply_queue + from dba_apply + where apply_name = canon_apply; + + -- capture and apply must share the same queue + if apply_queue != capture_queue then + raise_application_error(-20000, + 'capture and apply must share the same queue'); + end if; + + canon_queue := capture_queue; + + exception + when NO_DATA_FOUND then + raise_application_error(-20000, 'must specify queue_name'); + end; + end if; + + -- + -- make sure base_tables is not empty + -- + if (base_tables is null or base_tables.count = 0) then + raise_application_error(-20000, + 'base_tables collection must not be empty'); + end if; + + -- + -- error if query registration metadata already exists + -- + select count(*) into cnt + from stq_reg + where query_owner = canon_qry_owner + and query_name = canon_qry_name; + if (cnt > 0) then + owner_name := '"' || canon_qry_owner || '"."' || canon_qry_name || '"'; + raise_application_error(-20000, + 'Query ' || owner_name || ' already registered'); + end if; + + -- + -- check that tables exist + -- + -- construct ""."" + owner_name := '"' || canon_qry_owner || '"."' || canon_qry_name || '"'; + dbms_utility.name_resolve(owner_name, 2, canon_schema, canon_part1, + canon_part2, canon_dblink, canon_part1_type, object_number); + + for i in base_tables.first .. base_tables.last loop + dbms_utility.canonicalize(base_tables(i).table_owner, canon_tab_owner, 30); + dbms_utility.canonicalize(base_tables(i).table_name, canon_tab_name, 30); + owner_name := '"' || canon_tab_owner || '"."' || canon_tab_name || '"'; + + dbms_utility.name_resolve(owner_name, 2, canon_schema, canon_part1, + canon_part2, canon_dblink, canon_part1_type, object_number); + end loop; + + -- + -- validate refresh query: + -- begins with select + -- has :rid, :scn binds + for i in base_tables.first .. base_tables.last loop + dbms_utility.canonicalize(base_tables(i).table_owner, canon_tab_owner, 30); + dbms_utility.canonicalize(base_tables(i).table_name, canon_tab_name, 30); + owner_name := '"' || canon_tab_owner || '"."' || canon_tab_name || '"'; + + if (instr(upper(base_tables(i).refresh_query), 'SELECT') != 1 or + instr(upper(base_tables(i).refresh_query), ':RID') = 0 or + instr(upper(base_tables(i).refresh_query), ':SCN') = 0) then + raise_application_error(-20000, + 'Refresh query for ' || owner_name || ' has errors'); + end if; + end loop; + + -- get query key columns + key_cols := streams_mv_refresh_adm.get_keycols(canon_qry_owner, + canon_qry_name); + if (key_cols.count = 0) then + raise_application_error(-20000, + 'query table must have a PK or use dbms_apply_adm.set_key_columns()'); + end if; + if (key_cols.count > 0) then + for i in key_cols.first .. key_cols.last loop + streams_qry_refresh.print_trace('key_col='||key_cols(i)); + end loop; + end if; + + -- + -- initialize query metadata + -- + qryinfo := stq_query_t(canon_qry_owner, canon_qry_name, null, + stmv_column_list(), stq_table_list()); + -- get table keycols + qryinfo.key_cols := key_cols; + + -- store table information + qryinfo.base_tabs := base_tables; + + -- process all base tables + for i in base_tables.first .. base_tables.last loop + dbms_utility.canonicalize(base_tables(i).table_owner, canon_tab_owner, 30); + dbms_utility.canonicalize(base_tables(i).table_name, canon_tab_name, 30); + + -- save canonicalized tab owner/name in query metadata + qryinfo.base_tabs(i).table_owner := canon_tab_owner; + qryinfo.base_tabs(i).table_name := canon_tab_name; + + -- construct ""."" + owner_name := '"' || canon_tab_owner || '"."' || canon_tab_name || '"'; + + -- add apply rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'apply', + streams_name => canon_apply, + queue_name => canon_queue, + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + source_database => streams_qry_refresh_adm.source_dbname); + + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => 'streams_qry_refresh.source_dml_handler', + apply_database_link => NULL, + apply_name => canon_apply); + + -- add capture rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'capture', + streams_name => canon_capture, + queue_name => canon_queue, + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + inclusion_rule => true); + + end loop; + + -- capture rowids, too + dbms_capture_adm.include_extra_attribute(canon_capture, 'row_id', true); + + -- TODO: instantiate query table + -- + -- get instantiation scn by using current scn + -- (must be done after setting capture and apply table rules) + -- + inst_scn := dbms_flashback.get_system_change_number(); + + -- set instantiation scn + for i in base_tables.first .. base_tables.last loop + dbms_utility.canonicalize(base_tables(i).table_owner, canon_tab_owner, 30); + dbms_utility.canonicalize(base_tables(i).table_name, canon_tab_name, 30); + + -- construct ""."" + owner_name := '"' || canon_tab_owner || '"."' || canon_tab_name || '"'; + + -- if table already has an instantiation scn registered, don't call + -- dbms_apply_adm.set_table_instantiation_scn() + select count(*) into cnt + from dba_apply_instantiated_objects + where source_object_owner = canon_tab_owner + and source_object_name = canon_tab_name + and source_object_type = 'TABLE' + and source_database = streams_qry_refresh_adm.source_dbname; + + if (cnt = 0) then + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => streams_qry_refresh_adm.source_dbname, + instantiation_scn => inst_scn); + end if; + end loop; + + qryinfo.inst_scn := inst_scn; + + -- + -- save query registration metadata to disk + -- + insert into stq_reg values(qryinfo); + commit; + + streams_qry_refresh.print_trace('register_query()-'); + +end; + + +-- +-- remove a query from streams-driven refresh +-- +procedure unregister_query(query_owner varchar2, + query_name varchar2, + capture_name varchar2 := 'CAPTURE_QRY_MASTER', + apply_name varchar2 := 'APPLY_QRY_MASTER') is + + mycur mycurtyp; + tabowner varchar2(30); + tabname varchar2(30); + owner_name varchar2(80); + cnt pls_integer; + canon_qry_owner varchar2(30); + canon_qry_name varchar2(30); + canon_capture varchar2(30); + canon_apply varchar2(30); + + -- all table rules associated with the specified capture, apply and table + cursor table_rules(capture_name varchar2, apply_name varchar2, + table_owner varchar2, table_name varchar2) is + select streams_name, streams_type, rule_owner, rule_name + from dba_streams_table_rules str + where streams_type = 'CAPTURE' + and streams_name = capture_name + and table_owner = table_rules.table_owner + and table_name = table_rules.table_name + union + select streams_name, streams_type, rule_owner, rule_name + from dba_streams_table_rules str + where streams_type = 'APPLY' + and streams_name = apply_name + and table_owner = table_rules.table_owner + and table_name = table_rules.table_name; + + -- select all master tables registered by this query that is not used + -- by other registered queries + qry_base_tables varchar2(1000) := +'select bt.table_owner, bt.table_name + from stq_reg q, table(q.base_tabs) bt + where q.query_owner = :qry_owner + and q.query_name = :qry_name + and not exists + (select 1 + from stq_reg q2, table(q2.base_tabs) bt2 + where not (q2.query_owner = q.query_owner + and q2.query_name = q.query_name) + and bt.table_owner = bt2.table_owner + and bt.table_name = bt2.table_name)'; + +begin + streams_qry_refresh.print_trace('unregister_query()+'); + + -- canonicalize inputs + dbms_utility.canonicalize(query_owner, canon_qry_owner, 30); + dbms_utility.canonicalize(query_name, canon_qry_name, 30); + dbms_utility.canonicalize(capture_name, canon_capture, 30); + dbms_utility.canonicalize(apply_name, canon_apply, 30); + + -- make sure the apply process is down + select count(*) into cnt from dba_apply + where apply_name = canon_apply + and status = 'ENABLED'; + if (cnt > 0) then + raise_application_error(-20000, + 'Apply process must be disabled'); + end if; + + owner_name := '"' || canon_qry_owner || '"."' || canon_qry_name || '"'; + + -- + -- get query base tables + -- + open mycur for qry_base_tables using canon_qry_owner, canon_qry_name; + + loop + fetch mycur into tabowner, tabname; + exit when mycur%notfound; -- exit loop when last row is fetched + + -- construct ""."" + owner_name := '"' || tabowner || '"."' || tabname || '"'; + + -- remove DML handlers + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => canon_apply); + + -- remove rules + for rec in table_rules(canon_capture, canon_apply, tabowner, tabname) loop + -- construct ""."" + owner_name := '"' || rec.rule_owner || '"."' || rec.rule_name || '"'; + + dbms_streams_adm.remove_rule( + rule_name => owner_name, + streams_type => rec.streams_type, + streams_name => rec.streams_name); + end loop; + end loop; + + -- delete query from registration metadata + delete from stq_reg + where query_owner = canon_qry_owner + and query_name = canon_qry_name; + + commit; + + streams_qry_refresh.print_trace('unregister_query()-'); + +exception when others then + if mycur%isopen then + close mycur; + end if; + raise; +end; + + +-- +-- remove streams used for streams-driven refresh +-- +procedure remove_streams_qry_refresh( + capture_name varchar2 := 'CAPTURE_QRY_MASTER', + apply_name varchar2 := 'APPLY_QRY_MASTER') is + + owner_name varchar2(80); + inst_scn number; + db varchar2(128); + cnt pls_integer := 0; + canon_capture varchar2(30); + canon_apply varchar2(30); + capture_queue varchar2(30); + apply_queue varchar2(30); + + -- selects tables set up for query refresh apply + cursor apply_tables(apply_name varchar2) is + select table_owner, table_name + from dba_streams_table_rules + where streams_type = 'APPLY' + and streams_name = apply_name; + + cursor instantiated_objects is + select source_object_owner table_owner, source_object_name table_name + from dba_apply_instantiated_objects + where SOURCE_OBJECT_TYPE = 'TABLE'; + +begin + streams_qry_refresh.print_trace('remove_streams_qry_refresh()+'); + + -- canonicalize inputs + dbms_utility.canonicalize(capture_name, canon_capture, 30); + dbms_utility.canonicalize(apply_name, canon_apply, 30); + + -- stop capture and apply + dbms_capture_adm.stop_capture(canon_capture); + dbms_apply_adm.stop_apply(canon_apply); + + -- get queue_name from capture process + begin + select queue_name into capture_queue + from dba_capture + where capture_name = canon_capture; + exception + when NO_DATA_FOUND then + raise_application_error(-20000, 'capture not found'); + end; + + -- get queue_name from apply process + begin + select queue_name into apply_queue + from dba_apply + where apply_name = canon_apply; + exception + when NO_DATA_FOUND then + raise_application_error(-20000, 'apply not found'); + end; + + -- capture and apply must share the same queue + if apply_queue != capture_queue then + raise_application_error(-20000, + 'capture and apply must share the same queue'); + end if; + + for rec in apply_tables(canon_apply) loop + -- construct ""."" + owner_name := '"' || rec.table_owner || '"."' || rec.table_name || '"'; + + -- remove dml handlers + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => canon_apply); + + end loop; + + -- remove capture and apply + dbms_apply_adm.drop_apply(canon_apply, true); + dbms_capture_adm.drop_capture(canon_capture, true); + + -- remove queues + dbms_streams_adm.remove_queue(capture_queue); + + -- if there are no apply processes left, remove any dangling + -- table instantiation scns + select count(*) into cnt + from dba_apply; + + if (cnt = 0) then + for rec in instantiated_objects loop + -- construct ""."" + owner_name := '"' || rec.table_owner || '"."' || rec.table_name || '"'; + + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => streams_qry_refresh_adm.source_dbname, + instantiation_scn => null); + end loop; + else + -- other apply processes exist, so print a message to the caller + dbms_output.put_line('NOTE: Other apply processes exist so '|| + 'table instantiation scns were not removed.'); + dbms_output.put_line('To remove them, call ' || + 'dbms_apply_adm.set_table_instantiation_scn'); + dbms_output.put_line('Example:'); + dbms_output.put_line(' dbms_apply_adm.set_table_instantiation_scn('); + dbms_output.put_line(' source_object_name => ''tabowner.foo'','); + dbms_output.put_line(' source_database_name => db,'); + dbms_output.put_line(' instantiation_scn => null);'); + end if; + + -- delete any query registration metadata + delete from stq_reg; + commit; + + streams_qry_refresh.print_trace('remove_streams_qry_refresh()-'); + +end; + +-- +-- package instantiation code +-- +begin + -- read in query registration metadata + for rec in query_reg loop + reg_qrys.extend; + reg_qrys(reg_qrys.last) := rec.sys_nc_rowinfo$; + end loop; +end streams_qry_refresh_adm; +/ + + +-- +create or replace package body streams_qry_refresh as + +-- +-- prints debug statements to the trace file +-- +procedure print_trace(mesg varchar2) is +begin + -- enable this line if you want tracing + --sys.dbms_system.ksdwrt(1, mesg); + + null; +end; + + +-- +-- returns list of registered queries +-- +function get_qrys return stq_queries_t is +begin + return streams_qry_refresh_adm.reg_qrys; +end; + + +-- +-- create flashback query relative to a base table in the query +-- +function create_query(delete_or_upsert varchar2, + qry_no pls_integer, + tab_no pls_integer, + is_commit_query boolean) return varchar2 is + + query_after varchar2(32000); -- query at commit scn + query varchar2(32000); + prev_pos number :=1; + cur_pos number; + +begin + print_trace('create_query()+'); + + if (is_commit_query) then + query_after := + get_qrys()(qry_no).base_tabs(tab_no).commit_query; + else + query_after := + get_qrys()(qry_no).base_tabs(tab_no).refresh_query; + end if; + + -- replace all instances of ':SCN' with ':SCN-1' + -- to create a query which will get the 'before' image + while (true) loop + cur_pos := instr(upper(query_after), ':SCN', prev_pos); + + if (cur_pos = 0) then + exit; + end if; + + query := query || substr(query_after, prev_pos, cur_pos + 4 - prev_pos) + || '-1'; + prev_pos := cur_pos +4; + end loop; + + query := query || substr(query_after, prev_pos); + + if (delete_or_upsert = 'DELETE') then + query := query || ' MINUS ' || query_after; + else + query := query_after || ' MINUS ' || query; + end if; + + print_trace('sql_stmt='||query); + print_trace('create_query()-'); + return query; + +end create_query; + + +-- +-- find the next query that has owner.name as a base table +-- qry_no, tab_no keeps track of current position in query +-- registration metadata +-- +function find_next_qry(owner varchar2, + name varchar2, + qry_no in out pls_integer, + tab_no in out pls_integer) return boolean is + +begin + print_trace('find_next_qry()+'); + + if qry_no is null then + qry_no := get_qrys().first; + tab_no := get_qrys()(qry_no).base_tabs.first; + else + tab_no := get_qrys()(qry_no).base_tabs.next(tab_no); + if tab_no is null then + qry_no := get_qrys().next(qry_no); + if qry_no is not null then + tab_no := get_qrys()(qry_no).base_tabs.first; + end if; + end if; + end if; + + -- find next query that has owner.name as a base table + while qry_no is not null loop + while tab_no is not null loop + if (get_qrys()(qry_no).base_tabs(tab_no).table_owner = owner + and + get_qrys()(qry_no).base_tabs(tab_no).table_name = name) then + + print_trace('found query: '|| get_qrys()(qry_no).query_owner || '.' || + get_qrys()(qry_no).query_name); + print_trace('find_next_qry()-'); + return TRUE; + end if; + + tab_no := get_qrys()(qry_no).base_tabs.next(tab_no); + end loop; + + qry_no := get_qrys().next(qry_no); + if (qry_no is not null) then + tab_no := get_qrys()(qry_no).base_tabs.first; + end if; + + end loop; + + print_trace('find_next_qry()-'); + return FALSE; +end find_next_qry; + + +-- +-- for each row fetched from flashback query, creates and executes LCRs +-- +-- NOTE: no lobs in this version +procedure build_and_process_lcrs(sql_cursor pls_integer, + num_cols pls_integer, + desc_table sys.dbms_sql.desc_tab, + source_dbname varchar2, + cmd_type varchar2, + obj_owner varchar2, + obj_name varchar2, + key_cols stmv_column_list) is + + num_rows number; + lcr sys.lcr$_row_record; + is_key_col stmv_num_list := stmv_num_list(0); + first_time boolean := TRUE; + +begin + print_trace('build_and_process_lcrs()+'); + print_trace('cmd_type='||cmd_type); + print_trace('obj_owner='||obj_owner); + print_trace('obj_name='||obj_name); + + -- set up is_key_col array + -- initialize + is_key_col.extend(num_cols-1,1); + -- set elements that are key cols + for i in 1..num_cols loop + for j in key_cols.first .. key_cols.last loop + if (key_cols(j) = desc_table(i).col_name) then + is_key_col(i) := 1; + exit; + end if; + end loop; + end loop; + + -- execute the select statement + num_rows := dbms_sql.execute(sql_cursor); + + lcr := sys.lcr$_row_record.construct( + source_database_name=>source_dbname, + command_type=>cmd_type, + object_owner=>obj_owner, + object_name=>obj_name, + old_values=>NULL, + new_values=>NULL); + + -- loop until no more rows are returned + while dbms_sql.fetch_rows(sql_cursor) > 0 loop + print_trace('fetched row'); + + streams_mv_refresh.get_column_values(sql_cursor, num_cols, desc_table, + is_key_col, lcr, cmd_type, + first_time); + + first_time := FALSE; + + streams_qry_lcr.process_lcr(lcr); + + end loop; + + print_trace('build_and_process_lcrs()-'); +end; + + +-- +-- +-- +procedure execute_delta_query(qry_idx pls_integer, + tab_idx pls_integer, + dml_type varchar2, + is_commit_query boolean, + commit_scn number, + rowids streams_mv_refresh.rowid_list) +is + + sql_stmt varchar2(32000); + sql_cursor pls_integer; + num_cols pls_integer; + desc_table sys.dbms_sql.desc_tab; + query_owner varchar2(30); + query_name varchar2(30); + key_cols stmv_column_list; + +begin + print_trace('execute_delta_query()+'); + + query_owner := get_qrys()(qry_idx).query_owner; + query_name := get_qrys()(qry_idx).query_name; + key_cols := get_qrys()(qry_idx).key_cols; + + sql_stmt := create_query(dml_type, qry_idx, tab_idx, is_commit_query); + sql_cursor := dbms_sql.open_cursor; + dbms_sql.parse(sql_cursor, sql_stmt, sys.dbms_sql.v7); + dbms_sql.describe_columns(sql_cursor, num_cols, desc_table); + + -- loop through the columns and do the define columns + streams_mv_refresh.define_columns(sql_cursor, num_cols, desc_table); + + -- bind the scn variable once + dbms_sql.bind_variable(sql_cursor, streams_qry_refresh.scn_bind, commit_scn); + + if (is_commit_query) then + build_and_process_lcrs( + sql_cursor, + num_cols, + desc_table, + streams_qry_refresh_adm.source_dbname, + dml_type, + query_owner, + query_name, + key_cols); + else + for i in rowids.first .. rowids.last loop + dbms_sql.bind_variable(sql_cursor, streams_qry_refresh.rowid_bind, + rowids(i)); + build_and_process_lcrs( + sql_cursor, + num_cols, + desc_table, + streams_qry_refresh_adm.source_dbname, + dml_type, + query_owner, + query_name, + key_cols); + + end loop; + end if; + + dbms_sql.close_cursor(sql_cursor); + print_trace('execute_delta_query()-'); + +exception + when others then + if dbms_sql.is_open(sql_cursor) then + dbms_sql.close_cursor(sql_cursor); + end if; + raise; +end; + + +-- +-- DML handler +-- +procedure source_dml_handler(lcr_anydata sys.anydata) is + + lcr sys.lcr$_row_record; + t pls_integer; + qry_i pls_integer := null; -- iterator + tab_i pls_integer := null; -- iterator + commit_scn number := null; + dml_type varchar2(10); + dml_code pls_integer; + ridval sys.anydata; + +BEGIN + print_trace('source_dml_handler()+'); + + t := lcr_anydata.getObject(lcr); + commit_scn := lcr.get_commit_scn(); + ridval := lcr.get_extra_attribute('row_id'); + if (ridval is null) then + raise_application_error(-20000, + 'supplemental logging missing for rowid on ' || + lcr.get_object_owner || '.' || lcr.get_object_name); + end if; + + print_trace('commit_scn='||commit_scn); + + -- + -- streams refresh codepath + -- + while find_next_qry(lcr.get_object_owner, lcr.get_object_name, + qry_i, tab_i) loop + -- skip this query if commit scn of this LCR <= the query's instantiation + -- scn + print_trace('query inst_scn=' || get_qrys()(qry_i).inst_scn); + if (commit_scn > get_qrys()(qry_i).inst_scn) then + + dml_type := lcr.get_command_type; + print_trace('command_type='||dml_type); + + if (dml_type = 'INSERT') then + dml_code := streams_qry_refresh.insert_dml; + elsif (dml_type = 'UPDATE') then + dml_code := streams_qry_refresh.update_dml; + elsif (dml_type = 'DELETE') then + dml_code := streams_qry_refresh.delete_dml; + else + dml_code := 0; + end if; + + -- add table to collection for commit-time processing + streams_mv_refresh.add_to_table_coll(lcr.get_object_owner, + lcr.get_object_name, + dml_code, + ridval.AccessURowid, + streams_qry_refresh.txn_tabs); + end if; + end loop; + + print_trace('source_dml_handler()-'); +end; + + +-- +-- pre-commit handler +-- +procedure source_commit_hdlr(commit_scn number) is + + qry_i pls_integer := null; -- iterator + tab_i pls_integer := null; -- iterator + lcr sys.lcr$_row_record; + dml_type pls_integer; + tab_owner varchar2(30); + tab_name varchar2(30); + has_deletes boolean; + has_inserts boolean; + +begin + print_trace('source_commit_hdlr()+'); + + -- streams-based refresh + if (streams_qry_refresh.txn_tabs.count > 0) then + print_trace('commit_scn='||commit_scn); + + for i in streams_qry_refresh.txn_tabs.first.. + streams_qry_refresh.txn_tabs.last loop + + tab_owner := streams_qry_refresh.txn_tabs(i).table_owner; + tab_name := streams_qry_refresh.txn_tabs(i).table_name; + has_deletes := streams_qry_refresh.txn_tabs(i).delete_rowids.count > 0; + has_inserts := streams_qry_refresh.txn_tabs(i).insert_rowids.count > 0; + + print_trace('table=' || tab_owner || '.' || tab_name); + + while find_next_qry(tab_owner, tab_name, qry_i, tab_i) loop + + print_trace('qry=' || get_qrys()(qry_i).query_owner || '.' || + get_qrys()(qry_i).query_name); + + print_trace('qry inst_scn=' || get_qrys()(qry_i).inst_scn); + if (commit_scn > get_qrys()(qry_i).inst_scn) then + + print_trace('delete phase:'); + if (has_deletes) then + execute_delta_query(qry_i, tab_i, 'DELETE', FALSE, commit_scn, + streams_qry_refresh.txn_tabs(i).delete_rowids); + end if; + if (has_inserts) then + execute_delta_query(qry_i, tab_i, 'DELETE', FALSE, commit_scn, + streams_qry_refresh.txn_tabs(i).insert_rowids); + end if; + + print_trace('insert phase:'); + if (has_deletes) then + execute_delta_query(qry_i, tab_i, 'UPDATE', FALSE, commit_scn, + streams_qry_refresh.txn_tabs(i).delete_rowids); + end if; + if (has_inserts) then + execute_delta_query(qry_i, tab_i, 'UPDATE', FALSE, commit_scn, + streams_qry_refresh.txn_tabs(i).insert_rowids); + end if; + + if (get_qrys()(qry_i).base_tabs(tab_i).commit_query is not null) then + print_trace('delete phase: commit_query'); + execute_delta_query(qry_i, tab_i, 'DELETE', TRUE, commit_scn,NULL); + + print_trace('insert phase: commit_query'); + execute_delta_query(qry_i, tab_i, 'UPDATE', TRUE, commit_scn,NULL); + end if; + end if; + end loop; + + end loop; + + -- reset tab_owners, tab_names collections + streams_qry_refresh.txn_tabs.delete; + + end if; + + print_trace('source_commit_hdlr()-'); +end; + +end streams_qry_refresh; +/ + +create or replace package body streams_qry_lcr as + +-- +-- apply the LCR +-- +procedure process_lcr(lcr sys.lcr$_row_record) is + + -- new exception raised during apply to replace ora-1403 + row_does_not_exist exception; + pragma exception_init(row_does_not_exist, -26787); + +begin + streams_qry_refresh.print_trace('process_lcr()+'); + + -- this function may be customized to call a different procedure + begin + lcr.execute(true); + streams_qry_refresh.print_trace('applied LCR'); + + exception + when DUP_VAL_ON_INDEX then + streams_qry_refresh.print_trace('DUP_VAL_ON_INDEX, type='|| + lcr.get_command_type); + + when NO_DATA_FOUND or row_does_not_exist then + streams_qry_refresh.print_trace('NO_DATA_FOUND, type='|| + lcr.get_command_type); + streams_mv_lcr.do_an_insert(lcr); + when others then + raise; + end; + + streams_qry_refresh.print_trace('process_lcr()-'); +end; + +end streams_qry_lcr; +/ diff --git a/strmqry1.sql b/strmqry1.sql new file mode 100644 index 0000000..6cf8c3e --- /dev/null +++ b/strmqry1.sql @@ -0,0 +1,507 @@ +Rem +Rem $Header: rdbms/demo/strmqry1.sql /main/6 2009/06/30 03:03:52 snalla Exp $ +Rem +Rem strmqry1.sql +Rem +Rem Copyright (c) 2006, 2009, Oracle and/or its affiliates. +Rem All rights reserved. +Rem +Rem NAME +Rem strmqry1.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem snalla 06/23/09 - fix ORA-01940: cannot drop a user that is +Rem currently connected +Rem davzhang 09/27/06 - grant create view explicitly +Rem wesmith 06/23/06 - register_query: add parameter queue_name +Rem wesmith 06/12/06 - move include_extra_attribute() call +Rem liwong 05/15/06 - sync capture cleanup +Rem wesmith 01/19/06 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 10000 +SET SERVEROUTPUT ON + +COLUMN SRC_LONG_CNAME FORMAT A15 +COLUMN SCHEMA_NAME FORMAT A15 +COLUMN OBJECT_NAME FORMAT A15 +COLUMN STREAMS_TYPE HEADING 'STREAMS_TYPE' FORMAT A19 + +variable site1 varchar2(80); + +-- grant necessary privileges for streams admin +connect system/manager + +drop user stradm cascade; +grant dba to stradm identified by stradm; +grant execute on SYS.DBMS_SYSTEM to stradm; +begin + dbms_streams_auth.grant_admin_privilege( + grantee => 'stradm', + grant_privileges => true); +end; +/ + +-- create user for queries +drop user sqst cascade; +grant connect, resource to sqst identified by sqst; +grant create materialized view, create view to sqst; + +connect sqst/sqst + +-- create base tables and load +set echo off +@strmmv2s.sql +set echo on + +-- subquery (1 level) +create view orders_v (o_id, c_id, ol_num) as +select o.o_id, o.c_id, o.ol_num from sqst.orders o + where exists + (select c.c_id from sqst.customer c + where c.zip >= 19555 and o.c_id = c.c_id); + +create table orders_mv as +select o.o_id, o.c_id, o.ol_num from sqst.orders o + where exists + (select c.c_id from sqst.customer c + where c.zip >= 19555 and o.c_id = c.c_id); + +alter table orders_mv add primary key (o_id); + +-- another subquery (2-levels) +create view oline_v (ol_id, o_id, i_id) as + select ol.ol_id, ol.o_id, ol.i_id from sqst.order_line ol + where exists + (select o.o_id from sqst.orders o + where ol.o_id = o.o_id + and exists + (select c.c_id from sqst.customer c + where c.zip >= 19555 and o.c_id = c.c_id)); + +create table oline_mv as + select ol.ol_id, ol.o_id, ol.i_id from sqst.order_line ol + where exists + (select o.o_id from sqst.orders o + where ol.o_id = o.o_id + and exists + (select c.c_id from sqst.customer c + where c.zip >= 19555 and o.c_id = c.c_id)); + +alter table oline_mv add primary key (ol_id); + +-- join view +create view orders_v2 as +select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid +from sqst.orders o, sqst.customer c +where o.c_id = c.c_id(+) and c.zip(+) >= 19555; + +create table orders_mv2 as +select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid +from sqst.orders o, sqst.customer c +where o.c_id = c.c_id(+) and c.zip(+) >= 19555; + +-- aggregate +create view sales_region_v as +select s.region, sum(s.amt) sales +from sqst.sales s +group by s.region; + +create table sales_region_mv as +select s.region, sum(s.amt) sales +from sqst.sales s +group by s.region; + + +-- create supporting objects and packages for streams refresh metadata +connect stradm/stradm +set echo off +@strmmvp2 +@strmqp1 +set echo on + +-- +-- streams setup +-- +begin + dbms_streams_adm.set_up_queue + (queue_user => 'stradm', queue_name => 'QRY_MASTER_Q', + queue_table => 'QRY_MASTER_QT'); +end; +/ + +begin + streams_qry_refresh_adm.register_query( + query_owner=>'SQST', query_name=>'ORDERS_MV', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + queue_name=>'QRY_MASTER_Q', + base_tables=> +stq_table_list( + stq_table_t('SQST', 'ORDERS', + 'select o.o_id, o.c_id, o.ol_num from sqst.orders as of scn(:scn) o + where exists + (select c.c_id from sqst.customer as of scn(:scn) c + where c.zip >= 19555 and o.c_id = c.c_id) + and o.rowid = :rid', null), + stq_table_t('SQST', 'customer', + 'select o.o_id, o.c_id, o.ol_num from sqst.orders as of scn(:scn) o + where exists + (select c.c_id from sqst.customer as of scn(:scn) c + where c.zip >= 19555 + and o.c_id = c.c_id + and c.rowid = :rid)', null))); +end; +/ + +-- need set_key_columns for this query table since there is no pk +exec dbms_apply_adm.set_key_columns('SQST.ORDERS_MV2', 'o_rid, c_rid'); + +-- register queries for streams refresh +begin + streams_qry_refresh_adm.register_query( + query_owner=>'SQST', query_name=>'ORDERS_MV2', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + base_tables=> +stq_table_list( + stq_table_t('SQST', 'ORDERS', + 'select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid + from sqst.orders as of scn(:scn) o, sqst.customer as of scn(:scn) c + where o.c_id = c.c_id(+) and c.zip(+) >= 19555 + and o.rowid = :rid', null), + stq_table_t('SQST', 'customer', + 'select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid + from sqst.orders as of scn(:scn) o, sqst.customer as of scn(:scn) c + where o.c_id = c.c_id(+) and c.zip(+) >= 19555 + and c.rowid = :rid', + 'select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid + from sqst.orders as of scn(:scn) o, sqst.customer as of scn(:scn) c + where not exists (select 1 from sqst.customer as of scn(:scn) c + where o.c_id = c.c_id and c.zip >= 19555) + and o.c_id = c.c_id(+) and c.zip(+) >= 19555 + and c.rowid is null'))); +end; +/ + +begin + streams_qry_refresh_adm.register_query( + query_owner=>'SQST', query_name=>'OLINE_MV', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + base_tables=> +stq_table_list( + stq_table_t('SQST', 'ORDER_LINE', + 'select ol.ol_id, ol.o_id, ol.i_id from sqst.order_line as of scn(:scn) ol + where exists + (select o.o_id from sqst.orders as of scn(:scn) o + where ol.o_id = o.o_id + and exists + (select c.c_id from sqst.customer as of scn(:scn) c + where c.zip >= 19555 and o.c_id = c.c_id)) + and ol.rowid = :rid', null), + stq_table_t('SQST', 'orders', + 'select ol.ol_id, ol.o_id, ol.i_id from sqst.order_line as of scn(:scn) ol + where exists + (select o.o_id from sqst.orders as of scn(:scn) o + where ol.o_id = o.o_id + and exists + (select c.c_id from sqst.customer as of scn(:scn) c + where c.zip >= 19555 and o.c_id = c.c_id) + and o.rowid = :rid)', null), + stq_table_t('SQST', 'CUSTOMER', + 'select ol.ol_id, ol.o_id, ol.i_id from sqst.order_line as of scn(:scn) ol + where exists + (select o.o_id from sqst.orders as of scn(:scn) o + where ol.o_id = o.o_id + and exists + (select c.c_id from sqst.customer as of scn(:scn) c + where c.zip >= 19555 + and o.c_id = c.c_id + and c.rowid = :rid))', null))); +end; +/ + +-- need set_key_columns for this query table since there is no pk +exec dbms_apply_adm.set_key_columns('SQST.sales_region_mv', 'region'); + +begin + streams_qry_refresh_adm.register_query( + query_owner=>'SQST', query_name=>'sales_region_mv', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + base_tables=> +stq_table_list( + stq_table_t('SQST', 'sales', + 'select s.region, sum(s.amt) sales + from sqst.sales as of scn(:scn) s, sqst.sales as of scn(:scn) s2 + where s.region = s2.region and s2.rowid = :rid + group by s.region', + null))); +end; +/ + + +connect stradm/stradm +exec dbms_capture_adm.start_capture('CAPTURE'); + +exec dbms_apply_adm.set_parameter('APPLY_MV_MASTER','DISABLE_ON_ERROR','N'); + +-- assign precommit handler to apply process +begin + dbms_apply_adm.alter_apply( + apply_name => 'APPLY_MV_MASTER', + precommit_handler => 'streams_qry_refresh.source_commit_hdlr'); +end; +/ +exec dbms_apply_adm.start_apply('APPLY_MV_MASTER'); + +-- check streams metadata +select apply_name, status from dba_apply order by apply_name; +select capture_name, status from dba_capture order by 1,2; + +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +-- check query registration metadata +select query_owner, query_name from stq_reg order by query_owner, query_name; + +-- do some DMLs +connect sqst/sqst +set serveroutput on +update customer set zip = 0; +update order_line set i_id = 101 where ol_id < 800; +insert into sales values('West', 100); +insert into sales values('East', 50); +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('orders_v2','orders_mv2'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('sales_region_v','sales_region_mv'); +set timing off + +-- 0 rows expected +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; + +select region, sales from sales_region_mv order by region; + +update customer set zip = 19555 where c_id > 5; +update order_line set i_id = 61 where ol_id >= 800; +-- update primary key +update order_line set ol_id = 599 where ol_id = 522; +commit; +update sales set amt=null where region='West' and amt = 100; +insert into sales values('East', 150); +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('orders_v2','orders_mv2'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('sales_region_v','sales_region_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; +select region, sales from sales_region_mv order by region; + +update customer set zip = -19555 where zip > 19455; +commit; +update sales set amt=250 where region='East' and amt=150; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('orders_v2','orders_mv2'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('sales_region_v','sales_region_mv'); +set timing off + +--0 rows +select o_id, c_id, ol_num from orders_mv order by o_id; +--0 rows +select ol_id, o_id, i_id from oline_mv order by ol_id; + +select region, sales from sales_region_mv order by region; + +update customer set zip = 19556 where zip = -19555; +commit; +delete from sales; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('orders_v2','orders_mv2'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('sales_region_v','sales_region_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; +select region, sales from sales_region_mv order by region; + +delete from order_line where o_id = 71; +delete from orders where c_id = 6; +delete from customer where c_id = 9; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('orders_v2','orders_mv2'); +exec verify_tables('oline_v','oline_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; +select region, sales from sales_region_mv order by region; + +insert into customer (c_id, zip) values (101, 29555); +insert into orders (o_id, c_id, ol_num) values (1001, 101, 11); +insert into orders (o_id, c_id, ol_num) values (1002, 101, 11); +delete from orders where o_id < 22; +update orders set c_id = 7 where c_id = 5; +update order_line set o_id = 2 where o_id = 82; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('orders_v2','orders_mv2'); +exec verify_tables('oline_v','oline_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; +select region, sales from sales_region_mv order by region; + +-- Cleanup +connect stradm/stradm +exec dbms_apply_adm.stop_apply('APPLY_MV_MASTER'); + +-- unregister one query +begin + streams_qry_refresh_adm.unregister_query( + query_owner=>'SQST', query_name=>'OLINE_MV', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER'); +end; +/ + +-- check streams metadata +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +select query_owner, query_name from stq_reg order by query_owner, query_name; + +-- unregister more queries +begin + streams_qry_refresh_adm.unregister_query( + query_owner=>'SQST', query_name=>'ORDERS_MV', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER'); +end; +/ +begin + streams_qry_refresh_adm.unregister_query( + query_owner=>'SQST', query_name=>'ORDERS_MV2', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER'); +end; +/ +begin + streams_qry_refresh_adm.unregister_query( + query_owner=>'SQST', query_name=>'sales_region_mv', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER'); +end; +/ + +-- check streams metadata +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +select query_owner, query_name from stq_reg order by query_owner, query_name; + +-- remove streams configuration +begin + streams_qry_refresh_adm.remove_streams_qry_refresh( + 'CAPTURE', 'APPLY_MV_MASTER'); +end; +/ + +select 1 from dba_capture where capture_name = 'CAPTURE'; +select 1 from dba_apply where apply_name = 'APPLY_MV_MASTER'; + +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER'); + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +-- cleanup +connect system/manager +set serveroutput on +exec wait_session ('stradm'); +drop user stradm cascade ; +exec wait_session ('sqst'); +drop user sqst cascade ; diff --git a/strmqry1README.txt b/strmqry1README.txt new file mode 100644 index 0000000..60de75a --- /dev/null +++ b/strmqry1README.txt @@ -0,0 +1,273 @@ +/ +/ $Header: strmqry1README.txt 08-sep-2006.14:04:24 wesmith Exp $ +/ +/ strmqry1README.txt +/ +/ Copyright (c) 2006, Oracle. All Rights Reserved. +/ +/ NAME +/ strmqry1README.txt - +/ +/ DESCRIPTION +/ +/ +/ NOTES +/ +/ +/ MODIFIED (MM/DD/YY) +/ wesmith 06/23/06 - register_query: add parameter queue_name +/ wesmith 01/24/06 - Creation +/ + +register_query +-------------- +for streams-based refresh of arbitrary queries that may not be +fast-refreshable as an MV. + + +APIs +---- + +-- sets up a query for streams-driven refresh +procedure register_query(query_owner varchar2, + query_name varchar2, + base_tables stq_table_list, + capture_name varchar2 := 'CAPTURE_QRY_MASTER', + apply_name varchar2 := 'APPLY_QRY_MASTER', + queue_name varchar2 := NULL) + + + +Parameters +---------- +query_owner, query_name: query to register (actually the container table + for the query, which must exist) + +base_tables: collection of base tables referenced in the query, along with + the queries required to incrementally maintain the query with respect + to each base table. This parameter is of type stq_table_list which is + a nested table of the type stq_table_t: + +create or replace type stq_table_list is table of stq_table_t +/ + +create or replace type stq_table_t as object ( + table_owner varchar2(30), /* base table owner */ + table_name varchar2(30), /* base table name */ + refresh_query varchar2(4000), /* query used by the pre-commit handler */ + commit_query varchar2(4000) /* query used by the pre-commit handler */ +) +/ + +For each base table in the query, create a stq_table_t element. +refresh_query and commit_query will be used by the pre-commit handler to +incrementally maintain the query. + +capture_name: + name of the capture process to use. It is recommended to specify a capture + that does not already exist. + +apply_name: + name of the apply process to use. It is recommended to specify an apply + that does not already exist. + +queue_name: + name of the streams queue associated with the capture and apply process. + If NULL, then the queue_name is derived from the capture process + metadata, if it exists. + + +Notes: + +- base_tables collection element: +refresh_query and commit_query are both derived from the orignal query. +Both should have a flashback expression, 'as of scn(:scn)', for each table +in the original query. + +In addition, refresh_query should contain an additional rowid match +predicate 'and ..rowid = :rid', where +. is the current base table. In some cases, +the base table must be added again to the original query in order to +match the rowid (ex: query with aggregates). + +refresh_query is used to incrementally maintain the registered query +on a per-LCR basis. + +commit_query is used to incrementally maintain the registered query +on a per-transaction basis. A commit_query is required for certain +types of queries that cannot be properly maintained with just +a refresh_query. For example, a query with outer joins will need to +delete anti-join rows no longer in the query, and/or insert anti-join rows +that are new to the query. These queries require a 'rowid is null' +predicate instead of a rowid match predicate. + +- refresh algorithm +If a user transaction modifies a table that a registered query references, +then for each LCR for that table, the pre-commit handler constructs the +following queries: + +a. refresh_query (binds: scn=-1, rid=) + minus + refresh_query (binds: scn=, rid=) + +These are rows that no longer exist in the query. DELETE LCRs will be +constructed and executed on the query table. + +b. refresh_query (binds: scn=, rid=) + minus + refresh_query (binds: scn=-1, rid=) + +These are rows that are new to the query. UPDATE LCRs will be +constructed and executed (upsert performed) on the query table. + +If a commit_query was registered for a table that was modified in the +transaction, the pre-commit handler constructs the following +queries: + +a. commit_query (binds: scn=-1) + minus + commit_query (binds: scn=) + +These are rows that no longer exist in the query. DELETE LCRs will be +constructed and executed on the query table. + +b. commit_query (binds: scn=) + minus + commit_query (binds: scn=-1) + +These are rows that are new to the query. UPDATE LCRs will be +constructed and executed (upsert performed) on the query table. + + +Examples: + +1. subquery +create table customer( + c_id number primary key, + zip number, + c_name varchar(30)); + +create table orders( + o_id number primary key, + c_id number, + ol_num number default 0); + +-- query table +create table orders_mv as +select o.o_id, o.c_id, o.ol_num from sqst.orders o + where exists + (select c.c_id from sqst.customer c + where c.zip >= 19555 and o.c_id = c.c_id); + +alter table orders_mv add primary key (o_id); + +begin + streams_qry_refresh_adm.register_query( + query_owner=>'SQST', query_name=>'ORDERS_MV', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + base_tables=> +stq_table_list( + stq_table_t('SQST', 'ORDERS', + 'select o.o_id, o.c_id, o.ol_num from sqst.orders as of scn(:scn) o + where exists + (select c.c_id from sqst.customer as of scn(:scn) c + where c.zip >= 19555 and o.c_id = c.c_id) + and o.rowid = :rid', null), + stq_table_t('SQST', 'customer', + 'select o.o_id, o.c_id, o.ol_num from sqst.orders as of scn(:scn) o + where exists + (select c.c_id from sqst.customer as of scn(:scn) c + where c.zip >= 19555 + and o.c_id = c.c_id + and c.rowid = :rid)', null))); +end; +/ + +Notes: +- no commit_query needed for this query + + +2. join + +-- query table +create table orders_mv2 as +select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid +from sqst.orders o, sqst.customer c +where o.c_id = c.c_id(+) and c.zip(+) >= 19555; + +-- need set_key_columns for this query table since there is no pk +exec dbms_apply_adm.set_key_columns('SQST.ORDERS_MV2', 'o_rid, c_rid'); + +begin + streams_qry_refresh_adm.register_query( + query_owner=>'SQST', query_name=>'ORDERS_MV2', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + base_tables=> +stq_table_list( + stq_table_t('SQST', 'ORDERS', + 'select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid + from sqst.orders as of scn(:scn) o, sqst.customer as of scn(:scn) c + where o.c_id = c.c_id(+) and c.zip(+) >= 19555 + and o.rowid = :rid', + 'select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid + from sqst.orders as of scn(:scn) o, sqst.customer as of scn(:scn) c + where o.c_id = c.c_id(+) and c.zip(+) >= 19555 + and o.rowid is null'), + stq_table_t('SQST', 'customer', + 'select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid + from sqst.orders as of scn(:scn) o, sqst.customer as of scn(:scn) c + where o.c_id = c.c_id(+) and c.zip(+) >= 19555 + and c.rowid = :rid', + 'select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid + from sqst.orders as of scn(:scn) o, sqst.customer as of scn(:scn) c + where o.c_id = c.c_id(+) and c.zip(+) >= 19555 + and c.rowid is null'))); +end; +/ + +Notes: +- a commit query is required for this join query with outer joins to + deal with new/old antijoin rows in the query. For example, if there is + no customer row with matching c_id for an order row, there will be an + antijoin row for that o_id. If a row with matching c_id is now inserted + into customer, the antijoin row must be replaced with a join row. + Since c_rid is null for the antijoin row, it cannot be handled by + refresh_query (which uses rowid match predicate) and therefore must be + done by commit_query. + + +3. aggregate +create table sales (region varchar2(10), amt number); + +-- query table +create table sales_region_mv as +select s.region, sum(s.amt) sales +from sqst.sales s +group by s.region; + +-- need set_key_columns for this query table since there is no pk +exec dbms_apply_adm.set_key_columns('SQST.sales_region_mv', 'region'); + +begin + streams_qry_refresh_adm.register_query( + query_owner=>'SQST', query_name=>'sales_region_mv', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + base_tables=> +stq_table_list( + stq_table_t('SQST', 'sales', + 'select s.region, sum(s.amt) sales + from sqst.sales as of scn(:scn) s, sqst.sales as of scn(:scn) s2 + where s.region = s2.region and s2.rowid = :rid + group by s.region', + null))); +end; +/ + +Notes: +- another join of sales is required to add a rowid match predicate, + where the join clause is on the grouping columns for sales (region) +- no additional aggregates is required (count(*), count(sales)) as would + be if an MV is created using the query. +- no commit_query is required for this query + + diff --git a/summit2.sql b/summit2.sql new file mode 100644 index 0000000..0c400de --- /dev/null +++ b/summit2.sql @@ -0,0 +1,1286 @@ +rem +rem $Header: summit2.sql 27-jun-2000.12:30:22 slari Exp $ +rem +rem Copyright (c) 1991, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem summit2.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem FUNCTION +rem Create and populate tables and sequences to support the Summit +rem Sporting Goods business scenario. These objects and data are used +rem in several Oracle classes and demonstration files. +rem +rem MODIFIED (MM/DD/YY) +rem slari 06/27/00 - b1138912: remove duplicate contents +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem GDURHAM Mar 15, 1993 -- Created + +set feedback off +prompt Creating and populating tables and sequences. Please wait. + +rem Create sequences. +rem Starting values for sequences begin at the existing maxima for +rem existing primary key values, plus increments. + +CREATE SEQUENCE s_customer_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 216 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_dept_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 51 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_emp_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 26 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_image_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 1981 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_longtext_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 1369 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_ord_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 113 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_product_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 50537 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_region_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 6 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_warehouse_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 10502 + NOCACHE + NOORDER + NOCYCLE; + + +rem Create and populate tables. + +CREATE TABLE s_customer +(id NUMBER(7) + CONSTRAINT s_customer_id_nn NOT NULL, + name VARCHAR2(50) + CONSTRAINT s_customer_name_nn NOT NULL, + phone VARCHAR2(25), + address VARCHAR2(400), + city VARCHAR2(30), + state VARCHAR2(20), + country VARCHAR2(30), + zip_code VARCHAR2(75), + credit_rating VARCHAR2(9), + sales_rep_id NUMBER(7), + region_id NUMBER(7), + comments VARCHAR2(255), + CONSTRAINT s_customer_id_pk PRIMARY KEY (id), + CONSTRAINT s_customer_credit_rating_ck + CHECK (credit_rating IN ('EXCELLENT', 'GOOD', 'POOR'))); + +INSERT INTO s_customer VALUES ( + 201, 'Unisports', '55-2066101', + '72 Via Bahia', 'Sao Paolo', NULL, 'Brazil', NULL, + 'EXCELLENT', 12, 2, NULL); +INSERT INTO s_customer VALUES ( + 202, 'OJ Atheletics', '81-20101', + '6741 Takashi Blvd.', 'Osaka', NULL, 'Japan', NULL, + 'POOR', 14, 4, NULL); +INSERT INTO s_customer VALUES ( + 203, 'Delhi Sports', '91-10351', + '11368 Chanakya', 'New Delhi', NULL, 'India', NULL, + 'GOOD', 14, 4, NULL); +INSERT INTO s_customer VALUES ( + 204, 'Womansport', '1-206-104-0103', + '281 King Street', 'Seattle', 'Washington', 'USA', NULL, + 'EXCELLENT', 11, 1, NULL); +INSERT INTO s_customer VALUES ( + 205, 'Kam''s Sporting Goods', '852-3692888', + '15 Henessey Road', 'Hong Kong', NULL, NULL, NULL, + 'EXCELLENT', 15, 4, NULL); +INSERT INTO s_customer VALUES ( + 206, 'Sportique', '33-2257201', + '172 Rue de Rivoli', 'Cannes', NULL, 'France', NULL, + 'EXCELLENT', 15, 5, NULL); +INSERT INTO s_customer VALUES ( + 207, 'Sweet Rock Sports', '234-6036201', + '6 Saint Antoine', 'Lagos', NULL, 'Nigeria', NULL, + 'GOOD', NULL, 3, NULL); +INSERT INTO s_customer VALUES ( + 208, 'Muench Sports', '49-527454', + '435 Gruenestrasse', 'Stuttgart', NULL, 'Germany', NULL, + 'GOOD', 15, 5, NULL); +INSERT INTO s_customer VALUES ( + 209, 'Beisbol Si!', '809-352689', + '792 Playa Del Mar', 'San Pedro de Macon''s', NULL, 'Dominican Republic', + NULL, 'EXCELLENT', 11, 1, NULL); +INSERT INTO s_customer VALUES ( + 210, 'Futbol Sonora', '52-404562', + '3 Via Saguaro', 'Nogales', NULL, 'Mexico', NULL, + 'EXCELLENT', 12, 2, NULL); +INSERT INTO s_customer VALUES ( + 211, 'Kuhn''s Sports', '42-111292', + '7 Modrany', 'Prague', NULL, 'Czechoslovakia', NULL, + 'EXCELLENT', 15, 5, NULL); +INSERT INTO s_customer VALUES ( + 212, 'Hamada Sport', '20-1209211', + '57A Corniche', 'Alexandria', NULL, 'Egypt', NULL, + 'EXCELLENT', 13, 3, NULL); +INSERT INTO s_customer VALUES ( + 213, 'Big John''s Sports Emporium', '1-415-555-6281', + '4783 18th Street', 'San Francisco', 'CA', 'USA', NULL, + 'EXCELLENT', 11, 1, NULL); +INSERT INTO s_customer VALUES ( + 214, 'Ojibway Retail', '1-716-555-7171', + '415 Main Street', 'Buffalo', 'NY', 'USA', NULL, + 'POOR', 11, 1, NULL); +INSERT INTO s_customer VALUES ( + 215, 'Sporta Russia', '7-3892456', + '6000 Yekatamina', 'Saint Petersburg', NULL, 'Russia', NULL, + 'POOR', 15, 5, NULL); +COMMIT; + + +CREATE TABLE s_dept +(id NUMBER(7) + CONSTRAINT s_dept_id_nn NOT NULL, + name VARCHAR2(25) + CONSTRAINT s_dept_name_nn NOT NULL, + region_id NUMBER(7), + CONSTRAINT s_dept_id_pk PRIMARY KEY (id), + CONSTRAINT s_dept_name_region_id_uk UNIQUE (name, region_id)); + +INSERT INTO s_dept VALUES ( + 10, 'Finance', 1); +INSERT INTO s_dept VALUES ( + 31, 'Sales', 1); +INSERT INTO s_dept VALUES ( + 32, 'Sales', 2); +INSERT INTO s_dept VALUES ( + 33, 'Sales', 3); +INSERT INTO s_dept VALUES ( + 34, 'Sales', 4); +INSERT INTO s_dept VALUES ( + 35, 'Sales', 5); +INSERT INTO s_dept VALUES ( + 41, 'Operations', 1); +INSERT INTO s_dept VALUES ( + 42, 'Operations', 2); +INSERT INTO s_dept VALUES ( + 43, 'Operations', 3); +INSERT INTO s_dept VALUES ( + 44, 'Operations', 4); +INSERT INTO s_dept VALUES ( + 45, 'Operations', 5); +INSERT INTO s_dept VALUES ( + 50, 'Administration', 1); +COMMIT; + + +CREATE TABLE s_emp +(id NUMBER(7) + CONSTRAINT s_emp_id_nn NOT NULL, + last_name VARCHAR2(25) + CONSTRAINT s_emp_last_name_nn NOT NULL, + first_name VARCHAR2(25), + userid VARCHAR2(8), + start_date DATE, + comments VARCHAR2(255), + manager_id NUMBER(7), + title VARCHAR2(25), + dept_id NUMBER(7), + salary NUMBER(11, 2), + commission_pct NUMBER(4, 2), + CONSTRAINT s_emp_id_pk PRIMARY KEY (id), + CONSTRAINT s_emp_userid_uk UNIQUE (userid), + CONSTRAINT s_emp_commission_pct_ck + CHECK (commission_pct IN (10, 12.5, 15, 17.5, 20))); + +INSERT INTO s_emp VALUES ( + 1, 'Velasquez', 'Carmen', 'cvelasqu', + to_date('03-MAR-90 8:30', 'dd-mon-yy hh24:mi'), NULL, NULL, 'President', + 50, 2500, NULL); +INSERT INTO s_emp VALUES ( + 2, 'Ngao', 'LaDoris', 'lngao', + '08-MAR-90', NULL, 1, 'VP, Operations', + 41, 1450, NULL); +INSERT INTO s_emp VALUES ( + 3, 'Nagayama', 'Midori', 'mnagayam', + '17-JUN-91', NULL, 1, 'VP, Sales', + 31, 1400, NULL); +INSERT INTO s_emp VALUES ( + 4, 'Quick-To-See', 'Mark', 'mquickto', + '07-APR-90', NULL, 1, 'VP, Finance', + 10, 1450, NULL); +INSERT INTO s_emp VALUES ( + 5, 'Ropeburn', 'Audry', 'aropebur', + '04-MAR-90', NULL, 1, 'VP, Administration', + 50, 1550, NULL); +INSERT INTO s_emp VALUES ( + 6, 'Urguhart', 'Molly', 'murguhar', + '18-JAN-91', NULL, 2, 'Warehouse Manager', + 41, 1200, NULL); +INSERT INTO s_emp VALUES ( + 7, 'Menchu', 'Roberta', 'rmenchu', + '14-MAY-90', NULL, 2, 'Warehouse Manager', + 42, 1250, NULL); +INSERT INTO s_emp VALUES ( + 8, 'Biri', 'Ben', 'bbiri', + '07-APR-90', NULL, 2, 'Warehouse Manager', + 43, 1100, NULL); +INSERT INTO s_emp VALUES ( + 9, 'Catchpole', 'Antoinette', 'acatchpo', + '09-FEB-92', NULL, 2, 'Warehouse Manager', + 44, 1300, NULL); +INSERT INTO s_emp VALUES ( + 10, 'Havel', 'Marta', 'mhavel', + '27-FEB-91', NULL, 2, 'Warehouse Manager', + 45, 1307, NULL); +INSERT INTO s_emp VALUES ( + 11, 'Magee', 'Colin', 'cmagee', + '14-MAY-90', NULL, 3, 'Sales Representative', + 31, 1400, 10); +INSERT INTO s_emp VALUES ( + 12, 'Giljum', 'Henry', 'hgiljum', + '18-JAN-92', NULL, 3, 'Sales Representative', + 32, 1490, 12.5); +INSERT INTO s_emp VALUES ( + 13, 'Sedeghi', 'Yasmin', 'ysedeghi', + '18-FEB-91', NULL, 3, 'Sales Representative', + 33, 1515, 10); +INSERT INTO s_emp VALUES ( + 14, 'Nguyen', 'Mai', 'mnguyen', + '22-JAN-92', NULL, 3, 'Sales Representative', + 34, 1525, 15); +INSERT INTO s_emp VALUES ( + 15, 'Dumas', 'Andre', 'adumas', + '09-OCT-91', NULL, 3, 'Sales Representative', + 35, 1450, 17.5); +INSERT INTO s_emp VALUES ( + 16, 'Maduro', 'Elena', 'emaduro', + '07-FEB-92', NULL, 6, 'Stock Clerk', + 41, 1400, NULL); +INSERT INTO s_emp VALUES ( + 17, 'Smith', 'George', 'gsmith', + '08-MAR-90', NULL, 6, 'Stock Clerk', + 41, 940, NULL); +INSERT INTO s_emp VALUES ( + 18, 'Nozaki', 'Akira', 'anozaki', + '09-FEB-91', NULL, 7, 'Stock Clerk', + 42, 1200, NULL); +INSERT INTO s_emp VALUES ( + 19, 'Patel', 'Vikram', 'vpatel', + '06-AUG-91', NULL, 7, 'Stock Clerk', + 42, 795, NULL); +INSERT INTO s_emp VALUES ( + 20, 'Newman', 'Chad', 'cnewman', + '21-JUL-91', NULL, 8, 'Stock Clerk', + 43, 750, NULL); +INSERT INTO s_emp VALUES ( + 21, 'Markarian', 'Alexander', 'amarkari', + '26-MAY-91', NULL, 8, 'Stock Clerk', + 43, 850, NULL); +INSERT INTO s_emp VALUES ( + 22, 'Chang', 'Eddie', 'echang', + '30-NOV-90', NULL, 9, 'Stock Clerk', + 44, 800, NULL); +INSERT INTO s_emp VALUES ( + 23, 'Patel', 'Radha', 'rpatel', + '17-OCT-90', NULL, 9, 'Stock Clerk', + 34, 795, NULL); +INSERT INTO s_emp VALUES ( + 24, 'Dancs', 'Bela', 'bdancs', + '17-MAR-91', NULL, 10, 'Stock Clerk', + 45, 860, NULL); +INSERT INTO s_emp VALUES ( + 25, 'Schwartz', 'Sylvie', 'sschwart', + '09-MAY-91', NULL, 10, 'Stock Clerk', + 45, 1100, NULL); +COMMIT; + + +CREATE TABLE s_image +(id NUMBER(7) + CONSTRAINT s_image_id_nn NOT NULL, + format VARCHAR2(25), + use_filename VARCHAR2(1), + filename VARCHAR2(255), + image LONG RAW, + CONSTRAINT s_image_id_pk + PRIMARY KEY (id), + CONSTRAINT s_image_format_ck + CHECK (format in ('JFIFF', 'JTIFF')), + CONSTRAINT s_image_use_filename_ck + CHECK (use_filename in ('Y', 'N'))); + +INSERT INTO s_image VALUES ( + 1001, 'JTIFF', 'Y', 'bunboot.tif', NULL); +INSERT INTO s_image VALUES ( + 1002, 'JTIFF', 'Y', 'aceboot.tif', NULL); +INSERT INTO s_image VALUES ( + 1003, 'JTIFF', 'Y', 'proboot.tif', NULL); +INSERT INTO s_image VALUES ( + 1011, 'JTIFF', 'Y', 'bunpole.tif', NULL); +INSERT INTO s_image VALUES ( + 1012, 'JTIFF', 'Y', 'acepole.tif', NULL); +INSERT INTO s_image VALUES ( + 1013, 'JTIFF', 'Y', 'propole.tif', NULL); +INSERT INTO s_image VALUES ( + 1291, 'JTIFF', 'Y', 'gpbike.tif', NULL); +INSERT INTO s_image VALUES ( + 1296, 'JTIFF', 'Y', 'himbike.tif', NULL); +INSERT INTO s_image VALUES ( + 1829, 'JTIFF', 'Y', 'safthelm.tif', NULL); +INSERT INTO s_image VALUES ( + 1381, 'JTIFF', 'Y', 'probar.tif', NULL); +INSERT INTO s_image VALUES ( + 1382, 'JTIFF', 'Y', 'curlbar.tif', NULL); +INSERT INTO s_image VALUES ( + 1119, 'JTIFF', 'Y', 'baseball.tif', NULL); +INSERT INTO s_image VALUES ( + 1223, 'JTIFF', 'Y', 'chaphelm.tif', NULL); +INSERT INTO s_image VALUES ( + 1367, 'JTIFF', 'Y', 'grglove.tif', NULL); +INSERT INTO s_image VALUES ( + 1368, 'JTIFF', 'Y', 'alglove.tif', NULL); +INSERT INTO s_image VALUES ( + 1369, 'JTIFF', 'Y', 'stglove.tif', NULL); +INSERT INTO s_image VALUES ( + 1480, 'JTIFF', 'Y', 'cabbat.tif', NULL); +INSERT INTO s_image VALUES ( + 1482, 'JTIFF', 'Y', 'pucbat.tif', NULL); +INSERT INTO s_image VALUES ( + 1486, 'JTIFF', 'Y', 'winbat.tif', NULL); +COMMIT; + + +CREATE TABLE s_inventory +(product_id NUMBER(7) + CONSTRAINT s_inventory_product_id_nn NOT NULL, + warehouse_id NUMBER(7) + CONSTRAINT s_inventory_warehouse_id_nn NOT NULL, + amount_in_stock NUMBER(9), + reorder_point NUMBER(9), + max_in_stock NUMBER(9), + out_of_stock_explanation VARCHAR2(255), + restock_date DATE, + CONSTRAINT s_inventory_prodid_warid_pk + PRIMARY KEY (product_id, warehouse_id)); + +INSERT INTO s_inventory VALUES ( + 10011, 101, 650, 625, 1100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10012, 101, 600, 560, 1000, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10013, 101, 400, 400, 700, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10021, 101, 500, 425, 740, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10022, 101, 300, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10023, 101, 400, 300, 525, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20106, 101, 993, 625, 1000, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20108, 101, 700, 700, 1225, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20201, 101, 802, 800, 1400, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20510, 101, 1389, 850, 1400, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20512, 101, 850, 850, 1450, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30321, 101, 2000, 1500, 2500, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30326, 101, 2100, 2000, 3500, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30421, 101, 1822, 1800, 3150, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30426, 101, 2250, 2000, 3500, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30433, 101, 650, 600, 1050, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32779, 101, 2120, 1250, 2200, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32861, 101, 505, 500, 875, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40421, 101, 578, 350, 600, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40422, 101, 0, 350, 600, 'Phenomenal sales...', '08-FEB-93'); +INSERT INTO s_inventory VALUES ( + 41010, 101, 250, 250, 437, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41020, 101, 471, 450, 750, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41050, 101, 501, 450, 750, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41080, 101, 400, 400, 700, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41100, 101, 350, 350, 600, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50169, 101, 2530, 1500, 2600, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50273, 101, 233, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50417, 101, 518, 500, 875, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50418, 101, 244, 100, 275, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50419, 101, 230, 120, 310, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50530, 101, 669, 400, 700, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50532, 101, 0, 100, 175, 'Wait for Spring.', '12-APR-93'); +INSERT INTO s_inventory VALUES ( + 50536, 101, 173, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20106, 201, 220, 150, 260, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20108, 201, 166, 150, 260, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20201, 201, 320, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20510, 201, 175, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20512, 201, 162, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30321, 201, 96, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30326, 201, 147, 120, 210, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30421, 201, 102, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30426, 201, 200, 120, 210, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30433, 201, 130, 130, 230, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32779, 201, 180, 150, 260, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32861, 201, 132, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50169, 201, 225, 220, 385, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50273, 201, 75, 60, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50417, 201, 82, 60, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50418, 201, 98, 60, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50419, 201, 77, 60, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50530, 201, 62, 60, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50532, 201, 67, 60, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50536, 201, 97, 60, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20510, 301, 69, 40, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20512, 301, 28, 20, 50, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30321, 301, 85, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30421, 301, 102, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30433, 301, 35, 20, 35, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32779, 301, 102, 95, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32861, 301, 57, 50, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40421, 301, 70, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40422, 301, 65, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41010, 301, 59, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41020, 301, 61, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41050, 301, 49, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41080, 301, 50, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41100, 301, 42, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20510, 401, 88, 50, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20512, 401, 75, 75, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30321, 401, 102, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30326, 401, 113, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30421, 401, 85, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30426, 401, 135, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30433, 401, 0, 100, 175, 'A defective shipment was sent to Hong Kong ' || + 'and needed to be returned. The soonest ACME can turn this around is ' || + 'early February.', '07-SEP-92'); +INSERT INTO s_inventory VALUES ( + 32779, 401, 135, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32861, 401, 250, 150, 250, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40421, 401, 47, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40422, 401, 50, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41010, 401, 80, 70, 220, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41020, 401, 91, 70, 220, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41050, 401, 169, 70, 220, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41080, 401, 100, 70, 220, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41100, 401, 75, 70, 220, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50169, 401, 240, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50273, 401, 224, 150, 280, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50417, 401, 130, 120, 210, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50418, 401, 156, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50419, 401, 151, 150, 280, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50530, 401, 119, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50532, 401, 233, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50536, 401, 138, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10012, 10501, 300, 300, 525, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10013, 10501, 314, 300, 525, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10022, 10501, 502, 300, 525, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10023, 10501, 500, 300, 525, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20106, 10501, 150, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20108, 10501, 222, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20201, 10501, 275, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20510, 10501, 57, 50, 87, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20512, 10501, 62, 50, 87, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30321, 10501, 194, 150, 275, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30326, 10501, 277, 250, 440, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30421, 10501, 190, 150, 275, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30426, 10501, 423, 250, 450, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30433, 10501, 273, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32779, 10501, 280, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32861, 10501, 288, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40421, 10501, 97, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40422, 10501, 90, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41010, 10501, 151, 140, 245, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41020, 10501, 224, 140, 245, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41050, 10501, 157, 140, 245, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41080, 10501, 159, 140, 245, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41100, 10501, 141, 140, 245, NULL, NULL); +COMMIT; + + +CREATE TABLE s_item +(ord_id NUMBER(7) + CONSTRAINT s_item_ord_id_nn NOT NULL, + item_id NUMBER(7) + CONSTRAINT s_item_item_id_nn NOT NULL, + product_id NUMBER(7) + CONSTRAINT s_item_product_id_nn NOT NULL, + price NUMBER(11, 2), + quantity NUMBER(9), + quantity_shipped NUMBER(9), + CONSTRAINT s_item_ordid_itemid_pk PRIMARY KEY (ord_id, item_id), + CONSTRAINT s_item_ordid_prodid_uk UNIQUE (ord_id, product_id)); + +INSERT INTO s_item VALUES ( + 100, 1, 10011, 135, 500, 500); +INSERT INTO s_item VALUES ( + 100, 2, 10013, 380, 400, 400); +INSERT INTO s_item VALUES ( + 100, 3, 10021, 14, 500, 500); +INSERT INTO s_item VALUES ( + 100, 5, 30326, 582, 600, 600); +INSERT INTO s_item VALUES ( + 100, 7, 41010, 8, 250, 250); +INSERT INTO s_item VALUES ( + 100, 6, 30433, 20, 450, 450); +INSERT INTO s_item VALUES ( + 100, 4, 10023, 36, 400, 400); +INSERT INTO s_item VALUES ( + 101, 1, 30421, 16, 15, 15); +INSERT INTO s_item VALUES ( + 101, 3, 41010, 8, 20, 20); +INSERT INTO s_item VALUES ( + 101, 5, 50169, 4.29, 40, 40); +INSERT INTO s_item VALUES ( + 101, 6, 50417, 80, 27, 27); +INSERT INTO s_item VALUES ( + 101, 7, 50530, 45, 50, 50); +INSERT INTO s_item VALUES ( + 101, 4, 41100, 45, 35, 35); +INSERT INTO s_item VALUES ( + 101, 2, 40422, 50, 30, 30); +INSERT INTO s_item VALUES ( + 102, 1, 20108, 28, 100, 100); +INSERT INTO s_item VALUES ( + 102, 2, 20201, 123, 45, 45); +INSERT INTO s_item VALUES ( + 103, 1, 30433, 20, 15, 15); +INSERT INTO s_item VALUES ( + 103, 2, 32779, 7, 11, 11); +INSERT INTO s_item VALUES ( + 104, 1, 20510, 9, 7, 7); +INSERT INTO s_item VALUES ( + 104, 4, 30421, 16, 35, 35); +INSERT INTO s_item VALUES ( + 104, 2, 20512, 8, 12, 12); +INSERT INTO s_item VALUES ( + 104, 3, 30321, 1669, 19, 19); +INSERT INTO s_item VALUES ( + 105, 1, 50273, 22.89, 16, 16); +INSERT INTO s_item VALUES ( + 105, 3, 50532, 47, 28, 28); +INSERT INTO s_item VALUES ( + 105, 2, 50419, 80, 13, 13); +INSERT INTO s_item VALUES ( + 106, 1, 20108, 28, 46, 46); +INSERT INTO s_item VALUES ( + 106, 4, 50273, 22.89, 75, 75); +INSERT INTO s_item VALUES ( + 106, 5, 50418, 75, 98, 98); +INSERT INTO s_item VALUES ( + 106, 6, 50419, 80, 27, 27); +INSERT INTO s_item VALUES ( + 106, 2, 20201, 123, 21, 21); +INSERT INTO s_item VALUES ( + 106, 3, 50169, 4.29, 125, 125); +INSERT INTO s_item VALUES ( + 107, 1, 20106, 11, 50, 50); +INSERT INTO s_item VALUES ( + 107, 3, 20201, 115, 130, 130); +INSERT INTO s_item VALUES ( + 107, 5, 30421, 16, 55, 55); +INSERT INTO s_item VALUES ( + 107, 4, 30321, 1669, 75, 75); +INSERT INTO s_item VALUES ( + 107, 2, 20108, 28, 22, 22); +INSERT INTO s_item VALUES ( + 108, 1, 20510, 9, 9, 9); +INSERT INTO s_item VALUES ( + 108, 6, 41080, 35, 50, 50); +INSERT INTO s_item VALUES ( + 108, 7, 41100, 45, 42, 42); +INSERT INTO s_item VALUES ( + 108, 5, 32861, 60, 57, 57); +INSERT INTO s_item VALUES ( + 108, 2, 20512, 8, 18, 18); +INSERT INTO s_item VALUES ( + 108, 4, 32779, 7, 60, 60); +INSERT INTO s_item VALUES ( + 108, 3, 30321, 1669, 85, 85); +INSERT INTO s_item VALUES ( + 109, 1, 10011, 140, 150, 150); +INSERT INTO s_item VALUES ( + 109, 5, 30426, 18.25, 500, 500); +INSERT INTO s_item VALUES ( + 109, 7, 50418, 75, 43, 43); +INSERT INTO s_item VALUES ( + 109, 6, 32861, 60, 50, 50); +INSERT INTO s_item VALUES ( + 109, 4, 30326, 582, 1500, 1500); +INSERT INTO s_item VALUES ( + 109, 2, 10012, 175, 600, 600); +INSERT INTO s_item VALUES ( + 109, 3, 10022, 21.95, 300, 300); +INSERT INTO s_item VALUES ( + 110, 1, 50273, 22.89, 17, 17); +INSERT INTO s_item VALUES ( + 110, 2, 50536, 50, 23, 23); +INSERT INTO s_item VALUES ( + 111, 1, 40421, 65, 27, 27); +INSERT INTO s_item VALUES ( + 111, 2, 41080, 35, 29, 29); +INSERT INTO s_item VALUES ( + 97, 1, 20106, 9, 1000, 1000); +INSERT INTO s_item VALUES ( + 97, 2, 30321, 1500, 50, 50); +INSERT INTO s_item VALUES ( + 98, 1, 40421, 85, 7, 7); +INSERT INTO s_item VALUES ( + 99, 1, 20510, 9, 18, 18); +INSERT INTO s_item VALUES ( + 99, 2, 20512, 8, 25, 25); +INSERT INTO s_item VALUES ( + 99, 3, 50417, 80, 53, 53); +INSERT INTO s_item VALUES ( + 99, 4, 50530, 45, 69, 69); +INSERT INTO s_item VALUES ( + 112, 1, 20106, 11, 50, 50); +COMMIT; + + +CREATE TABLE s_longtext +(id NUMBER(7) + CONSTRAINT s_longtext_id_nn NOT NULL, + use_filename VARCHAR2(1), + filename VARCHAR2(255), + text VARCHAR2(2000), + CONSTRAINT s_longtext_id_pk PRIMARY KEY (id), + CONSTRAINT s_longtext_use_filename_ck + CHECK (use_filename in ('Y', 'N'))); + +INSERT INTO s_longtext VALUES ( + 1017, 'N', NULL, + 'Protective knee pads for any number of physical activities including ' || + 'bicycling and skating (4-wheel, in-line, and ice). Also provide ' || + 'support for stress activities such as weight-lifting. Velcro belts ' || + 'allow easy adjustment for any size and snugness of fit. Hardened ' || + 'plastic shell comes in a variety of colors, so you can buy a pair to ' || + 'match every outfit. Can also be worn at the beach to cover ' || + 'particularly ugly knees.'); +INSERT INTO s_longtext VALUES ( + 1019, 'N', NULL, + 'Protective elbow pads for any number of physical activities including ' || + 'bicycling and skating (4-wheel, in-line, and ice). Also provide ' || + 'support for stress activities such as weight-lifting. Velcro belts ' || + 'allow easy adjustment for any size and snugness of fit. Hardened ' || + 'plastic shell comes in a variety of colors, so you can buy a pair to ' || + 'match every outfit.'); +INSERT INTO s_longtext VALUES ( + 1037, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 1039, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 1043, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 1286, 'N', NULL, + 'Don''t slack off--try the Slaker Water Bottle. With its 1 quart ' || + 'capacity, this is the only water bottle you''ll need. It''s ' || + 'lightweight, durable, and guaranteed for life to be leak proof. It ' || + 'comes with a convenient velcro strap so it ' || + 'can be conveniently attached to your bike or other sports equipment.'); +INSERT INTO s_longtext VALUES ( + 1368, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 517, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 518, 'N', NULL, + 'Perfect for the beginner. Rear entry (easy to put on with only one ' || + 'buckle), weight control adjustment on side of boot for easy access, ' || + 'comes in a wide variety of colors to match every outfit.'); +INSERT INTO s_longtext VALUES ( + 519, 'N', NULL, + 'If you have mastered the basic techniques you are ready for the Ace Ski ' || + 'Boot. This intermediate boot comes as a package with self adjustable ' || + 'bindings that will adapt to your skill and speed. The boot is designed ' || + 'for extra grip on slopes and jumps.'); +INSERT INTO s_longtext VALUES ( + 520, 'N', NULL, + 'The Pro ski boot is an advanced boot that combines high tech and ' || + 'comfort. It''s made of fibre that will mould to your foot with body ' || + 'heat. If you''re after perfection, don''t look any further: this is it!'); +INSERT INTO s_longtext VALUES ( + 527, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 528, 'N', NULL, + 'Lightweight aluminum pole, comes in a variety of sizes and neon ' || + 'colors. Comfortable adjustable straps.'); +INSERT INTO s_longtext VALUES ( + 529, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 530, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 557, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 587, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 607, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 613, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 615, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 676, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 708, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 780, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 828, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 833, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 924, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 925, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 926, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 927, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 928, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 929, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 933, 'N', NULL, + 'The widest, strongest, and knobbiest tires for mountain bike ' || + 'enthusiasts. Guaranteed to withstand pummelling that will reduce most ' || + 'bicycles (except for the Himalayan) to scrap iron. These tires can ' || + 'carry you to places where nobody would want to bicycle. Sizes to ' || + 'fit all makes of mountain bike including wide and super wide rims. ' || + 'Steel-banded radial models are also available by direct factory order.'); +INSERT INTO s_longtext VALUES ( + 940, NULL, NULL, NULL); +COMMIT; + + +CREATE TABLE s_ord +(id NUMBER(7) + CONSTRAINT s_ord_id_nn NOT NULL, + customer_id NUMBER(7) + CONSTRAINT s_ord_customer_id_nn NOT NULL, + date_ordered DATE, + date_shipped DATE, + sales_rep_id NUMBER(7), + total NUMBER(11, 2), + payment_type VARCHAR2(6), + order_filled VARCHAR2(1), + CONSTRAINT s_ord_id_pk PRIMARY KEY (id), + CONSTRAINT s_ord_payment_type_ck + CHECK (payment_type in ('CASH', 'CREDIT')), + CONSTRAINT s_ord_order_filled_ck + CHECK (order_filled in ('Y', 'N'))); + +INSERT INTO s_ord VALUES ( + 100, 204, '31-AUG-92', '10-SEP-92', + 11, 601100, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 101, 205, '31-AUG-92', '15-SEP-92', + 14, 8056.6, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 102, 206, '01-SEP-92', '08-SEP-92', + 15, 8335, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 103, 208, '02-SEP-92', '22-SEP-92', + 15, 377, 'CASH', 'Y'); +INSERT INTO s_ord VALUES ( + 104, 208, '03-SEP-92', '23-SEP-92', + 15, 32430, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 105, 209, '04-SEP-92', '18-SEP-92', + 11, 2722.24, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 106, 210, '07-SEP-92', '15-SEP-92', + 12, 15634, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 107, 211, '07-SEP-92', '21-SEP-92', + 15, 142171, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 108, 212, '07-SEP-92', '10-SEP-92', + 13, 149570, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 109, 213, '08-SEP-92', '28-SEP-92', + 11, 1020935, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 110, 214, '09-SEP-92', '21-SEP-92', + 11, 1539.13, 'CASH', 'Y'); +INSERT INTO s_ord VALUES ( + 111, 204, '09-SEP-92', '21-SEP-92', + 11, 2770, 'CASH', 'Y'); +INSERT INTO s_ord VALUES ( + 97, 201, '28-AUG-92', '17-SEP-92', + 12, 84000, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 98, 202, '31-AUG-92', '10-SEP-92', + 14, 595, 'CASH', 'Y'); +INSERT INTO s_ord VALUES ( + 99, 203, '31-AUG-92', '18-SEP-92', + 14, 7707, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 112, 210, '31-AUG-92', '10-SEP-92', + 12, 550, 'CREDIT', 'Y'); +COMMIT; + + +CREATE TABLE s_product +(id NUMBER(7) + CONSTRAINT s_product_id_nn NOT NULL, + name VARCHAR2(50) + CONSTRAINT s_product_name_nn NOT NULL, + short_desc VARCHAR2(255), + longtext_id NUMBER(7), + image_id NUMBER(7), + suggested_whlsl_price NUMBER(11, 2), + whlsl_units VARCHAR2(25), + CONSTRAINT s_product_id_pk PRIMARY KEY (id), + CONSTRAINT s_product_name_uk UNIQUE (name)); + +INSERT INTO s_product VALUES ( + 10011, 'Bunny Boot', + 'Beginner''s ski boot', + 518, 1001, + 150, NULL); +INSERT INTO s_product VALUES ( + 10012, 'Ace Ski Boot', + 'Intermediate ski boot', + 519, 1002, + 200, NULL); +INSERT INTO s_product VALUES ( + 10013, 'Pro Ski Boot', + 'Advanced ski boot', + 520, 1003, + 410, NULL); +INSERT INTO s_product VALUES ( + 10021, 'Bunny Ski Pole', + 'Beginner''s ski pole', + 528, 1011, + 16.25, NULL); +INSERT INTO s_product VALUES ( + 10022, 'Ace Ski Pole', + 'Intermediate ski pole', + 529, 1012, + 21.95, NULL); +INSERT INTO s_product VALUES ( + 10023, 'Pro Ski Pole', + 'Advanced ski pole', + 530, 1013, + 40.95, NULL); +INSERT INTO s_product VALUES ( + 20106, 'Junior Soccer Ball', + 'Junior soccer ball', + 613, NULL, + 11, NULL); +INSERT INTO s_product VALUES ( + 20108, 'World Cup Soccer Ball', + 'World cup soccer ball', + 615, NULL, + 28, NULL); +INSERT INTO s_product VALUES ( + 20201, 'World Cup Net', + 'World cup net', + 708, NULL, + 123, NULL); +INSERT INTO s_product VALUES ( + 20510, 'Black Hawk Knee Pads', + 'Knee pads, pair', + 1017, NULL, + 9, NULL); +INSERT INTO s_product VALUES ( + 20512, 'Black Hawk Elbow Pads', + 'Elbow pads, pair', + 1019, NULL, + 8, NULL); +INSERT INTO s_product VALUES ( + 30321, 'Grand Prix Bicycle', + 'Road bicycle', + 828, 1291, + 1669, NULL); +INSERT INTO s_product VALUES ( + 30326, 'Himalaya Bicycle', + 'Mountain bicycle', + 833, 1296, + 582, NULL); +INSERT INTO s_product VALUES ( + 30421, 'Grand Prix Bicycle Tires', + 'Road bicycle tires', + 927, NULL, + 16, NULL); +INSERT INTO s_product VALUES ( + 30426, 'Himalaya Tires', + 'Mountain bicycle tires', + 933, NULL, + 18.25, NULL); +INSERT INTO s_product VALUES ( + 30433, 'New Air Pump', + 'Tire pump', + 940, NULL, + 20, NULL); +INSERT INTO s_product VALUES ( + 32779, 'Slaker Water Bottle', + 'Water bottle', + 1286, NULL, + 7, NULL); +INSERT INTO s_product VALUES ( + 32861, 'Safe-T Helmet', + 'Bicycle helmet', + 1368, 1829, + 60, NULL); +INSERT INTO s_product VALUES ( + 40421, 'Alexeyer Pro Lifting Bar', + 'Straight bar', + 928, 1381, + 65, NULL); +INSERT INTO s_product VALUES ( + 40422, 'Pro Curling Bar', + 'Curling bar', + 929, 1382, + 50, NULL); +INSERT INTO s_product VALUES ( + 41010, 'Prostar 10 Pound Weight', + 'Ten pound weight', + 517, NULL, + 8, NULL); +INSERT INTO s_product VALUES ( + 41020, 'Prostar 20 Pound Weight', + 'Twenty pound weight', + 527, NULL, + 12, NULL); +INSERT INTO s_product VALUES ( + 41050, 'Prostar 50 Pound Weight', + 'Fifty pound weight', + 557, NULL, + 25, NULL); +INSERT INTO s_product VALUES ( + 41080, 'Prostar 80 Pound Weight', + 'Eighty pound weight', + 587, NULL, + 35, NULL); +INSERT INTO s_product VALUES ( + 41100, 'Prostar 100 Pound Weight', + 'One hundred pound weight', + 607, NULL, + 45, NULL); +INSERT INTO s_product VALUES ( + 50169, 'Major League Baseball', + 'Baseball', + 676, 1119, + 4.29, NULL); +INSERT INTO s_product VALUES ( + 50273, 'Chapman Helmet', + 'Batting helmet', + 780, 1223, + 22.89, NULL); +INSERT INTO s_product VALUES ( + 50417, 'Griffey Glove', + 'Outfielder''s glove', + 924, 1367, + 80, NULL); +INSERT INTO s_product VALUES ( + 50418, 'Alomar Glove', + 'Infielder''s glove', + 925, 1368, + 75, NULL); +INSERT INTO s_product VALUES ( + 50419, 'Steinbach Glove', + 'Catcher''s glove', + 926, 1369, + 80, NULL); +INSERT INTO s_product VALUES ( + 50530, 'Cabrera Bat', + 'Thirty inch bat', + 1037, 1480, + 45, NULL); +INSERT INTO s_product VALUES ( + 50532, 'Puckett Bat', + 'Thirty-two inch bat', + 1039, 1482, + 47, NULL); +INSERT INTO s_product VALUES ( + 50536, 'Winfield Bat', + 'Thirty-six inch bat', + 1043, 1486, + 50, NULL); +COMMIT; + + +CREATE TABLE s_region +(id NUMBER(7) + CONSTRAINT s_region_id_nn NOT NULL, + name VARCHAR2(50) + CONSTRAINT s_region_name_nn NOT NULL, + CONSTRAINT s_region_id_pk PRIMARY KEY (id), + CONSTRAINT s_region_name_uk UNIQUE (name)); + +INSERT INTO s_region VALUES ( + 1, 'North America'); +INSERT INTO s_region VALUES ( + 2, 'South America'); +INSERT INTO s_region VALUES ( + 3, 'Africa / Middle East'); +INSERT INTO s_region VALUES ( + 4, 'Asia'); +INSERT INTO s_region VALUES ( + 5, 'Europe'); +COMMIT; + + +CREATE TABLE s_title +(title VARCHAR2(25) + CONSTRAINT s_title_title_nn NOT NULL, + CONSTRAINT s_title_title_pk PRIMARY KEY (title)); + +INSERT INTO s_title VALUES ('President'); +INSERT INTO s_title VALUES ('Sales Representative'); +INSERT INTO s_title VALUES ('Stock Clerk'); +INSERT INTO s_title VALUES ('VP, Administration'); +INSERT INTO s_title VALUES ('VP, Finance'); +INSERT INTO s_title VALUES ('VP, Operations'); +INSERT INTO s_title VALUES ('VP, Sales'); +INSERT INTO s_title VALUES ('Warehouse Manager'); +COMMIT; + + +CREATE TABLE s_warehouse +(id NUMBER(7) + CONSTRAINT s_warehouse_id_nn NOT NULL, + region_id NUMBER(7) + CONSTRAINT s_warehouse_region_id_nn NOT NULL, + address LONG, + city VARCHAR2(30), + state VARCHAR2(20), + country VARCHAR2(30), + zip_code VARCHAR2(75), + phone VARCHAR2(25), + manager_id NUMBER(7), + CONSTRAINT s_warehouse_id_pk PRIMARY KEY (id)); + +INSERT INTO s_warehouse VALUES ( + 101, 1, + '283 King Street', + 'Seattle', 'WA', 'USA', + NULL, + NULL, 6); +INSERT INTO s_warehouse VALUES ( + 10501, 5, + '5 Modrany', + 'Bratislava', NULL, 'Czechozlovakia', + NULL, + NULL, 10); +INSERT INTO s_warehouse VALUES ( + 201, 2, + '68 Via Centrale', + 'Sao Paolo', NULL, 'Brazil', + NULL, + NULL, 7); +INSERT INTO s_warehouse VALUES ( + 301, 3, + '6921 King Way', + 'Lagos', NULL, 'Nigeria', + NULL, + NULL, 8); +INSERT INTO s_warehouse VALUES ( + 401, 4, + '86 Chu Street', + 'Hong Kong', NULL, NULL, + NULL, + NULL, 9); +COMMIT; + + +rem Add foreign key constraints. + +ALTER TABLE s_dept + ADD CONSTRAINT s_dept_region_id_fk + FOREIGN KEY (region_id) REFERENCES s_region (id); +ALTER TABLE s_emp + ADD CONSTRAINT s_emp_manager_id_fk + FOREIGN KEY (manager_id) REFERENCES s_emp (id); +ALTER TABLE s_emp + ADD CONSTRAINT s_emp_dept_id_fk + FOREIGN KEY (dept_id) REFERENCES s_dept (id); +ALTER TABLE s_emp + ADD CONSTRAINT s_emp_title_fk + FOREIGN KEY (title) REFERENCES s_title (title); +ALTER TABLE s_customer + ADD CONSTRAINT s_sales_rep_id_fk + FOREIGN KEY (sales_rep_id) REFERENCES s_emp (id); +ALTER TABLE s_customer + ADD CONSTRAINT s_customer_region_id_fk + FOREIGN KEY (region_id) REFERENCES s_region (id); +ALTER TABLE s_ord + ADD CONSTRAINT s_ord_customer_id_fk + FOREIGN KEY (customer_id) REFERENCES s_customer (id); +ALTER TABLE s_ord + ADD CONSTRAINT s_ord_sales_rep_id_fk + FOREIGN KEY (sales_rep_id) REFERENCES s_emp (id); +ALTER TABLE s_product + ADD CONSTRAINT s_product_image_id_fk + FOREIGN KEY (image_id) REFERENCES s_image (id); +ALTER TABLE s_product + ADD CONSTRAINT s_product_longtext_id_fk + FOREIGN KEY (longtext_id) REFERENCES s_longtext (id); +ALTER TABLE s_item + ADD CONSTRAINT s_item_ord_id_fk + FOREIGN KEY (ord_id) REFERENCES s_ord (id); +ALTER TABLE s_item + ADD CONSTRAINT s_item_product_id_fk + FOREIGN KEY (product_id) REFERENCES s_product (id); +ALTER TABLE s_warehouse + ADD CONSTRAINT s_warehouse_manager_id_fk + FOREIGN KEY (manager_id) REFERENCES s_emp (id); +ALTER TABLE s_warehouse + ADD CONSTRAINT s_warehouse_region_id_fk + FOREIGN KEY (region_id) REFERENCES s_region (id); +ALTER TABLE s_inventory + ADD CONSTRAINT s_inventory_product_id_fk + FOREIGN KEY (product_id) REFERENCES s_product (id); +ALTER TABLE s_inventory + ADD CONSTRAINT s_inventory_warehouse_id_fk + FOREIGN KEY (warehouse_id) REFERENCES s_warehouse (id); + +prompt Tables and sequences created and populated. +set feedback on diff --git a/tyevdemo.sql b/tyevdemo.sql new file mode 100644 index 0000000..51a4672 --- /dev/null +++ b/tyevdemo.sql @@ -0,0 +1,354 @@ +Rem +Rem $Header: tyevdemo.sql 01-may-2001.14:30:34 hyeh Exp $ +Rem +Rem tyevdemo.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem tyevdemo.sql - Demonstrate Type Evolution feature +Rem +Rem DESCRIPTION +Rem Demonstrate Type Evolution feature +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem hyeh 05/01/01 - fix query format +Rem hyeh 04/10/01 - Merged hyeh_inh_tyev_demos +Rem hyeh 04/10/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +COLUMN constraint_nm FORMAT A20 +COLUMN index_nm FORMAT A20 +SET ECHO ON + +connect system/manager +drop user tyevdemo1 cascade; + +grant connect, resource to tyevdemo1 identified by tyevdemo1; + +connect tyevdemo1/tyevdemo1 + +-- create some types and tables +create type type1 as object (c1 number, c2 number, c3 number); +/ +show errors +create type type2 as object (c2 varchar2(10), c3 number, c4 char(10), + member function mf1 (in1 varchar2) return number); +/ +show errors + +create type body type2 as + member function mf1 (in1 varchar2) return number as + begin + if in1 is null then + return length(self.c2); + end if; + return length(self.c2) + length(in1); + end; +end; +/ +show errors + +create type type3 as object (c1 ref type2, c2 varchar2(10)); +/ +show errors +create type type4 as object (c1 type2, c2 varchar2(10)); +/ +show errors +create type nttype1 as table of char(6); +/ +show errors +create type vatype1 as varray(7) of ref type2; +/ +show errors +create type nttype2 as table of type4; +/ +show errors + +create table otb1 of type1; +create table rtb1 (c1 type1, c2 number); +create table otb2 of type2 (constraint opk2 primary key (c2)); + +create table rtb2 (c1 type2, c2 vatype1, c3 number, c4 nttype2, + constraint rpk2 primary key (c1.c2)) + nested table c4 store as rtb2_c4, + varray c2 store as lob rtb2_c2 (index rlobix2_c2); +create index rix2 on rtb2 (c1.c4, c1.c2); + +insert into otb1 values (1,1,1); +insert into rtb1 select value(p), 1 from otb1 p; + +insert into otb2 values ('abcdefghij',1,'abcdefghij'); +insert into rtb2 values + (type2('abcdefghij',1,'abcdefghij'), null, 1,nttype2(type4(null,null))); + +update rtb2 p set p.c2=vatype1(null,null,null,null,null,null,null); +update table (select c4 from rtb2) e + set value(e)=type4((select value(p) from otb2 p), 'a'); + +declare + vref ref type2; + va1 vatype1; + va_cnt integer; +begin + select c2 into va1 from rtb2; + select ref(a) into vref from otb2 a; + va1 := vatype1(vref,null,null,null,null,null,null); + update rtb2 set c2 = va1; +end; +/ + +/*******************/ +/* Add/Drop Method */ +/*******************/ + +alter type type2 + add order member function om (in1 type2) return number, + add static procedure sp1 (in1 type2), + drop member function mf1 (in1 varchar2) return number, + add member function mf1 (in2 varchar2) return varchar2 + cascade; + +create or replace type body type2 as + member function mf1 (in2 varchar2) return varchar2 as + begin + if in2 is null then + return self.c2; + end if; + return (self.c2 || in2); + end; + + order member function om (in1 type2) return number as + begin + return (self.c3 - in1.c3); + end; + + static procedure sp1 (in1 type2) as + begin + dbms_output.put_line('in1.c3 = '||in1.c3); + end; +end; +/ +show errors + +desc type2 + +/* populate tables */ +update table(select c4 from rtb2) e + set value(e) = type4((select value(p) from otb2 p), '1a2b3c'); + +select * from otb1; +select * from rtb1; +select * from otb2; +select c1, c3, c4 from rtb2; +select deref(column_value) from table(select c2 from rtb2) order by 1; +select value(e) from table(select c4 from rtb2) e; + +select substr(constraint_name,1,20) constraint_nm, constraint_type, + TABLE_NAME, STATUS, INDEX_NAME,INVALID, VIEW_RELATED + from user_constraints order by 3,1; + +select substr(index_name,1,20) index_nm, index_type, table_name + from user_indexes + order by 3, 1; + +/********************/ +/* Modify attribute */ +/********************/ +/* can't increase length of fixed variable */ +alter type type2 modify attribute (c4 char(13)) cascade; +alter type type2 modify attribute (c2 varchar2(13)) cascade; + +/* workaround - reconnect */ +connect tyevdemo1/tyevdemo1 + +alter type type2 modify attribute (c2 varchar2(25)) invalidate; + +desc otb2 +desc rtb2 +desc type2 + +select * from otb2; +select c3 from rtb2; + +/******************/ +/* Drop attribute */ +/******************/ + +alter type type1 drop attribute(c2) cascade not including table data; +alter type type2 drop attribute(c2) cascade not including table data; + +connect tyevdemo1/tyevdemo1 + +/* fix type2 body not to refer to dropped attribute */ +create or replace type body type2 as + member function mf1 (in2 varchar2) return varchar2 as + begin + if in2 is null then + return self.c4; + end if; + return (self.c4 || in2); + end; + + order member function om (in1 type2) return number as + begin + return (self.c3 - in1.c3); + end; + + static procedure sp1 (in1 type2) as + begin + dbms_output.put_line('in1.c3 = '||in1.c3); + end; +end; +/ +show errors + +select * from otb1; +select * from rtb1; +select * from otb2; + +select c1, c3, c4 from rtb2; +select deref(column_value) from table(select c2 from rtb2) order by 1; + +select substr(constraint_name,1,20) constraint_nm, constraint_type, + TABLE_NAME, STATUS, INDEX_NAME,INVALID, VIEW_RELATED + from user_constraints order by 3,1; + +select substr(index_name,1,20) index_nm, index_type, table_name + from user_indexes + order by 3, 1; + +alter type type1 drop attribute(c3) invalidate; + +select * from otb1; +select c2 from rtb1; + +/* should get get ORA-22337 */ +select * from rtb1; + +/* reconnect to get new defn */ +connect tyevdemo1/tyevdemo1 +select * from rtb1; + +/******************/ +/* Add attribute */ +/******************/ + +alter table rtb1 upgrade; + +alter type type1 add attribute (c2 date) cascade; + +connect tyevdemo1/tyevdemo1 +desc otb1 +desc rtb1 +desc type1 + +alter type type1 drop attribute (c2) cascade; + +/* should get get ORA-22337 */ +select * from rtb1; + +connect tyevdemo1/tyevdemo1 +/* get new defn */ +desc type1 +select * from rtb1; + +alter type type1 add attribute (c3 clob) invalidate; + +/******************/ +/* Upgrade table */ +/******************/ + +alter table otb1 upgrade not including data; +alter table rtb1 upgrade not including data; + +select c2 from rtb1; +select * from otb1; + +update rtb1 set c2=c2; +update rtb1 set c1=c1; + +alter table rtb1 drop (c1); +alter table rtb1 add (c1 type1); +alter table rtb1 upgrade including data; +select * from otb1; + +connect tyevdemo1/tyevdemo1 +desc type1 +desc type2 + +update otb2 p set value(p)=value(p); + +select * from otb2; +select p.c1.c2 from rtb2 p; + +alter table rtb2 drop (c1); +select deref(column_value) from table(select c2 from rtb2 where c3=1) + order by 1; + +select p.column_value.c2 c2 + from table(select c2 from rtb2 where c3=1) p; + +truncate table rtb2; + +set serveroutput on +-- show objects depend on types +exec dbms_utility.get_dependency('type','tyevdemo1','type1'); +exec dbms_utility.get_dependency('type','tyevdemo1','type2'); +exec dbms_utility.get_dependency('type','tyevdemo1','type3'); +exec dbms_utility.get_dependency('type','tyevdemo1','nttype1'); +exec dbms_utility.get_dependency('type','tyevdemo1','vatype1'); + +/********************************************************/ +/* demonstrate type evolution with inheritance features */ +/********************************************************/ +connect tyevdemo1/tyevdemo1 + +alter table rtb1 drop (c1); +alter table rtb1 add (nc1 type1); + +insert into rtb1 values + (10, type1(10, empty_clob())); + +/* change type1 to not final */ +alter type type1 not final cascade; +alter type type1 + add attribute (c10 char(6)) cascade not including table data; +alter type type1 + add map member function mm1 return char cascade; + +/* create subtype */ + +create or replace type type1s under type1 (c11 nttype1); +/ +show errors + +/* override map method */ +alter type type1s + add overriding map member function mm1 return char; + +/* column rtb1.nc1 remains not substitutable */ +insert into rtb1 values + (1, type1s(1,empty_clob(),null,'a')); + +/* create table with substitutable column */ +create table rtb1s (c1 number, c2 type1, c3 date) + nested table treat(c2 as type1s).c11 store as rtb1s_c2_c11; +insert into rtb1s + select c2, type1s(p.nc1.c1, p.nc1.c3, p.nc1.c10, nttype1('A','B','C')), + to_date('08/21/2000','MM/DD/YYYY') from rtb1 p; + +select * from rtb1s order by c1; + +connect system/manager +drop user tyevdemo1 cascade; + diff --git a/ulcase.sh b/ulcase.sh new file mode 100644 index 0000000..495343e --- /dev/null +++ b/ulcase.sh @@ -0,0 +1,122 @@ +#!/bin/sh +# +# $Header: ulcase.sh 06-sep-2007.13:54:17 jstenois Exp $ +# +# ulcase.sh +# +# Copyright (c) 1999, 2007, Oracle. All rights reserved. +# +# NAME +# ulcase.sh - run sqlldr demos +# +# DESCRIPTION +# Shell script to run sqlldr demos. +# Please append to script as more ulcase* demos are added. +# +# MODIFIED (MM/DD/YY) +# jstenois 09/06/07 - remove password from demo script +# krich 01/26/04 - adding case study 11 +# cmlim 07/20/99 - create shell script for running all sqlldr demos +# cmlim 07/20/99 - Creation +# + +echo " " +echo "- This script runs through all of the SQL Loader demos." +echo "- It uses SQLPlus to create the necessary objects and then" +echo "- calls SQL Loader to load data. This script uses schema" +echo "- SCOTT for all of the tests. Whenever the script executes" +echo "- SQLPlus or SQL Loader utilities, it will prompt you for" +echo "- password of the SCOTT user. You will need to enter this" +echo "- password every time for the script to continue. The" +echo "- default password for user SCOTT is TIGER." +echo " " + +# CASE1 +echo " " +echo " Starting case 1" +echo " Calling SQL Plus to do setup for case 1" +sqlplus scott @ulcase1 +echo " Calling SQL Loader to load data for case 1" +sqlldr scott ulcase1.ctl + +# CASE2 +echo " " +echo " Starting case 2" +echo " Calling SQL Loader to load data for case 2" +sqlldr scott ulcase2 + +# CASE3 +echo " " +echo " Starting case 3" +echo " Calling SQL Plus to do setup for case 3" +sqlplus scott @ulcase3 +echo " Calling SQL Loader to load data for case 3" +sqlldr scott ulcase3 + +# CASE4 +echo " " +echo " Starting case 4" +echo " Calling SQL Plus to do setup for case 4" +sqlplus scott @ulcase4 +echo " Calling SQL Loader to load data for case 4" +sqlldr scott ulcase4 + +# CASE5 +echo " " +echo " Starting case 5" +echo " Calling SQL Plus to do setup for case 5" +sqlplus scott @ulcase5 +echo " Calling SQL Loader to load data for case 5" +sqlldr scott ulcase5 + +# CASE6 +echo " " +echo " Starting case 6" +echo " Calling SQL Plus to do setup for case 6" +sqlplus scott @ulcase6 +echo " Calling SQL Loader to load data for case 6" +sqlldr scott ulcase6 direct=true + +# CASE7 +echo " " +echo " Starting case 7" +echo " Calling SQL Plus to do setup for case 7" +sqlplus scott @ulcase7s +echo " Calling SQL Loader to load data for case 7" +sqlldr scott ulcase7 +echo " Calling SQL Plus to do cleanup for case 7" +sqlplus scott @ulcase7e + +# CASE8 +echo " " +echo " Starting case 8" +echo " Calling SQL Plus to do setup for case 8" +sqlplus scott @ulcase8 +echo " Calling SQL Loader to load data for case 8" +sqlldr scott ulcase8 + +# CASE9 +echo " " +echo " Starting case 9" +echo " Calling SQL Plus to do setup for case 9" +sqlplus scott @ulcase9 +echo " Calling SQL Loader to load data for case 9" +sqlldr scott ulcase9 + +# CASE10 +echo " " +echo " Starting case 10" +echo " Calling SQL Plus to do setup for case 10" +sqlplus scott @ulcase10 +echo " Calling SQL Loader to load data for case 10" +sqlldr scott ulcase10 + +# CASE11 +echo " " +echo " Starting case 11" +echo " Calling SQL Plus to do setup for case 11" +sqlplus scott @ulcase11 +echo " Calling SQL Loader to load data for case 11" +sqlldr scott ulcase11 + + diff --git a/ulcase1.ctl b/ulcase1.ctl new file mode 100644 index 0000000..8df9ec4 --- /dev/null +++ b/ulcase1.ctl @@ -0,0 +1,62 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase1.ctl - SQL*Loader Case Study 1: Loading Variable-Length Data +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- +-- A simple control file identifying one table and three columns +-- to be loaded. +-- +-- Including data to be loaded from the control file itself, so +-- there is no separate datafile. +-- +-- Loading data in stream format, with both types of delimited +-- fields: terminated and enclosed. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase1 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase1.ctl LOG=ulcase1.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- The LOAD DATA statement is required at the beginning of the +-- control file. +-- +-- INFILE * specifies that the data is found in the control file +-- and not in an external file. +-- +-- The INTO TABLE statement is required to identify the table to +-- be loaded (dept) into. By default, SQL*Loader requires the +-- table to be empty before it inserts any records. +-- +-- FIELDS TERMINATED BY specifies that the data is terminated by +-- commas, but may also be enclosed by quotation marks. Datatypes +-- for all fields default to CHAR. +-- +-- The names of columns to load are enclosed in parentheses. +-- If no datatype or length is specified and the field is delimited +-- with ENCLOSED BY or with TERMINATED BY, then the default +-- datatype is CHAR and the default length is 255. If ENCLOSED BY +-- or TERMINATED BY is not specified, then the default type is CHAR +-- and the default length is 1. +-- +-- BEGINDATA specifies the beginning of the data. +-- +LOAD DATA +INFILE * +INTO TABLE DEPT +FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' +(DEPTNO, DNAME, LOC) +BEGINDATA +12,RESEARCH,"SARATOGA" +10,"ACCOUNTING",CLEVELAND +11,"ART",SALEM +13,FINANCE,"BOSTON" +21,"SALES",PHILA. +22,"SALES",ROCHESTER +42,"INT'L","SAN FRAN" diff --git a/ulcase1.sql b/ulcase1.sql new file mode 100644 index 0000000..be7f115 --- /dev/null +++ b/ulcase1.sql @@ -0,0 +1,44 @@ +rem +rem $Header: ulcase1.sql 14-jul-99.14:22:19 mjaeger Exp $ +rem +rem Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase1.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem ksudarsh 03/01/93 - comment out vms specific host command +rem ksudarsh 12/29/92 - Creation +rem cheigham 08/28/91 - Creation +rem + +set termout off + +rem host write sys$output "Building first demonstration tables. Please wait" + +drop table emp; +drop table dept; + +create table emp + (empno number(4) not null, + ename char(10), + job char(9), + mgr number(4), + hiredate date, + sal number(7,2), + comm number(7,2), + deptno number(2)); + +create table dept + (deptno number(2), + dname char(14) , + loc char(13) ) ; + +exit diff --git a/ulcase10.ctl b/ulcase10.ctl new file mode 100644 index 0000000..d474b47 --- /dev/null +++ b/ulcase10.ctl @@ -0,0 +1,82 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase10.ctl - SQL*Loader Case Study 10: Loading REF Fields and VARRAYs +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- +-- Loading a customer table that has a primary key as its OID and +-- stores order items in a VARRAY. +-- +-- Loading an order table that has a reference to the customer table and +-- the order items in a VARRAY. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase10 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase1.ctl0 LOG=ulcase10.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- cust_no and item_list_count are FILLER fields. The FILLER field is +-- assigned values from the data field to which it is mapped. +-- +-- The cust field is created as a REF field. +-- +-- item_list is stored in a VARRAY. +-- +-- The second occurrence of item_list identifies the datatype of each +-- element of the VARRAY. Here, the datatype is COLUMN OBJECT. +-- +-- The listing of item, cnt, price shows all attributes of the column +-- object that are loaded for the VARRAY. The list is enclosed in parentheses. +-- +-- The data is contained in the control file and is preceded by the +-- BEGINDATA parameter. +-- +LOAD DATA +INFILE * +CONTINUEIF THIS (1) = '*' + +INTO TABLE customers +REPLACE +FIELDS TERMINATED BY "," +( + cust_no CHAR, + name CHAR, + addr CHAR +) + +INTO TABLE orders +REPLACE +FIELDS TERMINATED BY "," +( + order_no CHAR, + cust_no FILLER CHAR, + cust REF (CONSTANT 'CUSTOMERS', cust_no), + item_list_count FILLER CHAR, + item_list VARRAY COUNT (item_list_count) + ( + item_list COLUMN OBJECT + ( + item CHAR, + cnt CHAR, + price CHAR + ) + ) +) + +BEGINDATA +*00001,Spacely Sprockets,15 Space Way, +*00101,00001,2, +*Sprocket clips, 10000, .01, + Sprocket cleaner, 10, 14.00 +*00002,Cogswell Cogs,12 Cogswell Lane, +*00100,00002,4, +*one quarter inch cogs,1000,.02, +*one half inch cog, 150, .04, +*one inch cog, 75, .10, + Custom coffee mugs, 10, 2.50 diff --git a/ulcase10.sql b/ulcase10.sql new file mode 100644 index 0000000..513a046 --- /dev/null +++ b/ulcase10.sql @@ -0,0 +1,80 @@ +rem +Rem $Header: ulcase10.sql 11-may-00.13:48:45 rpfau Exp $ +rem +rem ulcase10.sql +rem +rem Copyright (c) 1998, 1999,, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase10.sql - set up for SQL Loader example 10 +rem +rem DESCRIPTION +rem Create tables need to for example of using SQL Loader to load +rem VARRAYS and references +rem +rem NOTES +rem none +rem +rem MODIFIED (MM/DD/YY) +Rem rpfau 05/11/00 - Remove slashes on create table commands so it +Rem runs successfully using sqlplus. +Rem cmlim 07/27/99 - add / +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem jstenois 10/26/98 - demo of 8.1 features for sqlldr +rem jstenois 10/26/98 - Created +rem + +rem host write sys$output "Building case 10 demonstration tables. Please wait" + +rem do all cleanup + +drop table orders; +drop table customers; +drop type item_list_type; +drop type item_type; +drop type customer_type; + +rem Create an ORDER record that has a VARRAY for the items that comprise the +rem order and has a reference field to a record in the CUSTOMER table for +rem the customer placing the order. + +rem create customer type + +create type customer_type as object ( + cust_no char(5), + name char(20), + addr char(20) +); +/ + +rem create object table for customer type + +create table customers of customer_type + (primary key (cust_no)) + object id primary key; + +rem create type for order items + +create type item_type as object ( + item varchar(50), + cnt number, + price number(7,2) +); +/ + +rem create varray type for order items + +create type item_list_type as varray (1000) of item_type; +/ + +rem create orders table with varray for items and ref to object table + +create table orders ( + order_no char(5), + cust ref customer_type references customers, + item_list item_list_type +); + +exit; +/ diff --git a/ulcase11.ctl b/ulcase11.ctl new file mode 100644 index 0000000..05f22d3 --- /dev/null +++ b/ulcase11.ctl @@ -0,0 +1,72 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase11.ctl - SQL*Loader Case Study 11: Load Data in the Unicode +-- Character Set UTF-16 +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- Using SQL*Loader to load data in the Unicode character set, UTF16. +-- +-- Using SQL*Loader to load data in a fixed-width, multibyte character set. +-- +-- Using character-length semantics. +-- +-- Using SQL*Loader to load data in little-endian byte order. SQL*Loader +-- checks the byte order of the system on which it is running. If necessary, +-- SQL*Loader swaps the byte order of the data to ensure that any +-- byte-order-dependent data is correctly loaded. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase11 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase11.ctl LOG=ulcase11.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- +-- The character set specified with the CHARACTERSET keyword is UTF16. +-- SQL*Loader will convert the data from the UTF16 character set to +-- the database character set. Because UTF16 is specified as the +-- character set, character-length semantics are used for the load. +-- +-- BYTEORDER LITTLE tells SQL*Loader that the data in the datafile is +-- in little-endian byte order. SQL*Loader checks the byte order of the +-- system on which it is running to determine if any byte-swapping is +-- necessary. In this example, all the character data in UTF16 is +-- byte-order dependent. +-- +-- The TERMINATED BY and OPTIONALLY ENCLOSED BY clauses both specify +-- hexadecimal strings. The X'002c' is the encoding for a comma (,) in +-- UTF-16 big-endian format. The X'0022' is the encoding for a double +-- quotation mark (") in big-endian format. Because the datafile is in +-- little-endian format, SQL*Loader swaps the bytes before checking for +-- a match. If these clauses were specified as character strings instead +-- of hexadecimal strings, SQL*Loader would convert the strings to the +-- datafile character set (UTF16) and byte-swap as needed before checking +-- for a match. +-- +-- Because character-length semantics are used, the maximum length for +-- the empno, hiredate, and deptno fields is interpreted as characters, +-- not bytes. +-- +-- The TERMINATED BY clause for the deptno field is specified using the +-- character string ":". SQL*Loader converts the string to the datafile +-- character set (UTF16) and byte-swaps as needed before checking for a match. + +LOAD DATA +CHARACTERSET utf16 +BYTEORDER little +INFILE ulcase11.dat +REPLACE + +INTO TABLE EMP +FIELDS TERMINATED BY X'002c' OPTIONALLY ENCLOSED BY X'0022' +(empno integer external (5), ename, job, mgr, + hiredate DATE(20) "DD-Month-YYYY", + sal, comm, + deptno CHAR(5) TERMINATED BY ":", + projno, + loadseq SEQUENCE(MAX,1) ) diff --git a/ulcase11.dat b/ulcase11.dat new file mode 100644 index 0000000000000000000000000000000000000000..6817763d060abfc50f3f5dfe4223ad2e5b7a2b23 GIT binary patch literal 932 zcma)*TTjA35QWdPzk>8xNxQVP_-06az+g=H1riAu5eXL){=MJqc3Z$3X}Xu`?wm8{ zOiPuj^fd4%Qsx_twCB`}RmQ$zwA)Sv*`2z~ zDG`fhtZx07>B?irOo<-!N|t$p{RHAnTcR(_EA8qpAx{a~qdxS>w|7k$H)r^T$4$Xc zf53Mhe?TR;Gs7QIFm*cM0ZVK(aZij|JP;@}`f8!VG^8~F&RAVY` z8wLJX-+_3iH4KgWss255HjZ657q$Mz=UD$7zk-tqc|!H827f|TrpFeAt;*or%oGmiDuh1BsL&jUK6K#peIHo$yeob9wys!5?tE{=uDpa-1+NLb*4+KALo%3{ vMzKS!Kl2N?RkdS7Esk_C1?^v1>VRUgTTT1uaq2t9Ts`j;>%#UgId$m^fh}(_ literal 0 HcmV?d00001 diff --git a/ulcase11.sql b/ulcase11.sql new file mode 100644 index 0000000..9109160 --- /dev/null +++ b/ulcase11.sql @@ -0,0 +1,40 @@ +Rem +Rem $Header: ulcase11.sql 06-feb-2001.14:26:12 rpfau Exp $ +Rem +Rem ulcase11.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem ulcase11.sql - Set up for SQL Loade example 11 +Rem +Rem DESCRIPTION +Rem Create table emp for example loading little endian unicode (UTF-16) +Rem data. +Rem +Rem NOTES +Rem None +Rem +Rem MODIFIED (MM/DD/YY) +Rem rpfau 02/06/01 - Merged rpfau_sqlldr_add_case_study_11 +Rem rpfau 01/30/01 - Created +Rem +set termout off + +rem host write sys$output "Building demonstration tables for case study 11. Please wait" + +drop table emp; + +create table emp + (empno number(4) not null, + ename char(10), + job char(9), + mgr number(4), + hiredate date, + sal number(7,2), + comm number(7,2), + deptno number(2), + projno number, + loadseq number); + +exit diff --git a/ulcase2.ctl b/ulcase2.ctl new file mode 100644 index 0000000..d7d2741 --- /dev/null +++ b/ulcase2.ctl @@ -0,0 +1,56 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase2.ctl - SQL*Loader Case Study 2: Loading Fixed-Format Files +-- +-- DESCRIPTION +-- This control file demonstrates the following: +-- Use of a separate data file. +-- +-- Data conversions. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase1 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. It is the same script +-- used to prepare for case study 1, so if you have already +-- run case study 1, you can skip this step. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase2.ctl LOG=ulcase2.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- The LOAD DATA statement is required at the beginning of the +-- control file. +-- +-- The name of the file containing data follows the INFILE parameter. +-- +-- The INTO TABLE statement is required to identify the table to +-- be loaded into. +-- +-- empno, ename, job, and so on are names of columns in table emp. +-- The datatypes (INTEGER EXTERNAL, CHAR, DECIMAL EXTERNAL) identify +-- the datatype of data fields in the file, not of corresponding +-- columns in the emp table. +-- +-- Note that the set of column specifications is enclosed in +-- parentheses. +-- +-- Records loaded in this example from the emp table contain +-- department numbers. Unless the dept table is loaded first, +-- referential integrity checking rejects these records (if +-- referential integrity constraints are enabled for the emp table). + +-- +LOAD DATA +INFILE 'ulcase2.dat' +INTO TABLE EMP + +( EMPNO POSITION(01:04) INTEGER EXTERNAL, + ENAME POSITION(06:15) CHAR, + JOB POSITION(17:25) CHAR, + MGR POSITION(27:30) INTEGER EXTERNAL, + SAL POSITION(32:39) DECIMAL EXTERNAL, + COMM POSITION(41:48) DECIMAL EXTERNAL, + DEPTNO POSITION(50:51) INTEGER EXTERNAL) + diff --git a/ulcase2.dat b/ulcase2.dat new file mode 100644 index 0000000..e8ebbf6 --- /dev/null +++ b/ulcase2.dat @@ -0,0 +1,7 @@ +7782 CLARK MANAGER 7839 2572.50 10 +7839 KING PRESIDENT 5500.00 10 +7934 MILLER CLERK 7782 920.00 10 +7566 JONES MANAGER 7839 3123.75 20 +7499 ALLEN SALESMAN 7698 1600.00 300.00 30 +7654 MARTIN SALESMAN 7698 1312.50 1400.00 30 +7658 CHAN ANALYST 7566 3450.00 20 diff --git a/ulcase3.ctl b/ulcase3.ctl new file mode 100644 index 0000000..2d16635 --- /dev/null +++ b/ulcase3.ctl @@ -0,0 +1,83 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase3.ctl - SQL*Loader Case Study 3: Loading a Delimited, +-- Free-format File +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- Loading data (enclosed and terminated) in stream format. +-- +-- Loading dates using the DATE datatype. +-- +-- Using SEQUENCE numbers to generate unique keys for loaded data. +-- +-- Using APPEND to indicate that the table need not be empty before +-- inserting new records. +-- +-- Using comments in the control file set off by two hyphens. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase3 to execute the SQL script for +-- this case study. This prepares and populates tables, adds +-- the projno and loadseq columns to table emp, and then returns +-- you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase3.ctl LOG=ulcase3.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- This control file loads the same table as in case 2, but it +-- loads three additional columns (hiredate, projno, and loadseq). +-- The projno and loadseq columns are added to the emp table when +-- you run the ulcase3.sql script. +-- +-- INFILE * specifies that the data is found at the end of the +-- control file. +-- +-- APPEND specifies that the data can be loaded even if the table +-- already contains rows. That is, the table need not be empty. +-- +-- The default terminator for the data fields is a comma, and some +-- fields may be enclosed by double quotation marks ("). +-- +-- The data to be loaded into column hiredate appears in the format +-- DD-Month-YYYY. The length of the date field is specified to have +-- a maximum of 20. The maximum length is in bytes, with default +-- byte-length semantics. If character-length semantics were used +-- instead, the length would be in characters. If a length is not +-- specified, then the length depends on the length of the date mask. +-- +-- The SEQUENCE function generates a unique value in the column loadseq. +-- This function finds the current maximum value in column loadseq and +-- adds the increment (1) to it to obtain the value for loadseq for +-- each row inserted. +-- +-- BEGINDATA specifies the end of the control information and the +-- beginning of the data. +-- +-- Although each physical record equals one logical record, the fields +-- vary in length, so that some records are longer than others. Note +-- also that several rows have null values for comm. + +LOAD DATA +INFILE * +APPEND + +INTO TABLE EMP +FIELDS TERMINATED BY "," OPTIONALLY ENCLOSED BY '"' +(empno, ename, job, mgr, + hiredate DATE(20) "DD-Month-YYYY", + sal, comm, + deptno CHAR TERMINATED BY ':', + projno, + loadseq SEQUENCE(MAX,1) ) + +BEGINDATA +7782, "Clark", "Manager", 7839, 09-June-1981, 2572.50,, 10:101 +7839, "King", "President", , 17-November-1981, 5500.00,, 10:102 +7934, "Miller", "Clerk", 7782, 23-January-1982, 920.00,, 10:102 +7566, "Jones", "Manager", 7839, 02-April-1981, 3123.75,, 20:101 +7499, "Allen", "Salesman", 7698, 20-February-1981, 1600.00, 300.00, 30:103 +7654, "Martin", "Salesman", 7698, 28-September-1981, 1312.50, 1400.00, 30:103 +7658, "Chan", "Analyst", 7566, 03-May-1982, 3450,, 20:101 diff --git a/ulcase3.sql b/ulcase3.sql new file mode 100644 index 0000000..e233df3 --- /dev/null +++ b/ulcase3.sql @@ -0,0 +1,31 @@ +rem +rem $Header: ulcase3.sql 14-jul-99.14:23:36 mjaeger Exp $ +rem +rem Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase3.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem NOTES +rem ulcase2.sql must be executed before this pocedure. +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem ksudarsh 03/11/93 - comment out vms specific host command +rem ksudarsh 12/29/92 - Creation +rem cheigham 08/28/91 - Creation +rem + +set termout off + +rem Do not clean up table because this example shows appending to existing +rem rows in table that also has new columns. + +rem host write sys$output "Adding columns to emp. Please wait." + +alter table emp add (projno number, loadseq number); + +exit diff --git a/ulcase4.ctl b/ulcase4.ctl new file mode 100644 index 0000000..2bd522f --- /dev/null +++ b/ulcase4.ctl @@ -0,0 +1,76 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase4.ctl - SQL*Loader Case Study 4: Loading Combined Physical Records +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- Combining multiple physical records to form one logical +-- record with CONTINUEIF. +-- +-- Inserting negative numbers. +-- +-- Using REPLACE to indicate that the table should be emptied +-- before the new data is inserted. +-- +-- Specifying a discard file in the control file using DISCARDFILE. +-- +-- Specifying a maximum number of discards using DISCARDMAX. +-- +-- Rejecting records due to duplicate values in a unique index +-- or due to invalid data values. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase4 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase4.ctl LOG=ulcase4.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- DISCARDFILE specifies a discard file named ulcase4.dsc. +-- +-- DISCARDMAX specifies a maximum of 999 discards allowed before +-- terminating the run. For all practical purposes, this allows +-- all discards for this test case. In real-world situations, +-- there may well be more than 999 discarded records. +-- +-- REPLACE specifies that if there is data in the table being loaded, +-- then SQL*Loader should delete that data before loading new data. +-- +-- CONTINUEIF specifies that if an asterisk is found in column 1 +-- of the current record, then the next physical record after that +-- record should be appended to it from the logical record. Note that +-- column 1 in each physical record should then contain either an +-- asterisk or a nondata value. +-- +-- The data file (ulcase4.dat) for this case study shows asterisks +-- in the first position and, though not visible, a newline character +-- is in position 20. Note that clark's commission is -10, and +-- SQL*Loader loads the value, converting it to a negative number. +-- +-- The resulting log file will show that the last two records are +-- rejected, given two assumptions. If a unique index is created on +-- column empno, then the record for chin will be rejected because +-- his empno is identical to chan's. If empno is defined as NOT NULL, +-- then chen's record will be rejected because it has no value for +-- empno. + +-- +LOAD DATA +INFILE "ulcase4.dat" +DISCARDFILE "ulcase4.dsc" +DISCARDMAX 999 +REPLACE +CONTINUEIF (1) = '*' +INTO TABLE EMP + +( EMPNO POSITION(01:04) INTEGER EXTERNAL, + ENAME POSITION(06:15) CHAR, + JOB POSITION(17:25) CHAR, + MGR POSITION(27:30) INTEGER EXTERNAL, + SAL POSITION(32:39) DECIMAL EXTERNAL, + COMM POSITION(41:48) DECIMAL EXTERNAL, + DEPTNO POSITION(50:51) INTEGER EXTERNAL, + HIREDATE POSITION(52:60) INTEGER EXTERNAL) diff --git a/ulcase4.dat b/ulcase4.dat new file mode 100644 index 0000000..6696bb0 --- /dev/null +++ b/ulcase4.dat @@ -0,0 +1,18 @@ +*7782 CLARK MA + NAGER 7839 2572.50 -10 2512-NOV-85 +*7839 KING PR + ESIDENT 5500.00 2505-APR-83 +*7934 MILLER CL + ERK 7782 920.00 2508-MAY-80 +*7566 JONES MA + NAGER 7839 3123.75 2517-JUL-85 +*7499 ALLEN SA + LESMAN 7698 1600.00 300.00 25 3-JUN-84 +*7654 MARTIN SA + LESMAN 7698 1312.50 1400.00 2521-DEC-85 +*7658 CHAN AN + ALYST 7566 3450.00 2516-FEB-84 +* CHEN AN + ALYST 7566 3450.00 2516-FEB-84 +*7658 CHIN AN + ALYST 7566 3450.00 2516-FEB-84 diff --git a/ulcase4.sql b/ulcase4.sql new file mode 100644 index 0000000..b1b0ac5 --- /dev/null +++ b/ulcase4.sql @@ -0,0 +1,37 @@ +rem +rem $Header: ulcase4.sql 14-jul-99.14:24:22 mjaeger Exp $ +rem +rem Copyright (c) 1990, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem +rem FUNCTION +rem NOTES +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem ksudarsh 03/11/93 - comment out vms specific host command +rem ksudarsh 12/29/92 - Creation +rem cheigham 08/28/91 - Creation +rem Heigham 11/21/90 - create UNIQUE index +rem + +set termout off + +rem host write sys$output "Building case 4 demonstration tables. Please wait" + +drop table emp; + +create table emp + (empno number(4) not null, + ename char(10), + job char(9), + mgr number(4), + hiredate date, + sal number(7,2), + comm number(7,2), + deptno number(2)); + +create unique index empix on emp(empno); + +exit diff --git a/ulcase5.ctl b/ulcase5.ctl new file mode 100644 index 0000000..34c550d --- /dev/null +++ b/ulcase5.ctl @@ -0,0 +1,72 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase5.ctl - SQL*Loader Case Study 5: Loading Data Into Multiple Tables +-- DESCRIPTION +-- This case study demonstrates the following: +-- Loading multiple tables. +-- +-- Using SQL*Loader to break down repeating groups in a flat file +-- and to load the data into normalized tables. In this way, one +-- file record may generate multiple database rows. +-- +-- Deriving multiple logical records from each physical record. +-- +-- Using a WHEN clause. +-- +-- Loading the same field (empno) into multiple tables. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase5 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase5.ctl LOG=ulcase5.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- REPLACE specifies that if there is data in the tables to be +-- loaded (emp and proj), SQL*loader should delete the data before +-- loading new rows. +-- +-- Multiple INTO TABLE clauses load two tables, emp and proj. +-- The same set of records is processed three times, using different +-- combinations of columns each time to load table proj. +-- +-- WHEN loads only rows with nonblank project numbers. When projno +-- is defined as columns 25...27, rows are inserted into proj only +-- if there is a value in those columns. +-- +-- When projno is defined as columns 29...31, rows are inserted +-- into proj only if there is a value in those columns. +-- +-- When projno is defined as columns 33...35, rows are inserted +-- into proj only if there is a value in those columns. +-- +LOAD DATA +INFILE 'ulcase5.dat' +BADFILE 'ulcase5.bad' +DISCARDFILE 'ulcase5.dsc' +REPLACE + +INTO TABLE EMP + (EMPNO POSITION(1:4) INTEGER EXTERNAL, + ENAME POSITION(6:15) CHAR, + DEPTNO POSITION(17:18) CHAR, + MGR POSITION(20:23) INTEGER EXTERNAL) + +INTO TABLE PROJ +-- PROJ has two columns, both not null: EMPNO and PROJNO +WHEN PROJNO != ' ' + (EMPNO POSITION(1:4) INTEGER EXTERNAL, + PROJNO POSITION(25:27) INTEGER EXTERNAL) -- 1st proj + +INTO TABLE PROJ +WHEN PROJNO != ' ' + (EMPNO POSITION(1:4) INTEGER EXTERNAL, + PROJNO POSITION(29:31) INTEGER EXTERNAL) -- 2nd proj + +INTO TABLE PROJ +WHEN PROJNO != ' ' + (EMPNO POSITION(1:4) INTEGER EXTERNAL, + PROJNO POSITION(33:35) INTEGER EXTERNAL) -- 3rd proj diff --git a/ulcase5.dat b/ulcase5.dat new file mode 100644 index 0000000..2da50bb --- /dev/null +++ b/ulcase5.dat @@ -0,0 +1,12 @@ +1234 BAKER 10 9999 101 102 103 +1234 JOKER 10 9999 777 888 999 +2664 YOUNG 20 2893 425 abc 102 +5321 OTOOLE 10 9999 321 55 40 +2134 FARMER 20 4555 236 456 +2414 LITTLE 20 5634 236 456 40 +6542 LEE 10 4532 102 321 14 +2849 EDDS xx 4555 294 40 +4532 PERKINS 10 9999 40 +1244 HUNT 11 3452 665 133 456 + 123 DOOLITTLE 12 9940 132 +1453 MACDONALD 25 5532 200 diff --git a/ulcase5.sql b/ulcase5.sql new file mode 100644 index 0000000..a15e56d --- /dev/null +++ b/ulcase5.sql @@ -0,0 +1,47 @@ +rem +rem $Header: ulcase5.sql 20-jul-99.18:06:21 cmlim Exp $ +rem +rem Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase5.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +Rem cmlim 07/20/99 - add unique index on empno +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem ksudarsh 03/11/93 - comment out vms specific host command +rem ksudarsh 12/29/92 - Creation +rem cheigham 08/28/91 - Creation +rem + +set termout off + +rem host write sys$output "Building case 5 demonstration tables. Please wait" + +drop table emp; + +drop table proj; + +create table emp + (empno number(4) not null, + ename char(10), + job char(9), + mgr number(4), + hiredate date, + sal number(7,2), + comm number(7,2), + deptno number(2)); + +create unique index empix on emp(empno); + +create table proj + (empno number, + projno number); + +exit diff --git a/ulcase6.ctl b/ulcase6.ctl new file mode 100644 index 0000000..0709b7f --- /dev/null +++ b/ulcase6.ctl @@ -0,0 +1,47 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase6.ctl - SQL*Loader Case Study 6: Loading Data Using the +-- Direct Path Load Method +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- Use of the direct path load method to load and index data. +-- +-- How to specify the indexes for which the data is presorted. +-- +-- Use of the NULLIF clause. +-- +-- Loading all-blank numeric fields as NULL. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase6 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase6.ctl LOG=ulcase6.log DIRECT=TRUE +-- +-- NOTES ABOUT THIS CONTROL FILE +-- The SORTED INDEXES statement identifies the indexes on which +-- the data is sorted. This statement indicates that the datafile +-- is sorted on the columns in the empix index. It allows +-- SQL*Loader to optimize index creation by eliminating the sort +-- phase for this data when using the direct path load method. +-- +-- The NULLIF...BLANKS clause specifies that the column should +-- be loaded as NULL if the field in the datafile consists of +-- all blanks. +-- +LOAD DATA +INFILE 'ulcase6.dat' +REPLACE +INTO TABLE emp +SORTED INDEXES (empix) +(empno POSITION(1:4), +ename POSITION(6:15), +job POSITION(17:25), +mgr POSITION(27:30) NULLIF mgr=blanks, +sal POSITION(32:39) NULLIF sal=blanks, +comm POSITION(41:48) NULLIF comm=blanks, +deptno POSITION(50:51) NULLIF empno=blanks) diff --git a/ulcase6.dat b/ulcase6.dat new file mode 100644 index 0000000..82ebd9e --- /dev/null +++ b/ulcase6.dat @@ -0,0 +1,7 @@ +7499 ALLEN SALESMAN 7698 1600.00 300.00 30 +7566 JONES MANAGER 7839 3123.75 20 +7654 MARTIN SALESMAN 7698 1312.50 1400.00 30 +7658 CHAN ANALYST 7566 3450.00 20 +7782 CLARK MANAGER 7839 2572.50 10 +7839 KING PRESIDENT 5500.00 10 +7934 MILLER CLERK 7782 920.00 10 diff --git a/ulcase6.sql b/ulcase6.sql new file mode 100644 index 0000000..3322af1 --- /dev/null +++ b/ulcase6.sql @@ -0,0 +1,41 @@ +rem +rem $Header: ulcase6.sql 14-jul-99.14:25:48 mjaeger Exp $ +rem +rem Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase6.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem ksudarsh 02/21/94 - create unique index "empix" +rem ksudarsh 03/11/93 - comment out vms specific host command +rem ksudarsh 12/29/92 - Creation +rem ksudarsh 12/28/92 - Don't drop dept +rem cheigham 08/28/91 - Creation +rem cheigham 03/19/91 - Creation + +set termout off +rem host write sys$output "Building case 6 demonstration tables. Please wait" + +drop table emp; + +create table emp + (empno number(4) not null, + ename char(10), + job char(9), + mgr number(4), + hiredate date, + sal number(7,2), + comm number(7,2), + deptno number(2)); + +create unique index empix on emp(empno); + +exit diff --git a/ulcase7.ctl b/ulcase7.ctl new file mode 100644 index 0000000..412cf59 --- /dev/null +++ b/ulcase7.ctl @@ -0,0 +1,104 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase7.ctl - Extracting Data From a Formatted Report +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- Use of SQL*Loader with an INSERT trigger. +-- +-- Use of the SQL string to manipulate data. +-- +-- Use of different initial and trailing delimiters. +-- +-- Use of SYSDATE. +-- +-- Use of the TRAILING NULLCOLS clause. +-- +-- Ambiguous field length warnings. +-- +-- Use of a discard file. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase7s to execute the SQL script for +-- this case study. This creates a BEFORE INSERT trigger that +-- is required to fill in the department number, job name, +-- and manager's number when these fields are not present on +-- a data line. When values are present, they should be saved +-- in a global variable. When values are not present, the +-- global variables are used. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase7.ctl LOG=ulcase7.log +-- +-- 3. After you have run the case study and finished with it, you +-- must run the ulcase7e.sql script before you can successfully +-- run other case studies. This script drops the INSERT trigger +-- and the global variables package. Log in to SQL*Plus as +-- scott/tiger. Enter @ulcase7e. +-- +-- NOTES ABOUT THIS CONTROL FILE +-- The WHEN (57) = '.' clause indicates that the decimal point +-- in column 57 (the salary field) identifies a line with data +-- on it. All other lines in the report are discarded. +-- +-- The TRAILING NULLCOLS clause causes SQL*Loader to treat any fields +-- that are missing at the end of a record as null. Because the +-- commission field is not present for every record, this clause says +-- to load a null commission instead of rejecting the record when only +-- seven fields are found instead of the expected eight. +-- +-- The hiredate is filled in using the current system date (SYSDATE). +-- +-- The specification for deptno will generate a warning message in +-- the log file because the specified length does not agree with +-- the length determined by the field's position. The specified +-- length (3) is used. The length is in bytes with the default +-- byte-length semantics. If character-length semantics were used +-- instead, this length would be in characters. +-- +-- The NULLIF clause says that because the report shows only department +-- number, job, and manager when the value changes, these fields may +-- be blank. This control file causes them to be loaded as null, and +-- an insert trigger fills in the last valid value. +-- +-- For the job field, the SQL string changes the job name to +-- uppercase letters. +-- +-- For the mgr field, it is necessary to specify starting position. +-- If the job field and the manager field were both blank, then the +-- job field's TERMINATED BY WHITESPACE clause would cause SQL*Loader +-- to scan forward to the employee name field. Without the POSITION +-- clause, the employee name field would be mistakenly interpreted +-- as the manager field. +-- +-- For the sal field, the SQL string translates the field from a +-- formatted character string into a number. The numeric value takes +-- less space and can be printed with a variety of formatting options. +-- +-- For the comm field, different initial and trailing delimiters pick the +-- numeric value out of a formatted field. The SQL string then converts +-- the value to its stored form. +-- +LOAD DATA +INFILE 'ulcase7.dat' +DISCARDFILE 'ulcase7.dsc' +APPEND +INTO TABLE emp + WHEN (57)='.' + TRAILING NULLCOLS + (hiredate SYSDATE, + deptno POSITION(1:2) INTEGER EXTERNAL(3) + NULLIF deptno=BLANKS, + job POSITION(7:14) CHAR TERMINATED BY WHITESPACE + NULLIF job=BLANKS "UPPER(:job)", + mgr POSITION(28:31) INTEGER EXTERNAL TERMINATED BY WHITESPACE + NULLIF mgr=BLANKS, + ename POSITION (34:41) CHAR TERMINATED BY WHITESPACE + "UPPER(:ename)", + empno INTEGER EXTERNAL TERMINATED BY WHITESPACE, + sal POSITION(51) CHAR TERMINATED BY WHITESPACE + "TO_NUMBER(:sal,'$99,999.99')", + comm INTEGER EXTERNAL ENCLOSED BY '(' AND '%' + ":comm * 100" + ) diff --git a/ulcase7.dat b/ulcase7.dat new file mode 100644 index 0000000..7b5188f --- /dev/null +++ b/ulcase7.dat @@ -0,0 +1,13 @@ + + + Today's Newly Hired Employees + +Dept Job Manager MgrNo Emp Name EmpNo Salary/Commission +---- -------- -------- ----- -------- ----- ----------------- +20 Salesman Blake 7698 Shepard 8061 $1,600.00 (3%) + Falstaff 8066 $1,250.00 (5%) + Major 8064 $1,250.00 (14%) + +30 Clerk Scott 7788 Conrad 8062 $1,100.00 + Ford 7369 DeSilva 8063 $800.00 + Manager King 7839 Provo 8065 $2,975.00 diff --git a/ulcase7e.sql b/ulcase7e.sql new file mode 100644 index 0000000..584453c --- /dev/null +++ b/ulcase7e.sql @@ -0,0 +1,30 @@ +rem +rem $Header: ulcase7e.sql 14-jul-99.14:26:51 mjaeger Exp $ +rem +rem Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase7e.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem ksudarsh 03/11/93 - comment out vms specific host command +rem ksudarsh 12/30/92 - Creation +rem ksudarsh 12/27/92 - Creation +rem +rem ULDEMO7E.SQL +rem End-script for SQL*Loader Examples, Case 7 + +set termout off +rem host write sys$output "Cleaning up Case 7 Trigger and Package." + +DROP PACKAGE uldemo7; +DROP TRIGGER uldemo7_emp_insert; + +EXIT diff --git a/ulcase7s.sql b/ulcase7s.sql new file mode 100644 index 0000000..48173cf --- /dev/null +++ b/ulcase7s.sql @@ -0,0 +1,68 @@ +rem +rem $Header: ulcase7s.sql 26-jul-99.09:39:37 mjaeger Exp $ +rem +rem Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase7s.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/26/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem ksudarsh 03/11/93 - comment out vms specific host command +rem ksudarsh 12/30/92 - Creation +rem ksudarsh 12/27/92 - Creation +rem +rem ULDEMO7S.SQL +rem Start-script for SQL*Loader Examples, Case 7 + +rem The variables the insert-trigger uses to save the last valid value +rem are defined in a package so they will persist between calls. + +rem Since these values will be accessed by anyone inserting into EMP, only +rem the user doing the load should have access to EMP during this time +rem (Alternatively, the trigger could be modified to check the USERENV fnction +rem in a WHEN clause and only perform its functions for a particular user.) + +set termout off +rem host write sys$output "Building Package and Trigger for Case 7.Please wait" + +CREATE OR REPLACE PACKAGE uldemo7 AS + last_deptno NUMBER; + last_job CHAR(9); + last_mgr NUMBER; +END uldemo7; +/ + +CREATE OR REPLACE TRIGGER uldemo7_emp_insert + BEFORE INSERT ON emp + FOR EACH ROW + + BEGIN + IF :new.deptno IS NOT NULL THEN + uldemo7.last_deptno := :new.deptno; -- save value for later use + ELSE + :new.deptno := uldemo7.last_deptno; -- use last valid value + END IF; + + IF :new.job IS NOT NULL THEN + uldemo7.last_job := :new.job; -- save value for later use + ELSE + :new.job := uldemo7.last_job; -- use last valid value + END IF; + + IF :new.mgr IS NOT NULL THEN + uldemo7.last_mgr := :new.mgr; -- save value for later use + ELSE + :new.mgr := uldemo7.last_mgr; -- use last valid value + END IF; + + END; +/ + +EXIT diff --git a/ulcase8.ctl b/ulcase8.ctl new file mode 100644 index 0000000..d984c50 --- /dev/null +++ b/ulcase8.ctl @@ -0,0 +1,53 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase8.ctl - SQL*Loader Case Study 8: Loading Partitioned Tables +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- Partitioning of data. +-- +-- Explicitly defined field positions and datatypes. +-- +-- Loading data using the fixed-record-length option. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase8 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase8.ctl LOG=ulcase8.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- This control file loads the lineitem table with fixed-length +-- records, partitioning the data according to shipment date. +-- +-- The INFILE clause specifies that each record in the datafile is +-- of fixed length (129 bytes in this example). +-- +-- The PARTITION clause identifies the column name and location of the +-- data in the datafile to be loaded into each column. +-- +LOAD DATA + INFILE 'ulcase8.dat' "fix 129" +BADFILE 'ulcase8.bad' +TRUNCATE +INTO TABLE lineitem +PARTITION (ship_q1) + (l_orderkey position (1:6) char, + l_partkey position (7:11) char, + l_suppkey position (12:15) char, + l_linenumber position (16:16) char, + l_quantity position (17:18) char, + l_extendedprice position (19:26) char, + l_discount position (27:29) char, + l_tax position (30:32) char, + l_returnflag position (33:33) char, + l_linestatus position (34:34) char, + l_shipdate position (35:43) char, + l_commitdate position (44:52) char, + l_receiptdate position (53:61) char, + l_shipinstruct position (62:78) char, + l_shipmode position (79:85) char, + l_comment position (86:128) char) diff --git a/ulcase8.dat b/ulcase8.dat new file mode 100644 index 0000000..ba7b258 --- /dev/null +++ b/ulcase8.dat @@ -0,0 +1,10 @@ + 1 151978511724386.60 7.04.0NO09-SEP-6412-FEB-9622-MAR-96DELIVER IN PERSONTRUCK iPBw4mMm7w7kQ zNPL i261OPP + 1 2731 73223658958.28.09.06NO12-FEB-9628-FEB-9620-APR-96TAKE BACK RETURN MAIL 5wM04SNyl0AnghCP2nx lAi + 1 3370 3713 810210.96 .1.02NO29-MAR-9605-MAR-9631-JAN-96TAKE BACK RETURN REG AIRSQC2C 5PNCy4mM + 1 5214 46542831197.88.09.06NO21-APR-9630-MAR-9616-MAY-96NONE AIR Om0L65CSAwSj5k6k + 1 6564 6763246897.92.07.02NO30-MAY-9607-FEB-9603-FEB-96DELIVER IN PERSONMAIL CB0SnyOL PQ32B70wB75k 6Aw10m0wh + 1 7403 160524 31329.6 .1.04NO30-JUN-9614-MAR-9601 APR-96NONE FOB C2gOQj OB6RLk1BS15 igN + 2 8819 82012441659.44 0.08NO05-AUG-9609-FEB-9711-MAR-97COLLECT COD AIR O52M70MRgRNnmm476mNm + 3 9451 721230 41113.5.05.01AF05-SEP-9629-DEC-9318-FEB-94TAKE BACK RETURN FOB 6wQnO0Llg6y + 3 9717 1834440788.44.07.03RF09-NOV-9623-DEC-9315-FEB-94TAKE BACK RETURN SHIP LhiA7wygz0k4g4zRhMLBAM + 3 9844 1955 6 8066.64.04.01RF28-DEC-9615-DEC-9314-FEB-94TAKE BACK RETURN REG AIR6nmBmjQkgiCyzCQBkxPPOx5j4hB 0lRywgniP1297 diff --git a/ulcase8.sql b/ulcase8.sql new file mode 100644 index 0000000..2734cd6 --- /dev/null +++ b/ulcase8.sql @@ -0,0 +1,58 @@ +rem +Rem $Header: ulcase8.sql 20-jul-99.18:20:38 cmlim Exp $ +rem +rem ulcase8.sql +rem +rem Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase8.sql - Setup for SQL Loader example 8 +rem +rem DESCRIPTION +rem Create partitioned table for example 8 +rem +rem NOTES +rem Note that all partitions are created in the default tablespace. +rem Normally, each partition would be in a saparate tablespace, but we +rem use the same tablespace to keep the example simple. +rem +rem MODIFIED (MM/DD/YY) +Rem cmlim 07/20/99 - fix syntax for create table +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem jstenois 11/06/98 - example of loading fix record length file +rem jstenois 11/06/98 - Created +rem + +set termout off + +rem host write sys$output "Building case 8 demonstration tables. Please wait" + +drop table lineitem; + +create table lineitem +(l_orderkey number, +l_partkey number, +l_suppkey number, +l_linenumber number, +l_quantity number, +l_extendedprice number, +l_discount number, +l_tax number, +l_returnflag char, +l_linestatus char, +l_shipdate date, +l_commitdate date, +l_receiptdate date, +l_shipinstruct char(17), +l_shipmode char(7), +l_comment char(43)) +partition by range (l_shipdate) +( +partition ship_q1 values less than (TO_DATE('01-APR-1996', 'DD-MON-YYYY')), +partition ship_q2 values less than (TO_DATE('01-JUL-1996', 'DD-MON-YYYY')), +partition ship_q3 values less than (TO_DATE('01-OCT-1996', 'DD-MON-YYYY')), +partition ship_q4 values less than (TO_DATE('01-JAN-1997', 'DD-MON-YYYY')) +); + +exit diff --git a/ulcase9.ctl b/ulcase9.ctl new file mode 100644 index 0000000..3f7de41 --- /dev/null +++ b/ulcase9.ctl @@ -0,0 +1,66 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase9.ctl - SQL*Loader Case Study 9: Loading LOBFILEs (CLOBs) +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- Adding a CLOB column called resume to table emp. +-- +-- Using a filler field (res_file). +-- +-- Loading multiple LOBFILEs into the emp table. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase9 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase9.ctl LOG=ulcase9.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- This is an example of using SQL Loader to load LOBs from +-- secondary data file. +-- +-- There is one file per resume (the "TERMINATED BY EOF" clause +-- indicates this) and the name of the file containing the resume +-- is in field res_file. +-- +-- res_file is a filler field. The filler field is assigned values +-- from the data field to which it is mapped. This means that the +-- file name stored in the field is not loaded into any field in +-- the table. +-- +-- The resume column is loaded as a CLOB. The LOBFILE function specifies +-- the field name in which the name of the file that contains data for +-- LOB field is provided. +-- +-- The field name for column RESUME is in quotation marks because +-- RESUME is also a keyword for SQL*Loader. The quotation marks force +-- SQL*Loader to treat it as a column name instead. +-- +LOAD DATA +INFILE * +INTO TABLE EMP +REPLACE +FIELDS TERMINATED BY ',' +( EMPNO INTEGER EXTERNAL, + ENAME CHAR, + JOB CHAR, + MGR INTEGER EXTERNAL, + SAL DECIMAL EXTERNAL, + COMM DECIMAL EXTERNAL, + DEPTNO INTEGER EXTERNAL, + RES_FILE FILLER CHAR, + "RESUME" LOBFILE (RES_FILE) TERMINATED BY EOF NULLIF RES_FILE = 'NONE' +) + +BEGINDATA +7782,CLARK,MANAGER,7839,2572.50,,10,ulcase91.dat +7839,KING,PRESIDENT,,5500.00,,10,ulcase92.dat +7934,MILLER,CLERK,7782,920.00,,10,ulcase93.dat +7566,JONES,MANAGER,7839,3123.75,,20,ulcase94.dat +7499,ALLEN,SALESMAN,7698,1600.00,300.00,30,ulcase95.dat +7654,MARTIN,SALESMAN,7698,1312.50,1400.00,30,ulcase96.dat +7658,CHAN,ANALYST,7566,3450.00,,20,NONE diff --git a/ulcase9.sql b/ulcase9.sql new file mode 100644 index 0000000..363e0da --- /dev/null +++ b/ulcase9.sql @@ -0,0 +1,41 @@ +rem +rem $Header: ulcase9.sql 14-jul-99.14:28:05 mjaeger Exp $ +rem +rem ulcase9.sql +rem +rem Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase9.sql - setup for SQL Loader example 9 +rem +rem DESCRIPTION +rem Add RESUME column to EMP for example of using SQL Loader to load LOBs +rem +rem NOTES +rem Assumes an EMP table already exists +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem jstenois 10/26/98 - demo of 8.1 features for sqlldr +rem jstenois 10/26/98 - Created +rem + +set termout off + +rem host write sys$output "Building case 9 demonstration tables. Please wait" + +drop table emp; + +create table emp + (empno number(4) not null, + ename char(10), + job char(9), + mgr number(4), + hiredate date, + sal number(7,2), + comm number(7,2), + deptno number(2), + resume clob); + +exit diff --git a/ulcase91.dat b/ulcase91.dat new file mode 100644 index 0000000..1e0e5ad --- /dev/null +++ b/ulcase91.dat @@ -0,0 +1,14 @@ + Resume for Mary Clark + +Career Objective: Manage a sales team with consistent record breaking + performance. + +Education: BA Business University of Iowa 1992 + +Experience: 1992-1994 - Sales Support at MicroSales Inc. + Won "Best Sales Support" award in 1993 and 1994 + + 1994-Present - Sales Manager at MicroSales Inc. + Most sales in mid-South division for 2 years + + diff --git a/ulcase92.dat b/ulcase92.dat new file mode 100644 index 0000000..3cb4e3a --- /dev/null +++ b/ulcase92.dat @@ -0,0 +1,23 @@ + Resume for Monica King + +Career Objective: President of large computer services company + +Education: BA English Literature Bennington, 1985 + +Experience: 1985-1986 - Mailroom at New World Services + + 1986-1987 - Secretary for sales management at New World + Services + + 1988-1989 - Sales support at New World Services + + 1990-1992 - Saleman at New World Services + + 1993-1994 - Sales Manager at New World Services + + 1995 - Vice President of Sales and Marketing at New + World Services + + 1996-Present - President of New World Services + + diff --git a/ulcase93.dat b/ulcase93.dat new file mode 100644 index 0000000..4d94cd9 --- /dev/null +++ b/ulcase93.dat @@ -0,0 +1,7 @@ + Resume for Dan Miller + +Career Objective: Work as a sales support specialist for a services company + +Education: Plainview High School, 1996 + +Experience: 1996 - Present: Mail room clerk at New World Services diff --git a/ulcase94.dat b/ulcase94.dat new file mode 100644 index 0000000..cc0b62a --- /dev/null +++ b/ulcase94.dat @@ -0,0 +1,15 @@ + Resume for Alyson Jones + +Career Objective: Work in senior sales management for a vibrant and + growing company + +Education: BA Philosophy Howard Univerity 1993 + +Experience: 1993 - Sales Support for New World Services + + 1994-1995 - Salesman for New World Services. Led in US + sales in both 1994 and 1995. + + 1996 - present - Sales Manager New World Services. My sales + team has beat its quota by at least 15% each year. + diff --git a/ulcase95.dat b/ulcase95.dat new file mode 100644 index 0000000..f96d785 --- /dev/null +++ b/ulcase95.dat @@ -0,0 +1,10 @@ + Resume for David Allen + +Career Objective: Senior Sales man for agressive Services company + +Education: BS Business Administration, Weber State 1994 + +Experience: 1993-1994 - Sales Support New World Services + + 1994-present - Salesman at New World Service. Won sales award for + exceeding sales quota by over 20% in 1995, 1996. diff --git a/ulcase96.dat b/ulcase96.dat new file mode 100644 index 0000000..5eebe02 --- /dev/null +++ b/ulcase96.dat @@ -0,0 +1,8 @@ + Resume for Tom Martin + +Career Objective: Salesman for a computing service company + +Education: 1988 - BA Mathematics, University of the North + +Experience: 1988-1992 Sales Support, New World Services + 1993-present Salesman New World Services diff --git a/viewdemo.sql b/viewdemo.sql new file mode 100644 index 0000000..e6aad9b --- /dev/null +++ b/viewdemo.sql @@ -0,0 +1,177 @@ +rem +rem $Header: viewdemo.sql 12-aug-2004.06:18:09 rsriragh Exp $ +rem +rem Copyright (c) 1996, 2004, Oracle. All rights reserved. +rem +rem Owner : mchien +rem +rem NAME +rem viewdemo.sql - Oracle 8 demo of object views +rem +rem DESCRIPTON +rem This demo features Oracle8's object extensions to views, object views. +rem +rem MODIFIED (MM/DD/YY) +rem rsriragh 08/12/04 - fix order by diffs +rem hyeh 01/11/00 - enhance order by clause +rem hyeh 08/10/99 - use sqlplus syntax +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem yaggarwa 08/06/98 - Add New syntax +rem cchau 08/18/97 - enable dictionary protection +rem mchien 05/29/97 - fix type syntax +rem mchien 07/02/96 - born +rem +rem + +REMARK >>>> Set System Variables For Current SQLPlus Session <<<< +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET PAGESIZE 24 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET DEFINE '^' + +set echo on +set numwidth 6 +connect sys/knl_test7 as sysdba +grant connect,resource,dba to vrr1 identified by vrr1; + +connect vrr1/vrr1 + +REM create base tables + +CREATE TABLE department ( +deptno NUMBER(3), +dname VARCHAR2(20), +loc VARCHAR2(20), +CONSTRAINT pr1 primary key(deptno) +) partition BY RANGE (deptno) + (partition p1 VALUES less than (100), + partition p2 VALUES less than (200), + partition p3 VALUES less than (maxvalue) + ); + +CREATE TYPE dept_t AS OBJECT ( +deptno NUMBER(3), +dname VARCHAR2(20), +loc VARCHAR2(20)); +/ + +CREATE TABLE employee ( +empno NUMBER(4) PRIMARY KEY, +ename VARCHAR2(20), +job VARCHAR2(20), +deptno NUMBER(3), + CONSTRAINT fk1 FOREIGN KEY (deptno) REFERENCES department) -- foreign key + partition BY RANGE (empno) + (partition p1 VALUES less than (100), + partition p2 VALUES less than (200), + partition p3 VALUES less than (maxvalue) + ); + +insert into department select deptno, dname, loc from scott.dept; +insert into employee select empno, ename, job, deptno from scott.emp; +commit; + +----------------------------------------------------------------------. +REM Updatable views + +REM typed view + +CREATE VIEW dept_ext_view OF dept_t +WITH OBJECT OID (deptno) AS +SELECT d.deptno, d.dname, d.loc +FROM department d; + +REM view with ref view column + +CREATE VIEW emp_dept_view (empno, ename, job, edept) AS +SELECT empno, ename, job, MAKE_REF(dept_ext_view, deptno) +FROM employee; + +select * from user_updatable_columns + where table_name = 'DEPT_EXT_VIEW' order by 3; +select * from user_updatable_columns + where table_name = 'EMP_DEPT_VIEW' order by 3; + +REM now perform select, insert, update, delete on the views + +select * from dept_ext_view order by deptno; + +-- deref through pkref 'edept' +select empno, ename, job, + e.edept.deptno "DNO", e.edept.dname "DNAME", e.edept.loc "LOC" + from emp_dept_view e + order by empno; + +-- deref with distinct + +select distinct sys_op_dump(deref(edept)), empno from + emp_dept_view order by empno; + +-- deref through pkref 'edept' in where clause +select empno, ename, job, + ed.edept.deptno "DNO", ed.edept.dname "DNAME", ed.edept.loc "LOC" + from emp_dept_view ed, dept_ext_view de + where ed.edept.deptno = de.deptno + order by empno; + +-- deref through pkref 'edept' in order by clause +select empno, ename, job, + e.edept.deptno "DNO", e.edept.dname "DNAME", e.edept.loc "LOC" + from emp_dept_view e + order by e.edept.deptno, empno; + +-- deref through pkref 'edept' in group by clause +select e.edept.deptno, max(empno) + from emp_dept_view e + group by e.edept.deptno order by 1; + +----------------------------------------------------------------------. +-- now perform dml on updatable columns +insert into dept_ext_view values (100, 'LRT', 'Redwood City'); +insert into dept_ext_view values (200, 'ST', 'Redwood Shores'); +-- update oid - ok because no foreign key reference +update dept_ext_view set deptno = 0 where dname = 'LRT'; + +-- test for oid access optimization +select empno, ename, job, + ed.edept.deptno "DNO", ed.edept.dname "DNAME", ed.edept.loc "LOC" + from emp_dept_view ed, dept_ext_view de + where ref(de) = (ed.edept) + order by empno; + +select empno, ename, job, + ed.edept.deptno "DNO", ed.edept.dname "DNAME", ed.edept.loc "LOC" + from emp_dept_view ed, dept_ext_view de + where ref(de) = (ed.edept) and ref(de) is not null + order by empno; + +select empno, ename, job, + ed.edept.deptno "DNO", ed.edept.dname "DNAME", ed.edept.loc "LOC" + from emp_dept_view ed, dept_ext_view de + where ref(de) = (ed.edept) or ref(de) is null + order by empno; + +-- update oid - fail because foreign key reference +update dept_ext_view set deptno = 99 where dname = 'SALES'; +commit; + +select sys_op_dump(value(p)) from dept_ext_view p + order by 1; +select sys_op_dump(deref(ref(p))) from dept_ext_view p + order by 1; + +insert into emp_dept_view (empno, ename, job) + values (1234, 'John Doe', 'manager'); +commit; + +select empno, ename, job, reftohex(edept) + from emp_dept_view + where empno = 1234 + order by empno; + +connect sys/knl_test7 as sysdba +drop user vrr1 cascade; +set echo off diff --git a/xademo1.sql b/xademo1.sql new file mode 100644 index 0000000..256c852 --- /dev/null +++ b/xademo1.sql @@ -0,0 +1,121 @@ +Rem +Rem $Header: xademo1.sql 30-nov-2005.00:34:26 yohu Exp $ +Rem +Rem xademo1.sql +Rem +Rem Copyright (c) 2005, Oracle. All rights reserved. +Rem +Rem NAME +Rem xademo1.sql - XA PL/SQL APIs demo 1 +Rem +Rem DESCRIPTION +Rem This demo program illustrates how XA PL/SQL APIs may be used +Rem in programming PL/SQL procedures/functions. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem yohu 11/21/05 - yohu_xa_plsql +Rem yohu 10/26/05 - Created +Rem + +connect scott/tiger +set serveroutput on +CREATE or REPLACE PROCEDURE xa_demo(gtrid IN NUMBER, op IN VARCHAR2, + emp_no IN NUMBER, e_name IN VARCHAR2) is + xid DBMS_XA_XID; + rc PLS_INTEGER; + oer PLS_INTEGER; + XAE exception; +BEGIN + xid := DBMS_XA_XID(gtrid); + + rc := dbms_xa.XA_START(xid, dbms_xa.TMNOFLAGS); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_start failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_START okay'); + END IF; + + CASE + WHEN op = 'add' THEN + INSERT INTO emp(empno, ename, sal) VALUES(emp_no, e_name, 1111); + WHEN op = 'del' THEN + DELETE FROM emp where empno = emp_no AND ename = e_name; + WHEN op = 'inc' THEN + UPDATE emp SET sal=sal+1 WHERE empno = emp_no AND ename = e_name; + ELSE + BEGIN + dbms_output.put_line('Unknown op code!'); + RAISE XAE; + END; + END CASE; + + rc := dbms_xa.XA_END(xid, dbms_xa.TMSUCCESS); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_end failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_END okay'); + END IF; + + rc := dbms_xa.XA_PREPARE(xid); + IF rc=dbms_xa.XA_OK THEN + dbms_output.put_line('XA_PREPARE okay'); + + rc := dbms_xa.XA_COMMIT(xid, FALSE); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_commit failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_COMMIT okay'); + END IF; + + ELSIF rc=dbms_xa.XA_RDONLY THEN + dbms_output.put_line('XA_PREPARE readonly'); + ELSE + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_prepare failed!'); + raise XAE; + END IF; +EXCEPTION + WHEN OTHERS THEN + dbms_output.put_line('XA error('||rc|| + ') occured, rolling back the transaction...'); + rc := dbms_xa.XA_END(xid, dbms_xa.TMSUCCESS); + rc := dbms_xa.XA_ROLLBACK(xid); + IF rc != dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('XA-'||rc||', ORA-' || oer || + ' xa_rollback does not return XA_OK!'); + raise_application_error(-20001, 'ORA-'||oer|| + ' error in rolling back a failed transaction!'); + END IF; + raise_application_error(-20002, 'ORA-'||oer|| + ' error in transaction processing, transction rolled back!'); +END; +/ +show errors + +REM sample usage: + +BEGIN xa_demo(111, 'add', 1234, 'xa_demo1'); END; +/ +Rem the following rollback should be a noop +ROLLBACK; +select empno,ename,sal from emp where empno=1234 and ename='xa_demo1'; + +BEGIN xa_demo(222, 'inc', 1234, 'xa_demo1'); END; + / +Rem the following rollback should be a noop +ROLLBACK; +select empno,ename,sal from emp where empno=1234 and ename='xa_demo1'; + +BEGIN xa_demo(333, 'del', 1234, 'xa_demo1'); END; +/ +select empno,ename,sal from emp where empno=1234 and ename='xa_demo1'; + +disconnect +quit diff --git a/xademo2.sql b/xademo2.sql new file mode 100644 index 0000000..2ae5ce0 --- /dev/null +++ b/xademo2.sql @@ -0,0 +1,154 @@ +Rem +Rem $Header: xademo2.sql 30-nov-2005.01:13:59 yohu Exp $ +Rem +Rem xademo2.sql +Rem +Rem Copyright (c) 2005, Oracle. All rights reserved. +Rem +Rem NAME +Rem xademo2.sql - XA PL/SQL API usage demo 2 +Rem +Rem DESCRIPTION +Rem This demo program illustrates how XA PL/SQL APIs may be used +Rem to have a single transaction working across sessions. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem yohu 11/21/05 - yohu_xa_plsql +Rem yohu 10/26/05 - Created +Rem + +Rem Session 1: starts a transaction and do some work + +connect scott/tiger +SET SERVEROUTPUT ON +DECLARE + rc PLS_INTEGER; + oer PLS_INTEGER; + XAE exception; +BEGIN + rc := dbms_xa.XA_START(DBMS_XA_XID(123), dbms_xa.TMNOFLAGS); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_start failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_START(new xid=123) okay'); + END IF; + + UPDATE emp SET sal=sal*1.1 WHERE empno = 7788; + + rc := dbms_xa.XA_END(DBMS_XA_XID(123), dbms_xa.TMSUSPEND); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_end failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_END(suspend xid=123) okay'); + END IF; +EXCEPTION + WHEN OTHERS THEN + dbms_output.put_line('XA error('||rc|| + ') occured, rolling back the transaction...'); + rc := dbms_xa.XA_END(DBMS_XA_XID(123), dbms_xa.TMSUCCESS); + rc := dbms_xa.XA_ROLLBACK(DBMS_XA_XID(123)); + IF rc != dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('XA-'||rc||', ORA-' || oer || + ' xa_rollback does not return XA_OK!'); + raise_application_error(-20001, 'ORA-'||oer|| + ' error in rolling back a failed transaction!'); + END IF; + raise_application_error(-20002, 'ORA-'||oer|| + ' error in transaction processing, transction rolled back!'); +END; +/ +show errors +disconnect + + +Rem Session 2: resumes the transaction and do some work + +connect scott/tiger +SET SERVEROUTPUT ON +DECLARE + rc PLS_INTEGER; + oer PLS_INTEGER; + s NUMBER; + XAE exception; +BEGIN + rc := dbms_xa.XA_START(DBMS_XA_XID(123), dbms_xa.TMRESUME); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_start failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_START(resume xid=123) okay'); + END IF; + + SELECT sal INTO s FROM emp WHERE empno = 7788; + dbms_output.put_line('empno = 7788, sal = ' || s); + + rc := dbms_xa.XA_END(DBMS_XA_XID(123), dbms_xa.TMSUCCESS); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_end failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_END(detach xid=123) okay'); + END IF; +EXCEPTION + WHEN OTHERS THEN + dbms_output.put_line('XA error('||rc|| + ') occured, rolling back the transaction...'); + rc := dbms_xa.XA_END(DBMS_XA_XID(123), dbms_xa.TMSUCCESS); + rc := dbms_xa.XA_ROLLBACK(DBMS_XA_XID(123)); + IF rc != dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('XA-'||rc||', ORA-' || oer || + ' xa_rollback does not return XA_OK!'); + raise_application_error(-20001, 'ORA-'||oer|| + ' error in rolling back a failed transaction!'); + END IF; + raise_application_error(-20002, 'ORA-'||oer|| + ' error in transaction processing, transction rolled back!'); +END; +/ +show errors +disconnect + + +Rem Session 3: commit the transaction + +connect scott/tiger +SET SERVEROUTPUT ON +DECLARE + rc PLS_INTEGER; + oer PLS_INTEGER; + XAE exception; +BEGIN + rc := dbms_xa.XA_COMMIT(DBMS_XA_XID(123), TRUE); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_commit failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_COMMIT(commit xid=123) okay'); + END IF; + +EXCEPTION + WHEN XAE THEN + dbms_output.put_line('XA error('||rc|| + ') occured, rolling back the transaction...'); + rc := dbms_xa.XA_ROLLBACK(DBMS_XA_XID(123)); + IF rc != dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('XA-'||rc||', ORA-' || oer || + ' xa_rollback does not return XA_OK!'); + raise_application_error(-20001, 'ORA-'||oer|| + ' error in rolling back a failed transaction!'); + END IF; + raise_application_error(-20002, 'ORA-'||oer|| + ' error in transaction processing, transction rolled back!'); +END; +/ +show errors +disconnect +quit diff --git a/xmlgen1.sql b/xmlgen1.sql new file mode 100644 index 0000000..fc9f0bb --- /dev/null +++ b/xmlgen1.sql @@ -0,0 +1,302 @@ +Rem +Rem $Header: xmlgen1.sql 29-apr-2001.13:23:02 rbooredd Exp $ +Rem +Rem xmlgen1.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xmlgen1.sql - XML generation using DBMS_XMLGEN package +Rem +Rem DESCRIPTION +Rem This demo shows how to generate Purchase Order XML document +Rem from existing relational database using DBMS_XMLGEN package +Rem +Rem Object views are defined over relational tables to get data in +Rem canonical form. +Rem +Rem NOTES +Rem DBMS_XMLGEN Package maps UDT attributes names +Rem starting with '@' to xml attributes +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbooredd 04/29/01 - Merged rbooredd_xml_demo1 +Rem rbooredd 04/29/01 - +Rem rbooredd 04/27/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect system/manager +grant connect,resource to xmlgen1 identified by xmlgen1; +connect xmlgen1/xmlgen1; + +-- Purchase Order Object View Model + +-- PhoneList Varray object type +CREATE TYPE PhoneList_vartyp AS VARRAY(10) OF VARCHAR2(20) +/ + +-- Address object type +CREATE TYPE Address_typ AS OBJECT ( + Street VARCHAR2(200), + City VARCHAR2(200), + State CHAR(2), + Zip VARCHAR2(20) + ) +/ + +-- Customer object type +CREATE TYPE Customer_typ AS OBJECT ( + CustNo NUMBER, + CustName VARCHAR2(200), + Address Address_typ, + PhoneList PhoneList_vartyp +) +/ + + +-- StockItem object type +CREATE TYPE StockItem_typ AS OBJECT ( + "@StockNo" NUMBER, + Price NUMBER, + TaxRate NUMBER +) +/ + +-- LineItems object type +CREATE TYPE LineItem_typ AS OBJECT ( + "@LineItemNo" NUMBER, + Item StockItem_typ, + Quantity NUMBER, + Discount NUMBER + ) +/ +-- LineItems Nested table +CREATE TYPE LineItems_ntabtyp AS TABLE OF LineItem_typ +/ + +-- Purchase Order object type +CREATE TYPE PO_typ AUTHID CURRENT_USER AS OBJECT ( + "@PONO" NUMBER, + Cust_ref REF Customer_typ, + OrderDate DATE, + ShipDate TIMESTAMP, + LineItems_ntab LineItems_ntabtyp, + ShipToAddr Address_typ + ) +/ + +-- Create Purchase Order Relational Model tables + +--Customer table +CREATE TABLE Customer_tab( + CustNo NUMBER NOT NULL, + CustName VARCHAR2(200) , + Street VARCHAR2(200) , + City VARCHAR2(200) , + State CHAR(2) , + Zip VARCHAR2(20) , + Phone1 VARCHAR2(20), + Phone2 VARCHAR2(20), + Phone3 VARCHAR2(20), + constraint cust_pk PRIMARY KEY (CustNo) +) +ORGANIZATION INDEX OVERFLOW; + +-- Purchase Order table +CREATE TABLE po_tab ( + PONo NUMBER, /* purchase order no */ + Custno NUMBER constraint po_cust_fk references Customer_tab, + /* Foreign KEY referencing customer */ + OrderDate DATE, /* date of order */ + ShipDate TIMESTAMP, /* date to be shipped */ + ToStreet VARCHAR2(200), /* shipto address */ + ToCity VARCHAR2(200), + ToState CHAR(2), + ToZip VARCHAR2(20), + constraint po_pk PRIMARY KEY(PONo) +); + +--Stock Table +CREATE TABLE Stock_tab ( + StockNo NUMBER constraint stock_uk UNIQUE, + Price NUMBER, + TaxRate NUMBER +); + +--Line Items Table +CREATE TABLE LineItems_tab( + LineItemNo NUMBER, + PONo NUMBER constraint LI_PO_FK REFERENCES po_tab, + StockNo NUMBER , + Quantity NUMBER, + Discount NUMBER, + constraint LI_PK PRIMARY KEY (PONo, LineItemNo) +); + +-- create Object Views + +--Customer Object View +CREATE OR REPLACE VIEW Customer OF Customer_typ + WITH OBJECT IDENTIFIER(CustNo) + AS SELECT c.Custno, C.custname, + Address_typ(C.Street, C.City, C.State, C.Zip), + PhoneList_vartyp(Phone1, Phone2, Phone3) + FROM Customer_tab c; + +--Purchase order view +CREATE OR REPLACE VIEW PO OF PO_typ + WITH OBJECT IDENTIFIER ("@PONO") + AS SELECT P.PONo, + MAKE_REF(Customer, P.Custno), + P.OrderDate, + P.ShipDate, + CAST( MULTISET( + SELECT LineItem_typ( L.LineItemNo, + StockItem_typ(L.StockNo,S.Price,S.TaxRate), + L.Quantity, L.Discount) + FROM LineItems_tab L, Stock_tab S + WHERE L.PONo = P.PONo and S.StockNo=L.StockNo ) + AS LineItems_ntabtyp), + Address_typ(P.ToStreet,P.ToCity, P.ToState, P.ToZip) + FROM PO_tab P; + + + +-------------------- +-- Populate data +------------------- +-- Establish Inventory + +INSERT INTO Stock_tab VALUES(1004, 6750.00, 2) ; +INSERT INTO Stock_tab VALUES(1011, 4500.23, 2) ; +INSERT INTO Stock_tab VALUES(1534, 2234.00, 2) ; +INSERT INTO Stock_tab VALUES(1535, 3456.23, 2) ; + +-- Register Customers + +INSERT INTO Customer_tab + VALUES (1, 'Jean Nance', '2 Avocet Drive', + 'Redwood Shores', 'CA', '95054', + '415-555-1212', NULL, NULL) ; + +INSERT INTO Customer_tab + VALUES (2, 'John Nike', '323 College Drive', + 'Edison', 'NJ', '08820', + '609-555-1212', '201-555-1212', NULL) ; + +-- Place Orders + +INSERT INTO PO_tab + VALUES (1001, 1, SYSDATE, '10-MAY-1997', + NULL, NULL, NULL, NULL) ; + +INSERT INTO PO_tab + VALUES (2001, 2, SYSDATE, '20-MAY-1997', + '55 Madison Ave', 'Madison', 'WI', '53715') ; + +-- Detail Line Items + +INSERT INTO LineItems_tab VALUES(01, 1001, 1534, 12, 0) ; +INSERT INTO LineItems_tab VALUES(02, 1001, 1535, 10, 10) ; +INSERT INTO LineItems_tab VALUES(01, 2001, 1004, 1, 0) ; +INSERT INTO LineItems_tab VALUES(02, 2001, 1011, 2, 1) ; + +-------------------------------------------------- +-- create getXML wrapper function over DBMS_XMLGEN +-------------------------------------------------- +create or replace function getXML( sql_query varchar2, + rset_tag varchar2:='ROWSET', + rtag varchar2:='ROW') +return clob is + ctx number; + xmldoc sys.XMLType; +begin + ctx := DBMS_XMLGEN.newContext(sql_query); + + if (nvl(rset_tag,'X') != 'ROWSET') then + DBMS_XMLGEN.setRowSetTag(ctx,rset_tag); + end if; + + if (nvl(rtag,'Y') != 'ROW') then + DBMS_XMLGEN.setRowTag(ctx,rtag); + end if; + + xmldoc := DBMS_XMLGEN.getXMLType(ctx); + DBMS_XMLGEN.closeContext(ctx); + return xmldoc.getClobVal(); +exception + when others then + DBMS_XMLGEN.closeContext(ctx); + raise; +end; +/ +show error + +-- generate xml from any query using dbms_xmlgen package +set long 100000 + +select getXML('select "@PONO",lineitems_ntab lineitems,shiptoaddr + from po p') poxml +from dual; + + +------------------------------------------------------------ +-- Use DBMS_XMLGEN Package to generate each PO in XML format +-- and store XMLType in po_xml table +------------------------------------------------------------ + +-- create table with xmltype column to store po in XML format +create table po_xml( + XPO SYS.XMLType /* purchase order in XML format */ +) +/ + + +declare + qryCtx dbms_xmlgen.ctxHandle; + pxml SYS.XMLType; +begin + + -- get the query context; + qryCtx := dbms_xmlgen.newContext(' + select "@PONO",deref(cust_ref) customer,p.OrderDate,p.shipdate, + lineitems_ntab lineitems,shiptoaddr + from po p' + ); + + -- set the maximum number of rows to be 1, + dbms_xmlgen.setMaxRows(qryCtx, 1); + -- set rowset tag to null and row tag to PurchaseOrder + dbms_xmlgen.setRowSetTag(qryCtx,null); + dbms_xmlgen.setRowTag(qryCtx,'PurchaseOrder'); + + loop + -- now get the po in xml format + pxml := dbms_xmlgen.getXMLType(qryCtx); + + -- if there were no rows processed, then quit..! + exit when dbms_xmlgen.getNumRowsProcessed(qryCtx) = 0; + + -- Store XMLType po in po_xml table + insert into po_xml values(pxml); + end loop; + +end; +/ + +-- query po_xml table for generated POs in XML format +set long 100000 +select x.xpo.getClobVal() xpo +from po_xml x; + +-- cleanup +connect system/manager +drop user xmlgen1 cascade; diff --git a/xmlgen2.sql b/xmlgen2.sql new file mode 100644 index 0000000..1c97087 --- /dev/null +++ b/xmlgen2.sql @@ -0,0 +1,236 @@ +Rem +Rem $Header: xmlgen2.sql 29-apr-2001.13:23:03 rbooredd Exp $ +Rem +Rem xmlgen2.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xmlgen2.sql - XML generation using SYS_XMLGEN() and SYS_XMLAGG() +Rem +Rem DESCRIPTION +Rem This demo shows how to generate Purchase Order XML document +Rem from existing relational database using SYS_XMLGEN() and SYS_XMLAGG() +Rem SQL functions +Rem +Rem Object views are defined over relational tables to get data in +Rem canonical form. +Rem +Rem NOTES +Rem SYS_XMLGEN() maps UDT attributes names +Rem starting with '@' to xml attributes +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbooredd 04/29/01 - Merged rbooredd_xml_demo1 +Rem rbooredd 04/29/01 - +Rem rbooredd 04/27/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect system/manager +grant connect,resource to xmlgen2 identified by xmlgen2; +connect xmlgen2/xmlgen2; + +-- Purchase Order Object View Model + +-- PhoneList Varray object type +CREATE TYPE PhoneList_vartyp AS VARRAY(10) OF VARCHAR2(20) +/ + +-- Address object type +CREATE TYPE Address_typ AS OBJECT ( + Street VARCHAR2(200), + City VARCHAR2(200), + State CHAR(2), + Zip VARCHAR2(20) + ) +/ + +-- Customer object type +CREATE TYPE Customer_typ AS OBJECT ( + CustNo NUMBER, + CustName VARCHAR2(200), + Address Address_typ, + PhoneList PhoneList_vartyp +) +/ + + +-- StockItem object type +CREATE TYPE StockItem_typ AS OBJECT ( + "@StockNo" NUMBER, + Price NUMBER, + TaxRate NUMBER +) +/ + +-- LineItems object type +CREATE TYPE LineItem_typ AS OBJECT ( + "@LineItemNo" NUMBER, + Item StockItem_typ, + Quantity NUMBER, + Discount NUMBER + ) +/ +-- LineItems Nested table +CREATE TYPE LineItems_ntabtyp AS TABLE OF LineItem_typ +/ + +-- Purchase Order object type +CREATE TYPE PO_typ AUTHID CURRENT_USER AS OBJECT ( + "@PONO" NUMBER, + Customer Customer_typ, + OrderDate DATE, + ShipDate TIMESTAMP, + LineItems_ntab LineItems_ntabtyp, + ShipToAddr Address_typ + ) +/ + +-- Create Purchase Order Relational Model tables + +--Customer table +CREATE TABLE Customer_tab( + CustNo NUMBER NOT NULL, + CustName VARCHAR2(200) , + Street VARCHAR2(200) , + City VARCHAR2(200) , + State CHAR(2) , + Zip VARCHAR2(20) , + Phone1 VARCHAR2(20), + Phone2 VARCHAR2(20), + Phone3 VARCHAR2(20), + constraint cust_pk PRIMARY KEY (CustNo) +) +ORGANIZATION INDEX OVERFLOW; + +-- Purchase Order table +CREATE TABLE po_tab ( + PONo NUMBER, /* purchase order no */ + Custno NUMBER constraint po_cust_fk references Customer_tab, + /* Foreign KEY referencing customer */ + OrderDate DATE, /* date of order */ + ShipDate TIMESTAMP, /* date to be shipped */ + ToStreet VARCHAR2(200), /* shipto address */ + ToCity VARCHAR2(200), + ToState CHAR(2), + ToZip VARCHAR2(20), + constraint po_pk PRIMARY KEY(PONo) +); + +--Stock Table +CREATE TABLE Stock_tab ( + StockNo NUMBER constraint stock_uk UNIQUE, + Price NUMBER, + TaxRate NUMBER +); + +--Line Items Table +CREATE TABLE LineItems_tab( + LineItemNo NUMBER, + PONo NUMBER constraint LI_PO_FK REFERENCES po_tab, + StockNo NUMBER , + Quantity NUMBER, + Discount NUMBER, + constraint LI_PK PRIMARY KEY (PONo, LineItemNo) +); + +-- create Object Views +--Customer Object View +CREATE OR REPLACE VIEW Customer OF Customer_typ + WITH OBJECT IDENTIFIER(CustNo) + AS SELECT c.Custno, C.custname, + Address_typ(C.Street, C.City, C.State, C.Zip), + PhoneList_vartyp(Phone1, Phone2, Phone3) + FROM Customer_tab c; + +--Purchase order view +CREATE OR REPLACE VIEW PO OF PO_typ + WITH OBJECT IDENTIFIER ("@PONO") + AS SELECT P.PONo, + Customer_typ(P.Custno,C.CustName,C.Address,C.PhoneList), + P.OrderDate, + P.ShipDate, + CAST( MULTISET( + SELECT LineItem_typ( L.LineItemNo, + StockItem_typ(L.StockNo,S.Price,S.TaxRate), + L.Quantity, L.Discount) + FROM LineItems_tab L, Stock_tab S + WHERE L.PONo = P.PONo and S.StockNo=L.StockNo ) + AS LineItems_ntabtyp), + Address_typ(P.ToStreet,P.ToCity, P.ToState, P.ToZip) + FROM PO_tab P, Customer C + WHERE P.CustNo=C.custNo; + + + +-------------------- +-- Populate data +------------------- +-- Establish Inventory + +INSERT INTO Stock_tab VALUES(1004, 6750.00, 2) ; +INSERT INTO Stock_tab VALUES(1011, 4500.23, 2) ; +INSERT INTO Stock_tab VALUES(1534, 2234.00, 2) ; +INSERT INTO Stock_tab VALUES(1535, 3456.23, 2) ; + +-- Register Customers + +INSERT INTO Customer_tab + VALUES (1, 'Jean Nance', '2 Avocet Drive', + 'Redwood Shores', 'CA', '95054', + '415-555-1212', NULL, NULL) ; + +INSERT INTO Customer_tab + VALUES (2, 'John Nike', '323 College Drive', + 'Edison', 'NJ', '08820', + '609-555-1212', '201-555-1212', NULL) ; + +-- Place Orders + +INSERT INTO PO_tab + VALUES (1001, 1, SYSDATE, '10-MAY-1997', + NULL, NULL, NULL, NULL) ; + +INSERT INTO PO_tab + VALUES (2001, 2, SYSDATE, '20-MAY-1997', + '55 Madison Ave', 'Madison', 'WI', '53715') ; + +-- Detail Line Items + +INSERT INTO LineItems_tab VALUES(01, 1001, 1534, 12, 0) ; +INSERT INTO LineItems_tab VALUES(02, 1001, 1535, 10, 10) ; +INSERT INTO LineItems_tab VALUES(01, 2001, 1004, 1, 0) ; +INSERT INTO LineItems_tab VALUES(02, 2001, 1011, 2, 1) ; + +------------------------------------------------------- +-- Use SYS_XMLGEN() to generate PO in XML format +------------------------------------------------------- +set long 20000 +set pages 100 +SELECT SYS_XMLGEN(value(p), + sys.xmlgenformatType.createFormat('PurchaseOrder')).getClobVal() PO +FROM po p +WHERE p."@PONO"=1001; + +------------------------------------------------------- +-- Use SYS_XMLAGG() to aggrigate all Purchase Orders +-- into one XML Document +------------------------------------------------------- +set long 20000 +set pages 200 +SELECT SYS_XMLAGG(SYS_XMLGEN(value(p), + sys.xmlgenformatType.createFormat('PurchaseOrder'))).getClobVal() PO +FROM po p; + + +-- cleanup +connect system/manager +drop user xmlgen2 cascade; diff --git a/xmltype1.sql b/xmltype1.sql new file mode 100644 index 0000000..287c401 --- /dev/null +++ b/xmltype1.sql @@ -0,0 +1,175 @@ +Rem +Rem $Header: xmltype1.sql 04-may-2001.14:29:48 rbooredd Exp $ +Rem +Rem xmltype1.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xmltype1.sql - XMLType demo 1 +Rem +Rem DESCRIPTION +Rem This demo shows how to use XMLType to store and access +Rem xml documents inside database +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbooredd 04/29/01 - Merged rbooredd_xml_demo1 +Rem rbooredd 04/29/01 - +Rem rbooredd 04/27/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect system/manager +grant connect,resource,query rewrite to xmltype1 identified by xmltype1; +connect xmltype1/xmltype1; + +-- create xml table to store Purchase Order documents +CREATE TABLE po_tab( + po sys.XMLType +) XMLType COLUMN po + STORE AS CLOB ( + TABLESPACE system + STORAGE(INITIAL 4K NEXT 8K) + CHUNK 4096 NOCACHE LOGGING + ); + +------------------------------------ +-- DML on XMLType column +------------------------------------ + +-- insert PurchaseOrder into po_tab table +-- with createXML constructor +insert into po_tab +values(sys.XMLType.createXML( +' + + Po_1 + John + + 1033, Main Street + Sunnyvalue + CA + +') +); + +insert into po_tab +values(sys.XMLType.createXML( +' + + Po_2 + Nance + + 1033, Main Street + Sunnyvalue + CA + +') +); + + +-- Updating Purchase Order 2 with new shipping address +update po_tab e +set e.po=sys.XMLType.createXML( +' + + Po_2 + Nance + + 2 Avocet Drive + Redwood Shores + CA + +') +where e.po.extract('/PO/@pono').getNumberVal()=2; + + +-- deleting Purchase Order 2 +delete from po_tab e +where e.po.extract('/PO/PNAME/text()').getStringVal()='Po_2'; + +commit; + +------------------------------------ +-- Queries on XMLType column +------------------------------------ + +-- selecting XMLType document as CLOB +set long 2000 +select e.po.getClobval() +from po_tab e; + +-- extract Purchase Order NAME where pono attribue exists and equal to 1 +-- and customer name is like '%John%' + +select e.po.extract('/PO/PNAME/text()').getStringVal() PNAME +from po_tab e +where e.po.existsNode('/PO/@pono') = 1 and + e.po.extract('/PO/@pono').getNumberVal() = 1 and + e.po.extract('/PO/CUSTNAME/text()').getStringVal() like '%John%'; + +-- check if /PO/SHIPADDR/STATE node is a xml fragment +select e.po.extract('/PO/SHIPADDR/STATE').isFragment() +from po_tab e; + +-- use Extract(), ExitsNode() XML Operators to query XML document +select extract(e.po,'/PO/PNAME/text()').getStringVal() PNAME +from po_tab e +where existsNode(e.po,'/PO/SHIPADDR') = 1 and + extract(e.po,'/PO/@pono').getNumberVal() = 1 and + extract(e.po,'/PO/CUSTNAME/text()').getStringVal() like '%John%'; + +--------------------------------------- +-- Functional Indexes on XMLType column +--------------------------------------- + +-- create a unique functional index on pono to enforce +-- unique constraint on pono attribute +create unique index pono_fidx on po_tab(sys.xmltype.getNumberVal( + sys.xmltype.extract(po,'/PO/@pono'))); + +-- insert fails due to unique constraint violation! +insert into po_tab +values(sys.XMLType.createXML( +' + + Po_1 + John + + 1033, Main Street + Sunnyvalue + CA + +') +); + + +-- create a functional index on customer name +create index cname_fidx on po_tab(substr(sys.xmltype.getStringVal( + sys.xmltype.extract(po,'/PO/CUSTNAME/text()')),1,200)); + +-- create a functional index for existsNode() of SHIPADDR +create index sadd_fidx on po_tab(po.existsNode('/PO/SHIPADDR')); + + +-- use functional indexes to improve query performance +alter session set query_rewrite_enabled=true; +alter session set query_rewrite_integrity=trusted; + +select /*+ index(e pono_fidx) */ e.po.getClobVal() +from po_tab e +where e.po.extract('/PO/@pono').getNumberVal() = 1; + +-- cleanup +connect system/manager +drop user xmltype1 cascade; diff --git a/xmltype2.sql b/xmltype2.sql new file mode 100644 index 0000000..c88b9ac --- /dev/null +++ b/xmltype2.sql @@ -0,0 +1,118 @@ +Rem +Rem $Header: xmltype2.sql 04-may-2001.12:22:18 rbooredd Exp $ +Rem +Rem xmltype2.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xmltype2.sql - XMLType demo 2 +Rem +Rem DESCRIPTION +Rem This demo shows how to use XMLType inside PL/SQL +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbooredd 04/29/01 - Merged rbooredd_xml_demo1 +Rem rbooredd 04/27/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect system/manager +grant connect,resource to xmltype2 identified by xmltype2; +connect xmltype2/xmltype2; + + +-------------------------------------------------------------------------------- +-- Exploding the Purchase Order xml documnet to Store in a Relational Table +-- using XMLType methods and Table Function (pipelined) +-------------------------------------------------------------------------------- +create type poRow_type as object +( + poname varchar2(20), + postreet varchar2(20), + pocity varchar2(20), + postate char(2), + pozip char(10) +); +/ + +create type poRow_list as TABLE of poRow_type; +/ + +create or replace function poExplode_func (poList IN sys.XMLType) return +poRow_list +pipelined is + out_rec poRow_type := poRow_type(null,null,null,null,null); + poxml sys.XMLType; + i binary_integer := 1; +begin + + loop + + -- extract the i'th purchase order! + poxml := poList.extract('//PO['||i||']'); + + exit when poxml is null; + + -- extract the required attributes..!!! + out_rec.poname := + poxml.extract('/PO/PONAME/text()').getStringVal(); + out_rec.postreet := + poxml.extract('/PO/POADDR/STREET/text()').getStringVal(); + out_rec.pocity := + poxml.extract('/PO/POADDR/CITY/text()').getStringVal(); + out_rec.postate := + poxml.extract('/PO/POADDR/STATE/text()').getStringVal(); + out_rec.pozip := + poxml.extract('/PO/POADDR/ZIP/text()').getStringVal(); + + -- output the row + PIPE ROW(out_rec); + i := i+1; + end loop; + return; + +end; +/ + +-- generate poRow_type rowset from xml documnet +select * + from TABLE( CAST( + poExplode_func( + sys.XMLType.createXML( + ' + + + Po_1 + + 100 Main Street + Sunnyvale + CA + 94086 + + + + Po_2 + + 200 First Street + Oaksdale + CA + 95043 + + + ') + ) AS poRow_list)); + +-- cleanup +connect system/manager +drop user xmltype2 cascade; diff --git a/xmltype3.java b/xmltype3.java new file mode 100644 index 0000000..28222b5 --- /dev/null +++ b/xmltype3.java @@ -0,0 +1,162 @@ +/* $Header: xmltype3.java 09-dec-2001.18:51:27 bkhaladk Exp $ */ + +/* Copyright (c) 2001, Oracle Corporation. All rights reserved. */ + +/* + DESCRIPTION + This demo shows how to access/modify XMLType inside java/jdbc: + - retrieve PurchaseOrder(pono#2001) xml document from database + - store this PurchaseOrder in po_xml_hist table + - update "DISCOUNT" element using java DOM API + - update modified PurchaseOrder xml documnet in database + - delete PurchaseOrder 1001 + + PRIVATE CLASSES + None + + NOTES + Need to have classes12.zip, xmlparserv2.jar, and xdb_g.jar in CLASSPATH + And execute xmltype3.sql first to setup schema: + sqlplus /nolog @xmltype3.sql + + MODIFIED (MM/DD/YY) + bkhaladk 12/09/01 - . + bkhaladk 12/05/01 - . + bkhaladk 12/03/01 - . + rbooredd 04/29/01 - Merged rbooredd_xml_demo1 + rbooredd 04/27/01 - Creation + */ + +import java.sql.*; +import java.io.*; + +import oracle.xml.parser.v2.*; +import org.xml.sax.*; +import org.w3c.dom.*; + +import oracle.jdbc.driver.*; +import oracle.sql.*; + +import oracle.xdb.XMLType; + +public class xmltype3 +{ + + //static String conStr = "jdbc:oracle:thin:@energize:1521:m3"; + static String conStr = "jdbc:oracle:oci8:@"; + static String user = "xmltype3"; + static String pass = "xmltype3"; + /* static String qryStr = + "select x.xpo from po_xml x "+ + "where x.xpo.extract('/PurchaseOrder/@PONO').getNumberVal()=2001";*/ + static String qryStr = + "select x.xpo from po_xml x "; + + + static String updateXML(String xmlTypeStr) + { + System.out.println("\n==============================="); + System.out.println("xmlType.getStringVal():"); + System.out.println(xmlTypeStr); + System.out.println("==============================="); + String outXML = null; + try{ + DOMParser parser = new DOMParser(); + parser.setValidationMode(parser.PARTIAL_VALIDATION); + parser.setPreserveWhitespace (true); + + + parser.parse(new StringReader(xmlTypeStr)); + System.out.println("xmlType.getStringVal(): xml String is well-formed"); + + XMLDocument doc = parser.getDocument(); + + NodeList nl = doc.getElementsByTagName("DISCOUNT"); + + for(int i=0;i + + 1 + Jean Nance +
+ 2 Avocet Drive + Redwood Shores + CA + 95054 +
+ + 415-555-1212 + +
+ 29-APR-01 + 10-MAY-97 12.00.00.000000 AM + + + + 2234 + 2 + + 12 + 0 + + + + 3456.23 + 2 + + 10 + 10 + + + + ' +)); + +insert into po_xml +values(sys.XMLType.createXML( +' + + 2 + John Nike +
+ 323 College Drive + Edison + NJ + 08820 +
+ + 609-555-1212 + 201-555-1212 + +
+ 29-APR-01 + 20-MAY-97 12.00.00.000000 AM + + + + 6750 + 2 + + 1 + 0 + + + + 4500.23 + 2 + + 2 + 1 + + + + 55 Madison Ave + Madison + WI + 53715 + +
' +)); + + +set long 100000 +select x.xpo.getClobVal() xpo +from po_xml x; + +-- create po_xml_hist table store old PurchaseOrders +create table po_xml_hist( + xpo sys.xmltype +); + diff --git a/xrwutl.sql b/xrwutl.sql new file mode 100644 index 0000000..590b1e2 --- /dev/null +++ b/xrwutl.sql @@ -0,0 +1,383 @@ +Rem +Rem $Header: rdbms/demo/xrwutl.sql /main/2 2008/10/07 11:18:57 jraitto Exp $ +Rem +Rem xrwutl.sql +Rem +Rem Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. +Rem +Rem NAME +Rem xrwutl.sql - Utility to extract output from EXPLAIN_REWRITE() +Rem +Rem DESCRIPTION +Rem EXPLAIN_REWRITE() contains a large number of output fields. +Rem This utility helps to easily select the output fields from +Rem EXPLAIN_REWRITE(). +Rem +Rem NOTES +Rem This utility is merged as a demo script +Rem +Rem MODIFIED (MM/DD/YY) +Rem jraitto 10/04/08 - Handle internally thrown errors +Rem - Fix bug 4390758 +Rem jraitto 10/03/08 - fix bug 4391670 by re-signraising unexpected +Rem errors +Rem mthiyaga 04/01/05 - mthiyaga_xrw_demo +Rem mthiyaga 28/03/05 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + + +set echo off; + +-- DEFINITION for xrw (mv_list, command_list, querytxt): +-- This is a procedure to simplify the output from +-- explain_rewrite(). +-- INPUT +-- mv_list : List of mvs separated by commmas. +-- +-- command_list : List of commands separated by commas; you can provide +-- any of the following commands. +-- COMMAND LIST +-- +-- querytxt : Text of the query to be rewritten +-- + +connect /as sysdba; + +SET SERVEROUTPUT ON SIZE 32512; + +set echo off; + +-- The procedure is used to print a big string. Procedure dbms_output.put_line +-- cannot print a string that is longer than 250 chars. + +CREATE OR REPLACE PROCEDURE print_big_buf + ( + buf IN VARCHAR2 + ) +AS + len PLS_INTEGER; + nl PLS_INTEGER; + bsize CONSTANT PLS_INTEGER := 250; + +BEGIN + dbms_output.enable(1000000); + len := LENGTHB(buf); + nl := floor(len/bsize); + + FOR j IN 1..nl LOOP + dbms_output.put_line(SUBSTRB(buf, (j-1)*bsize + 1, bsize)); + END LOOP; + + dbms_output.put_line(SUBSTRB(buf, nl*bsize + 1, len - nl*bsize)); + +END; +/ + +GRANT EXECUTE ON SYS.print_big_buf TO PUBLIC; + + + +------------------------------------------------------------------------------ +-- DESCRIPTION for ckrw_help +-- This procedure can be called by the user to get help on +-- how to use xrw +------------------------------------------------------------------------------ + + CREATE OR REPLACE PROCEDURE xrw_help AUTHID CURRENT_USER + AS + BEGIN + + dbms_output.put_line('HELP for the use of precedure xrw'); + + dbms_output.put_line('sys.xrw (list_of_mvs (separated by commas), '|| + 'list of commands (separated by commas), querytxt)'); + + dbms_output.put_line('**** List of commands:'); + dbms_output.put_line('QUERY_TXT '); + dbms_output.put_line('REWRITTEN_TXT '); + dbms_output.put_line('QUERY_BLOCK_NO '); + dbms_output.put_line('PASS '); + dbms_output.put_line('COSTS '); + dbms_output.new_line; + + END; +/ +show errors + + + + + +------------------------------------------------------------------------------ +-- DEFINITION for check_mvs: +-- This procedure takes an array of mv names and checks whether +-- they are really mvs; if there is any name in the list that doesn't +-- correspond to a MV then we raise an error +-- INPUT +-- num_mvs : number of mvs given +-- mv_array : array of mv names +------------------------------------------------------------------------------ + +CREATE OR REPLACE PROCEDURE check_mvs + ( + num_mvs IN PLS_INTEGER, + mv_array IN dbms_utility.uncl_array + ) AUTHID CURRENT_USER + AS + i PLS_INTEGER; + BEGIN + IF (num_mvs > 0) THEN + DECLARE + mv_found PLS_INTEGER := 0; + mv_name VARCHAR2(30); + is_not_mv EXCEPTION; + cursor find_mv (given_mv_name VARCHAR2) IS SELECT 1 from user_mviews + where upper(mview_name) = given_mv_name; + + BEGIN + FOR i IN 1..num_mvs LOOP + mv_name := rtrim(ltrim(upper(mv_array(i)))); + open find_mv(mv_name); + fetch find_mv INTO mv_found; + -- The mv wasn't found in user_mviews, so the name given + -- doesn't correspond to a MV + IF (mv_found = 0) THEN + RAISE is_not_mv; + END IF; + + close find_mv; + END LOOP; + EXCEPTION WHEN NO_DATA_FOUND OR is_not_mv THEN + dbms_output.put_line('**FAILURE** Materialized View ' || mv_name || + ' was not found'); + RAISE NO_DATA_FOUND; + END; + END IF; + END; +/ +show errors + + + + +------------------------------------------------------------------------------ +-- DEFINITION for xrw: +-- This procedure is the top level api the user will use to +-- simplify output from explain_rewrite(). +------------------------------------------------------------------------------ + +CREATE OR REPLACE PROCEDURE xrw + ( + mv_list IN VARCHAR2, + command_list IN VARCHAR2, + querytxt IN VARCHAR2 + ) AUTHID CURRENT_USER + AS + + Rewrite_Array SYS.RewriteArrayType := SYS.RewriteArrayType(); + no_of_msgs NUMBER; + i NUMBER; + + + buf VARCHAR2(32512); + + + -- Variables used for the list of mvs given + num_mvs PLS_INTEGER := 0; + mv_array dbms_utility.uncl_array; + i PLS_INTEGER := 1; + + -- Variables used for the different commands + num_commands PLS_INTEGER := 0; + commands_array dbms_utility.lname_array; + command VARCHAR2(30); + query_txt BOOLEAN := false; + rewritten_txt BOOLEAN := false; + query_block_no BOOLEAN := false; + pass BOOLEAN := false; + costs BOOLEAN := false; + + + + empty_line VARCHAR2(80) := NULL; + + + + querytxt_err EXCEPTION; + commlist_err EXCEPTION; + + rewrite_err EXCEPTION; + no_rewrite_err EXCEPTION; + command_err EXCEPTION; + is_not_mv EXCEPTION; + explain_rewrite_err EXCEPTION; + failure_displayed BOOLEAN := false; + + BEGIN + + IF (mv_list IS NOT NULL) THEN + BEGIN + dbms_utility.comma_to_table (mv_list, num_mvs, mv_array); + EXCEPTION + WHEN OTHERS THEN + dbms_output.put_line ('** FAILURE ** Malformed MV list'); + failure_displayed := true; + RAISE; + END; + -- Check whether the given mvs are actually MVs + BEGIN + check_mvs (num_mvs, mv_array); + EXCEPTION + WHEN NO_DATA_FOUND THEN + RAISE is_not_mv; + WHEN OTHERS THEN + RAISE; + END; + END IF; + + IF querytxt IS NULL THEN + RAISE querytxt_err; + END IF; + +-- IF command_list IS NULL THEN +-- RAISE commlist_err; +-- END IF; + + IF command_list IS NOT NULL THEN + BEGIN + dbms_utility.comma_to_table (command_list, num_commands, commands_array); + EXCEPTION + WHEN OTHERS THEN + dbms_output.put_line ('** FAILURE ** Malformed command list'); + failure_displayed := true; + RAISE; + END; + END IF; + + -- Read the list of command and set the BOOLEAN variables appropriately + + FOR i IN 1..num_commands LOOP + command := rtrim(ltrim(upper(commands_array(i)))); + IF command = 'QUERY_TXT' THEN + query_txt := true; + ELSIF command = 'REWRITTEN_TXT' THEN + rewritten_txt := true; + ELSIF command = 'QUERY_BLOCK_NO' THEN + query_block_no := true; + ELSIF command = 'PASS' THEN + pass := true; + ELSIF command = 'COSTS' THEN + costs := true; + ELSE + dbms_output.put_line('Use execute sys.xrw_help to get the list ' || + 'of valid commands'); + RAISE command_err; + END IF; + END LOOP; + +BEGIN + dbms_output.new_line; + BEGIN + IF mv_list IS NULL then + dbms_mview.Explain_Rewrite(querytxt, '', Rewrite_Array); + ELSE + dbms_mview.Explain_Rewrite(querytxt, mv_list, Rewrite_Array); + END IF; + EXCEPTION + WHEN OTHERS THEN + dbms_output.put_line ('** Failure ** DBMS_MVIEW.EXPLAIN_REWRITE has encountered an error'); + failure_displayed := true; + RAISE; + END; + + no_of_msgs := Rewrite_array.count; + DBMS_OUTPUT.PUT_LINE('============================================================================'); + FOR i IN 1..no_of_msgs + LOOP + IF (i = 2) THEN + DBMS_OUTPUT.PUT_LINE('>> '); + DBMS_OUTPUT.PUT_LINE('------------------------- ANALYSIS OF QUERY REWRITE -------------------------'); + END IF; + DBMS_OUTPUT.PUT_LINE('>> '); + IF (query_block_no) THEN + IF (i > 1) THEN + DBMS_OUTPUT.PUT_LINE('>> QRY BLK #: '|| + Rewrite_Array(i).query_block_no); + END IF; + END IF; + DBMS_OUTPUT.PUT_LINE('>> MESSAGE : ' || Rewrite_Array(i).message); + IF (query_txt) THEN + DBMS_OUTPUT.PUT_LINE('>> QUERY : ' || Rewrite_Array(i).query_text); + END IF; + IF (rewritten_txt) THEN + DBMS_OUTPUT.PUT_LINE('>> RW QUERY : '|| Rewrite_Array(i).rewritten_text); + END IF; + IF (costs) THEN + DBMS_OUTPUT.PUT_LINE('>> ORIG COST: '|| Rewrite_Array(i).original_cost || ' RW COST: '|| Rewrite_Array(i).rewritten_cost); + END IF; + + IF (pass) THEN + IF (i > 1) THEN + IF (Rewrite_Array(i).pass = 'YES') THEN + DBMS_OUTPUT.PUT_LINE('>> MESSAGE OUTPUT BEFORE VIEW MERGING... '); + ELSE + DBMS_OUTPUT.PUT_LINE('>> MESSAGE OUTPUT AFTER VIEW MERGING... '); + END IF; + END IF; + END IF; + IF (i = 1) THEN + DBMS_OUTPUT.PUT_LINE('============================================================================'); + ELSIF (i != no_of_msgs) THEN + DBMS_OUTPUT.PUT_LINE('----------------------------------------------------------------------------'); + END IF; + END LOOP; + DBMS_OUTPUT.PUT_LINE('============================ END OF MESSAGES ==============================='); +END; + + + + EXCEPTION + WHEN querytxt_err THEN + dbms_output.put_line('**FAILURE** The querytxt cannot be NULL'); + WHEN commlist_err THEN + dbms_output.put_line('**FAILURE** The command list cannot be NULL'); + + WHEN command_err THEN + dbms_output.put_line('**FAILURE** ' || command || + ' is not a valid command'); + WHEN is_not_mv THEN + -- MV not found, this error has already been displayed + dbms_output.new_line; + WHEN OTHERS THEN + dbms_output.new_line; + IF (NOT failure_displayed) THEN + dbms_output.put_line('**FAILURE** An unexpected error has occurred'); + dbms_output.new_line; + END IF; + RAISE; + END; +/ +show errors; + + +drop public synonym XRW; +create public synonym XRW for SYS.XRW; +GRANT EXECUTE ON XRW TO PUBLIC; + +drop public synonym xrw_HELP; +create public synonym xrw_HELP for SYS.xrw_HELP; +GRANT EXECUTE ON xrw_HELP TO PUBLIC; + + + + + + diff --git a/xtdemo01.dat b/xtdemo01.dat new file mode 100644 index 0000000..f6f535f --- /dev/null +++ b/xtdemo01.dat @@ -0,0 +1,7 @@ +12,RESEARCH,"SARATOGA" +10,"ACCOUNTING",CLEVELAND +11,"ART",SALEM +13,FINANCE,"BOSTON" +21,"SALES",PHILA. +22,"SALES",ROCHESTER +42,"INT'L","SAN FRAN" diff --git a/xtdemo01.sql b/xtdemo01.sql new file mode 100644 index 0000000..3f5a4d3 --- /dev/null +++ b/xtdemo01.sql @@ -0,0 +1,71 @@ +Rem +Rem $Header: xtdemo01.sql 07-jun-2001.14:03:36 rsahani Exp $ +Rem +Rem xtdemo01.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xtdemo01.sql - External Table Demo 1 +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rsahani 06/07/01 - Merged rsahani_add_xt_demos_010605 +Rem rsahani 06/05/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect sys/knl_test7 as sysdba + +Rem Demo 1: External Table - Using variable-length data +Rem ###################### +Rem This demo corresponds to sql*ldr demo Case 1 in rdbms/demo/ulcase.sh +Rem - FIELDS TERMINATED BY specifies that data is terminated by commas, +Rem but may also be enclosed by quotation marks +Rem - datatypes for all fields defaults to CHAR +Rem ###################### + +Rem Create Directory +@xtsetup.sql + +Rem Drop and create external table +drop table xtdemo01; +CREATE TABLE xtdemo01 +( + DEPTNO NUMBER(2), + DNAME CHAR(14), + LOC CHAR(13) +) +ORGANIZATION external +( + TYPE oracle_loader + DEFAULT DIRECTORY def_dir + ACCESS PARAMETERS + ( + RECORDS DELIMITED BY NEWLINE CHARACTERSET WE8DEC + BADFILE 'deptXT.bad' + LOGFILE 'deptXT.log' + FIELDS TERMINATED BY "," OPTIONALLY ENCLOSED BY '"' LDRTRIM + ) + location ('xtdemo01.dat') +) +REJECT LIMIT UNLIMITED; + +Rem Query external table +select * from xtdemo01 order by deptno; + +Rem Cleanup +drop table xtdemo01; +drop directory def_dir; diff --git a/xtdemo02.sql b/xtdemo02.sql new file mode 100644 index 0000000..36640f2 --- /dev/null +++ b/xtdemo02.sql @@ -0,0 +1,86 @@ +Rem +Rem $Header: xtdemo02.sql 07-jun-2001.14:03:36 rsahani Exp $ +Rem +Rem xtdemo02.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xtdemo02.sql - External Table Demo 2 +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rsahani 06/07/01 - Merged rsahani_add_xt_demos_010605 +Rem rsahani 06/05/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect sys/knl_test7 as sysdba + +Rem Demo 2: External Table - Using fixed-format fields +Rem ###################### +Rem This demo corresponds to sql*ldr demo Case 2 in rdbms/demo/ulcase.sh +Rem - POSITIONAL_SPEC is used to identify a column name and the location +Rem of data in the datafile to be loaded into that column +Rem - the datatypes (integer external, char, decimal external) identify +Rem the datatype of data fields in file and not of corresponding +Rem columns in the empXT table +Rem ###################### + +Rem Create directory +@xtsetup.sql + +Rem Drop and Create external table +drop table empXT; +CREATE TABLE empXT +( + EMPNO NUMBER(4), + ENAME VARCHAR2(10), + JOB VARCHAR2(9), + MGR NUMBER(4), + SAL NUMBER(7,2), + COMM NUMBER(7,2), + DEPTNO NUMBER(2) +) +ORGANIZATION external +( + TYPE oracle_loader + DEFAULT DIRECTORY def_dir + ACCESS PARAMETERS + ( + RECORDS DELIMITED BY NEWLINE CHARACTERSET WE8DEC + BADFILE def_dir:'empXT.bad' + LOGFILE def_dir:'empXT.log' + FIELDS LDRTRIM + ( + EMPNO (1:4) INTEGER EXTERNAL(4), + ENAME (6:15) CHAR(10), + JOB (17:25) CHAR(9), + MGR (27:30) INTEGER EXTERNAL(4), + SAL (32:39) INTEGER EXTERNAL(8), + COMM (41:48) INTEGER EXTERNAL(8), + DEPTNO (50:51) INTEGER EXTERNAL(2) + ) + ) + location (def_dir:'ulcase2.dat') +) +REJECT LIMIT UNLIMITED; + +Rem Query External Table +select * from empXT order by empno; + +Rem Cleanup +drop table empXT; +drop directory def_dir; diff --git a/xtdemo03.dat b/xtdemo03.dat new file mode 100644 index 0000000..b9472b8 --- /dev/null +++ b/xtdemo03.dat @@ -0,0 +1,7 @@ +7782, "Clark", "Manager", 7839, 09-June-1981, 2572.50,, 10:101 +7839, "King", "President", , 17-November-1981, 5500.00,, 10:102 +7934, "Miller", "Clerk", 7782, 23-January-1982, 920.00,, 10:102 +7566, "Jones", "Manager", 7839, 02-April-1981, 3123.75,, 20:101 +7499, "Allen", "Salesman", 7698, 20-February-1981, 1600.00, 300.00, 30:103 +7654, "Martin", "Salesman", 7698, 28-September-1981, 1312.50, 1400.00, 30:103 +7658, "Chan", "Analyst", 7566, 03-May-1982, 3450,, 20:101 diff --git a/xtdemo03.sql b/xtdemo03.sql new file mode 100644 index 0000000..3ae2e16 --- /dev/null +++ b/xtdemo03.sql @@ -0,0 +1,94 @@ +Rem +Rem $Header: xtdemo03.sql 07-jun-2001.14:03:38 rsahani Exp $ +Rem +Rem xtdemo03.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xtdemo03.sql - External Table Demo 3 +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rsahani 06/07/01 - Merged rsahani_add_xt_demos_010605 +Rem rsahani 06/05/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 108 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 200 +SET ECHO ON + +connect sys/knl_test7 as sysdba + +Rem Demo 3: External Table - Using a Delimited, Free-Format File +Rem ###################### +Rem This demo corresponds to sql*ldr demo Case 3 in rdbms/demo/ulcase.sh +Rem - general specifications are overidden with declarations for +Rem individual fields: +Rem some data is enclosed in quotation marks, some is set off by commas +Rem and the values for DEPTNO and PROJNO are separated by colon +Rem - %a (agent number), %p (process number) is appended to +Rem BAD filename and LOG filename +Rem ###################### + +Rem Create Directory +@xtsetup.sql + +Rem Drop and create external table +drop table xtdemo03; +CREATE TABLE xtdemo03 +( + EMPNO NUMBER(4), + ENAME CHAR(10), + JOB CHAR(9), + MGR NUMBER(4), + HIREDATE DATE, + SAL NUMBER(7,2), + COMM NUMBER(7,2), + DEPTNO NUMBER(2), + PROJNO NUMBER +) +ORGANIZATION external +( + TYPE oracle_loader + DEFAULT DIRECTORY def_dir + ACCESS PARAMETERS + ( + RECORDS DELIMITED BY NEWLINE CHARACTERSET WE8DEC + BADFILE 'empXT_%a_%p.bad' + LOGFILE 'empXT_%a_%p.log' + FIELDS TERMINATED BY "," OPTIONALLY ENCLOSED BY '"' LDRTRIM + ( + EMPNO CHAR(255), + ENAME CHAR(255), + JOB CHAR(255), + MGR CHAR(255), + HIREDATE CHAR(20) + DATE_FORMAT DATE MASK "DD-Month-YYYY", + SAL CHAR(255), + COMM CHAR(255), + DEPTNO CHAR(255) + TERMINATED BY ":" OPTIONALLY ENCLOSED BY '"', + PROJNO CHAR(255) + ) + ) + location ('xtdemo03.dat') +) +REJECT LIMIT UNLIMITED; + +Rem Query external table +select * from xtdemo03 order by empno; + +Rem Cleanup +drop table xtdemo03; +drop directory def_dir; + diff --git a/xtdemo04.dat b/xtdemo04.dat new file mode 100644 index 0000000..6480242 --- /dev/null +++ b/xtdemo04.dat @@ -0,0 +1,9 @@ +1234 BAKER 10 9999 101 102 103 +2664 YOUNG 20 2893 425 102 +5321 OTOOLE 10 9999 321 55 40 +2134 FARMER 20 4555 236 456 +2414 LITTLE 20 5634 236 456 40 +6542 LEE 10 4532 102 321 14 +4532 PERKINS 10 9999 40 +1244 HUNT 11 3452 665 133 456 + 123 DOOLITTLE 12 9940 132 diff --git a/xtdemo04.sql b/xtdemo04.sql new file mode 100644 index 0000000..3efc1e2 --- /dev/null +++ b/xtdemo04.sql @@ -0,0 +1,124 @@ +Rem +Rem $Header: xtdemo04.sql 07-jun-2001.14:03:39 rsahani Exp $ +Rem +Rem xtdemo04.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xtdemo04.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rsahani 06/07/01 - Merged rsahani_add_xt_demos_010605 +Rem rsahani 06/06/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 108 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 200 +SET ECHO ON + +connect sys/knl_test7 as sysdba + +Rem Demo 4: External Table - Loading data into multiple tables +Rem ###################### + +Rem Create Directory +@xtsetup.sql + +Rem Drop and create external table +drop table emp_proj_XT; +CREATE TABLE emp_proj_XT +( + EMPNO NUMBER(4), + ENAME CHAR(10), + DEPTNO NUMBER(2), + MGR NUMBER(4), + PROJ1 NUMBER, + PROJ2 NUMBER, + PROJ3 NUMBER +) +ORGANIZATION external +( + TYPE oracle_loader + DEFAULT DIRECTORY def_dir + ACCESS PARAMETERS + ( + RECORDS DELIMITED BY NEWLINE CHARACTERSET WE8DEC + BADFILE 'emp_proj.bad' + DISCARDFILE 'emp_proj.dis' + LOGFILE 'emp_proj.log' + FIELDS LDRTRIM + ( + EMPNO (1:4) INTEGER EXTERNAL(4), + ENAME (6:15) CHAR(10), + DEPTNO (17:18) CHAR(2), + MGR (20:23) INTEGER EXTERNAL(4), + PROJ1 (25:27) INTEGER EXTERNAL(4), + PROJ2 (29:31) INTEGER EXTERNAL(3), + PROJ3 (32:34) INTEGER EXTERNAL(4) + ) + ) + location ('xtdemo04.dat') +) +REJECT LIMIT UNLIMITED; + +Rem Query external table +select * from emp_proj_XT order by empno, ename; + +Rem Create regular tables in which data will be inserted +drop table emp; +create table emp +( + EMPNO NUMBER(4), + ENAME CHAR(10), + DEPTNO NUMBER(2), + MGR NUMBER(4) +); + +select count(*) from emp; + +drop table proj; +create table proj +( + EMPNO NUMBER(4), + PROJID NUMBER +); + +select count(*) from proj; + +Rem Load data into EMP and PROJ table from EMP_PROJ_XT table +Rem using MULTI-TABLE INSERT +insert all +when 1=1 then + into emp (empno, ename, deptno, mgr) + values (empno, ename, deptno, mgr) +when proj1 is not null then + into proj (empno, projid) + values (empno, proj1) +when proj2 is not null then + into proj (empno, projid) + values (empno, proj2) +when proj3 is not null then + into proj (empno, projid) + values (empno, proj3) +select * from emp_proj_XT; + +Rem Verify that data has been loaded correctly +select * from emp order by empno; +select * from proj order by 1, 2; + +Rem Cleanup +drop table emp; +drop table proj; +drop table emp_proj_XT; +drop directory def_dir; diff --git a/xtsetup.sql b/xtsetup.sql new file mode 100644 index 0000000..0697eca --- /dev/null +++ b/xtsetup.sql @@ -0,0 +1,42 @@ +Rem +Rem $Header: xtsetup.sql 06-oct-2003.13:23:55 rsahani Exp $ +Rem +Rem xtsetup.sql +Rem +Rem Copyright (c) 2001, 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem xtsetup.sql - Create DEFAULT DIRECTORY required by +Rem External Table Demos +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem SQL statements for creating default directory should be +Rem uncommented and modified to point to location where +Rem data files referenced in external table are located +Rem +Rem MODIFIED (MM/DD/YY) +Rem rsahani 10/06/03 - uncomment "create directory" +Rem rsahani 06/07/01 - Merged rsahani_add_xt_demos_010605 +Rem rsahani 06/05/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect sys/knl_test7 as sysdba + +Rem Drop and create default directory +Rem - &1 in create directory statement below must be replaced by +Rem absolute path of the directory where data files referenced +Rem in external table demos are stored +drop directory def_dir; + +create directory def_dir as '&1';